From 3689ecd95afae5d188bc6be443e074135ab13fdf Mon Sep 17 00:00:00 2001 From: Arsenii es3n1n Date: Sat, 12 Oct 2024 15:07:25 +0200 Subject: [PATCH] Ensure class/structs name consistency, add more docs (#15) --- src/lib/es3n1n/common/defer.hpp | 58 ++++++---- src/lib/es3n1n/common/files.hpp | 47 +++++--- src/lib/es3n1n/common/linalg/matrix.hpp | 14 +-- src/lib/es3n1n/common/linalg/vector.hpp | 39 +++---- src/lib/es3n1n/common/macros.hpp | 7 ++ src/lib/es3n1n/common/memory/address.hpp | 44 ++++---- src/lib/es3n1n/common/memory/range.hpp | 32 +++++- src/lib/es3n1n/common/memory/reader.hpp | 132 +++++++++++++++-------- src/lib/es3n1n/common/platform.hpp | 32 ++---- src/lib/es3n1n/common/progress.hpp | 12 +-- src/lib/es3n1n/common/random.hpp | 30 +++--- src/lib/es3n1n/common/stopwatch.hpp | 132 +++++++++++------------ src/lib/es3n1n/common/string_parser.hpp | 85 ++++++++------- src/lib/es3n1n/common/traits.hpp | 27 +++-- src/lib/es3n1n/common/types.hpp | 46 ++++++-- src/tests/files.cpp | 3 +- src/tests/memory/address.cpp | 6 +- src/tests/memory/range.cpp | 23 +++- src/tests/memory/reader.cpp | 4 +- src/tests/traits.cpp | 12 +-- src/tests/types.cpp | 4 +- 21 files changed, 468 insertions(+), 321 deletions(-) create mode 100644 src/lib/es3n1n/common/macros.hpp diff --git a/src/lib/es3n1n/common/defer.hpp b/src/lib/es3n1n/common/defer.hpp index 7162847..6112a5a 100644 --- a/src/lib/es3n1n/common/defer.hpp +++ b/src/lib/es3n1n/common/defer.hpp @@ -1,27 +1,45 @@ #pragma once -#include +#include "base.hpp" +#include "macros.hpp" +#include -#define CAT_(x, y) x##y -#define CAT(x, y) CAT_(x, y) +/// \brief A class that holds a callable object and executes it upon destruction. +/// \tparam Callable The type of the callable object. +template +class DeferHolder : public base::NonCopyable { +public: + /// \brief Constructor that takes a callable object. + /// \param callable The callable object to be executed upon destruction. + explicit DeferHolder(Callable&& callable) noexcept: callable_(std::forward(callable)) { } -#define defer auto CAT(_defer_instance_, __COUNTER__) = defer_::defer_{} % [&]() + /// \brief Destructor that executes the stored callable object. + ~DeferHolder() { + callable_(); + } -namespace defer_ { - template - struct type { - callable cb; +private: + Callable callable_; ///< The stored callable object. +}; - explicit type(callable&& _cb): cb(std::forward(_cb)) { } +/// \brief A helper class for creating deferred execution objects. +class Defer : public base::NonCopyable { +public: + /// \brief Default constructor. + constexpr Defer() noexcept = default; - ~type() { - cb(); - } - }; + /// \brief Default destructor. + constexpr ~Defer() noexcept = default; - struct defer_ { - template - type operator%(callable&& cb) { - return type{std::forward(cb)}; - } - }; -} // namespace defer_ + /// \brief Overloaded modulus operator to create a DeferHolder object. + /// \tparam Callable The type of the callable object. + /// \param cb The callable object to be deferred. + /// \return A DeferHolder object containing the callable. + template + DeferHolder operator%(Callable&& cb) { + return DeferHolder{std::forward(cb)}; + } +}; + +/// \brief Create a deferred execution object. +/// \note This macro creates a unique variable name for each use. +#define defer auto COMMON_CAT(_defer_instance_, __LINE__) = Defer{} % [&]() diff --git a/src/lib/es3n1n/common/files.hpp b/src/lib/es3n1n/common/files.hpp index e319d6a..22a2c37 100644 --- a/src/lib/es3n1n/common/files.hpp +++ b/src/lib/es3n1n/common/files.hpp @@ -2,31 +2,46 @@ #include #include #include +#include #include namespace files { - inline std::vector read_file(const std::filesystem::path& path) { - std::fstream file(path, std::ios::in | std::ios::binary); - if (!file) { + /// \brief Calculates the size of a file. + /// \param file A reference to an open input file stream. + /// \return An optional containing the file size in bytes if successful, + /// or an empty optional if the file is not in a good state. + inline std::optional file_size(std::ifstream& file) { + if (!file.good()) { return {}; } - file.seekg(0, std::fstream::end); - const auto f_size = file.tellg(); - file.seekg(0, std::fstream::beg); - - std::vector buffer(static_cast(f_size)); + file.seekg(0, std::ios::end); + const auto file_size = file.tellg(); + file.seekg(0, std::ios::beg); + return static_cast(file_size); + } - // NOLINTNEXTLINE - file.read(reinterpret_cast(buffer.data()), buffer.size()); + /// \brief Reads the contents of a file into a vector of bytes. + /// \param path The filesystem path to the file to be read. + /// \return A vector of unsigned 8-bit integers containing the file contents. + /// Returns std::nullopt if the file cannot be opened. + inline std::optional> read_file(const std::filesystem::path& path) { + std::ifstream file(path, std::ios::binary); + if (!file.good()) { + return {}; + } + std::vector buffer(file_size(file).value()); + file.read(reinterpret_cast(buffer.data()), static_cast(buffer.size())); return buffer; } - inline void write_file(const std::filesystem::path& path, const std::uint8_t* raw_buffer, const size_t buffer_size) { - std::ofstream file(path, std::ios::binary | std::ios::out); - // NOLINTNEXTLINE - file.write(reinterpret_cast(raw_buffer), buffer_size); - file.close(); + /// \brief Writes a buffer of bytes to a file. + /// \param path The filesystem path where the file should be written. + /// \param raw_buffer Pointer to the buffer containing the data to be written. + /// \param buffer_size The size of the buffer in bytes. + inline void write_file(const std::filesystem::path& path, const std::uint8_t* raw_buffer, const std::size_t buffer_size) { + std::ofstream file(path, std::ios::binary); + file.write(reinterpret_cast(raw_buffer), static_cast(buffer_size)); } -} // namespace files \ No newline at end of file +} // namespace files diff --git a/src/lib/es3n1n/common/linalg/matrix.hpp b/src/lib/es3n1n/common/linalg/matrix.hpp index 5aa9a45..0dc63cc 100644 --- a/src/lib/es3n1n/common/linalg/matrix.hpp +++ b/src/lib/es3n1n/common/linalg/matrix.hpp @@ -13,7 +13,7 @@ namespace linalg { /// \tparam Ty The type of elements in the matrix (must be a number type). /// \tparam Rows The number of rows in the matrix. /// \tparam Cols The number of columns in the matrix. - template + template class Matrix { public: /// \brief Default constructor. @@ -180,17 +180,17 @@ namespace linalg { /// \brief Alias for 4x4 matrices. /// \tparam Ty The type of elements in the matrix (must be a number type). - template - using mat4x4_t = Matrix; + template + using Matrix4x4 = Matrix; /// \brief Alias for 3x4 matrices. /// \tparam Ty The type of elements in the matrix (must be a number type). - template - using mat3x4_t = Matrix; + template + using Matrix3x4 = Matrix; /// \brief Alias for 4x4 matrices of 32-bit floats. - using mat4x4f32_t = mat4x4_t; + using Matrix4x4f32 = Matrix4x4; /// \brief Alias for 3x4 matrices of 32-bit floats. - using mat3x4f32_t = mat3x4_t; + using Matrix3x4f32 = Matrix3x4; } // namespace linalg diff --git a/src/lib/es3n1n/common/linalg/vector.hpp b/src/lib/es3n1n/common/linalg/vector.hpp index 98e0fcc..c6de6be 100644 --- a/src/lib/es3n1n/common/linalg/vector.hpp +++ b/src/lib/es3n1n/common/linalg/vector.hpp @@ -15,7 +15,7 @@ namespace linalg { /// \brief A templated vector class representing an N-dimensional vector of numeric type Ty /// \tparam Ty The numeric type of the vector components /// \tparam N The dimension of the vector - template + template class Vector { public: /// \brief Default constructor @@ -240,42 +240,35 @@ namespace linalg { }; /// \brief Type alias for 2D vector - template - using vec2_t = Vector; + template + using Vector2 = Vector; /// \brief Type alias for 3D vector - template - using vec3_t = Vector; + template + using Vector3 = Vector; /// \brief Type alias for 4D vector - template - using vec4_t = Vector; + template + using Vector4 = Vector; /// \brief Type alias for 2D vector of unsigned 32-bit integers - using vec2u32_t = vec2_t; + using Vector2u32 = Vector2; /// \brief Type alias for 3D vector of unsigned 32-bit integers - using vec3u32_t = vec3_t; + using Vector3u32 = Vector3; /// \brief Type alias for 4D vector of unsigned 32-bit integers - using vec4u32_t = vec4_t; + using Vector4u32 = Vector4; /// \brief Type alias for 2D vector of signed 32-bit integers - using vec2i32_t = vec2_t; + using Vector2i32 = Vector2; /// \brief Type alias for 3D vector of signed 32-bit integers - using vec3i32_t = vec3_t; + using Vector3i32 = Vector3; /// \brief Type alias for 4D vector of signed 32-bit integers - using vec4i32_t = vec4_t; + using Vector4i32 = Vector4; /// \brief Type alias for 2D vector of 32-bit floats - using vec2f32_t = vec2_t; + using Vector2f32 = Vector2; /// \brief Type alias for 3D vector of 32-bit floats - using vec3f32_t = vec3_t; + using Vector3f32 = Vector3; /// \brief Type alias for 4D vector of 32-bit floats - using vec4f32_t = vec4_t; - - /// \brief Type alias for 2D vector of 64-bit doubles - using vec2f64_t = vec2_t; - /// \brief Type alias for 3D vector of 64-bit doubles - using vec3f64_t = vec3_t; - /// \brief Type alias for 4D vector of 64-bit doubles - using vec4f64_t = vec4_t; + using Vector4f32 = Vector4; } // namespace linalg diff --git a/src/lib/es3n1n/common/macros.hpp b/src/lib/es3n1n/common/macros.hpp new file mode 100644 index 0000000..a058c9a --- /dev/null +++ b/src/lib/es3n1n/common/macros.hpp @@ -0,0 +1,7 @@ +#pragma once + +/// \brief Concatenate two tokens. +#define COMMON_CAT_(x, y) x##y + +/// \brief Concatenate two tokens (indirect). +#define COMMON_CAT(x, y) COMMON_CAT_(x, y) diff --git a/src/lib/es3n1n/common/memory/address.hpp b/src/lib/es3n1n/common/memory/address.hpp index d5fa6da..c0ee76a 100644 --- a/src/lib/es3n1n/common/memory/address.hpp +++ b/src/lib/es3n1n/common/memory/address.hpp @@ -53,7 +53,7 @@ namespace memory { /// \param buffer Pointer to the data to write /// \param size Size of the data to write /// \return Expected containing this address on success, or an error code on failure - std::expected write(const void* buffer, std::size_t size) { + std::expected write(const void* buffer, std::size_t size) { return memory::reader.write(address_, buffer, size).transform([this](auto) { return *this; }); } @@ -61,16 +61,16 @@ namespace memory { /// \tparam Ty Type of the value to write (must be trivially copyable) /// \param value The value to write /// \return Expected containing this address on success, or an error code on failure - template - std::expected write(Ty value) { + template + std::expected write(Ty value) { return memory::reader.write(&value, address_).transform([this](auto) { return *this; }); } /// \brief Read a trivially copyable value from the address /// \tparam Ty Type of the value to read (must be trivially copyable) /// \return Expected containing the read value on success, or an error code on failure - template - [[nodiscard]] std::expected read() const { + template + [[nodiscard]] std::expected read() const { return memory::reader.read(address_); } @@ -78,15 +78,15 @@ namespace memory { /// \tparam Ty Type of the value to read (must be trivially copyable) /// \param dst Pointer to the destination where the read value will be stored /// \return Expected containing the destination pointer on success, or an error code on failure - template - std::expected read(Ty* dst) const { + template + std::expected read(Ty* dst) const { return memory::reader.read(dst, address_).transform([dst](auto) { return dst; }); } /// \brief Read a vector of bytes from the address /// \param size Number of bytes to read /// \return Expected containing the read vector on success, or an error code on failure - [[nodiscard]] std::expected, e_error_code> read_vector(std::size_t size) const { + [[nodiscard]] std::expected, ErrorCode> read_vector(std::size_t size) const { std::vector result(size); return memory::reader.read(result.data(), address_, size).transform([&result](auto) { return result; }); } @@ -94,8 +94,8 @@ namespace memory { /// \brief Dereference the address to read a value /// \tparam Ty Type of the value to read (default is address) /// \return Expected containing the dereferenced value on success, or an error code on failure - template - [[nodiscard]] std::expected deref() const { + template + [[nodiscard]] std::expected deref() const { return memory::reader.read(inner()); } @@ -103,17 +103,17 @@ namespace memory { /// \tparam Ty Type of the value to read (default is address) /// \param count Number of times to dereference (default is 1) /// \return Expected containing the final dereferenced value on success, or an error code on failure - template - [[nodiscard]] std::expected get(std::size_t count = 1) const noexcept { + template + [[nodiscard]] std::expected get(std::size_t count = 1) const noexcept { if (!address_ || count == 0) { - return std::unexpected(e_error_code::INVALID_ADDRESS); + return std::unexpected(ErrorCode::INVALID_ADDRESS); } auto tmp = *this; for (std::size_t i = 1; i < count; ++i) { auto deref_value = tmp.deref(); if (!deref_value) { - return std::unexpected(e_error_code::NOT_ENOUGH_BYTES); + return std::unexpected(ErrorCode::NOT_ENOUGH_BYTES); } tmp = *deref_value; } @@ -125,7 +125,7 @@ namespace memory { /// \tparam Ty Type of the pointer (default is address) /// \param offset Offset to add to the address (default is 0) /// \return Pointer of type Ty* to the address (plus offset) - template + template [[nodiscard]] constexpr Ty* ptr(std::ptrdiff_t offset = 0) const noexcept { return this->offset(offset).as>(); } @@ -134,7 +134,7 @@ namespace memory { /// \tparam Ty Type of the pointer (default is address) /// \param offset Offset to add to the address before getting the pointer (default is 0) /// \return Pointer of type Ty* to the original address (plus offset) - template + template [[nodiscard]] constexpr Ty* self_inc_ptr(std::ptrdiff_t offset = 0) noexcept { Ty* result = ptr(offset); *this = Address{result}.offset(sizeof(Ty)); @@ -146,8 +146,8 @@ namespace memory { /// \param data The data to write /// \param offset Offset to add to the address before writing (default is 0) /// \return Expected containing this address on success, or an error code on failure - template - std::expected self_write_inc(const Ty& data, std::ptrdiff_t offset = 0) noexcept { + template + std::expected self_write_inc(const Ty& data, std::ptrdiff_t offset = 0) noexcept { auto result = this->offset(offset).write(data); *this = this->offset(offset + sizeof(Ty)); return result; @@ -194,7 +194,7 @@ namespace memory { /// \brief Cast the address to another type (alias for cast) /// \tparam Ty The destination type (must be trivially copyable) /// \return The address cast to the specified type - template + template [[nodiscard]] constexpr Ty as() const noexcept { return cast(); } @@ -203,7 +203,7 @@ namespace memory { /// \tparam Ty The integral type to read /// \return Expected containing the read value on success, or an error code on failure template - [[nodiscard]] std::expected read_le() const { + [[nodiscard]] std::expected read_le() const { auto result = read(); if (!result) { return result; @@ -218,7 +218,7 @@ namespace memory { /// \tparam Ty The integral type to read /// \return Expected containing the read value on success, or an error code on failure template - [[nodiscard]] std::expected read_be() const { + [[nodiscard]] std::expected read_be() const { auto result = read(); if (!result) { return result; @@ -342,7 +342,7 @@ struct std::formatter : std::formatter { /// Custom hash implementation for std::hash to use this type in containers template <> struct std::hash { - size_t operator()(const memory::Address& instance) const noexcept { + std::size_t operator()(const memory::Address& instance) const noexcept { return std::hash()(instance.inner()); } }; diff --git a/src/lib/es3n1n/common/memory/range.hpp b/src/lib/es3n1n/common/memory/range.hpp index 3c3c42e..98063d4 100644 --- a/src/lib/es3n1n/common/memory/range.hpp +++ b/src/lib/es3n1n/common/memory/range.hpp @@ -2,14 +2,36 @@ #include "address.hpp" namespace memory { - using rva_t = memory::address; - - struct range_t { - rva_t start; - rva_t end; + /// \brief Represents a contiguous range of memory. + struct Range { + Address start; ///< The starting address of the range. + Address end; ///< The ending address of the range (exclusive). + /// \brief Calculates the size of the range in bytes. + /// \return The size of the range as a std::size_t. + /// \note This method is marked as nodiscard to encourage using the returned value. [[nodiscard]] constexpr std::size_t size() const { return (end - start).as(); } + + /// \brief Checks if the range is empty. + /// \return true if the range is empty (start == end), false otherwise. + [[nodiscard]] constexpr bool is_empty() const { + return start == end; + } + + /// \brief Checks if a given address is within the range. + /// \param address The address to check. + /// \return true if the address is within the range, false otherwise. + [[nodiscard]] constexpr bool contains(const Address& address) const { + return address >= start && address < end; + } + + /// \brief Checks if this range overlaps with another range. + /// \param other The other range to check for overlap. + /// \return true if the ranges overlap, false otherwise. + [[nodiscard]] constexpr bool overlaps(const Range& other) const { + return start < other.end && other.start < end; + } }; } // namespace memory diff --git a/src/lib/es3n1n/common/memory/reader.hpp b/src/lib/es3n1n/common/memory/reader.hpp index 11f42f5..2608822 100644 --- a/src/lib/es3n1n/common/memory/reader.hpp +++ b/src/lib/es3n1n/common/memory/reader.hpp @@ -10,106 +10,146 @@ #include "es3n1n/common/traits.hpp" namespace memory { - enum class e_error_code : std::uint8_t { - UNKNOWN_ERROR = 0, - INVALID_PARAMETERS, - INVALID_ADDRESS, - NOT_ENOUGH_BYTES, + /// \brief Error codes for memory operations + enum class ErrorCode : std::uint8_t { + UNKNOWN_ERROR = 0, ///< An unknown error occurred + INVALID_PARAMETERS, ///< Invalid parameters (sizes, most likely) were provided + INVALID_ADDRESS, ///< The provided address is invalid + NOT_ENOUGH_BYTES, ///< Not enough bytes available for the operation }; - // Not std::function in favor of constexpr-ness - using read_primitive_t = std::expected (*)(void*, std::uintptr_t, std::size_t); - using write_primitive_t = std::expected (*)(std::uintptr_t, const void*, std::size_t); + /// \brief Function pointer type for read primitive operations + /// \param buffer Pointer to the output buffer + /// \param address Source address to read from + /// \param size Number of bytes to read + /// \return Expected number of bytes read or an error code + using ReadPrimitive = std::expected (*)(void* buffer, std::uintptr_t address, std::size_t size); + + /// \brief Function pointer type for write primitive operations + /// \param address Destination address to write to + /// \param buffer Pointer to the data to write + /// \param size Number of bytes to write + /// \return Expected number of bytes written or an error code + using WritePrimitive = std::expected (*)(std::uintptr_t address, const void* buffer, std::size_t size); namespace detail { - inline std::optional sanitize_parameters(const void* buffer, const std::uintptr_t address, const std::size_t size) { + /// \brief Sanitize input parameters for memory operations + /// \param buffer Pointer to the buffer + /// \param address Memory address + /// \param size Number of bytes + /// \return Optional error code if parameters are invalid, nullopt otherwise + inline std::optional sanitize_parameters(const void* buffer, const std::uintptr_t address, const std::size_t size) { if (buffer == nullptr || address == 0U) { - return e_error_code::INVALID_ADDRESS; + return ErrorCode::INVALID_ADDRESS; } if (size == 0U) { - return e_error_code::INVALID_PARAMETERS; + return ErrorCode::INVALID_PARAMETERS; } return std::nullopt; } } // namespace detail - /// Default read primitive - /// \param buffer output buffer pointer - /// \param address source address - /// \param size number of bytes to read - /// \return number of bytes read on success, error code on failure - inline std::expected default_read(void* buffer, const std::uintptr_t address, const std::size_t size) { + /// \brief Default read primitive implementation + /// \param buffer Pointer to the output buffer + /// \param address Source address to read from + /// \param size Number of bytes to read + /// \return Expected number of bytes read or an error code + inline std::expected default_read(void* buffer, const std::uintptr_t address, const std::size_t size) { if (auto err = detail::sanitize_parameters(buffer, address, size); err.has_value()) { return std::unexpected(err.value()); } - // NOLINTNEXTLINE - std::memcpy(buffer, reinterpret_cast(address), size); + std::memcpy(buffer, reinterpret_cast(address), size); return size; } - /// Default write primitive - /// \param address destination address - /// \param buffer buffer of data to write - /// \param size number of bytes to write - /// \return number of bytes written on success, error code on failure - inline std::expected default_write(std::uintptr_t address, const void* buffer, const std::size_t size) { + /// \brief Default write primitive implementation + /// \param address Destination address to write to + /// \param buffer Pointer to the data to write + /// \param size Number of bytes to write + /// \return Expected number of bytes written or an error code + inline std::expected default_write(const std::uintptr_t address, const void* buffer, const std::size_t size) { if (auto err = detail::sanitize_parameters(buffer, address, size); err.has_value()) { return std::unexpected(err.value()); } - // NOLINTNEXTLINE std::memcpy(reinterpret_cast(address), buffer, size); return size; } - /// Memory reader implementation + /// \brief Memory reader implementation class Reader : public base::NonCopyable { public: + /// \brief Default constructor constexpr Reader(): read_primitive_(default_read), write_primitive_(default_write) { } - void read_primitive(read_primitive_t read_func) { + /// \brief Set the read primitive function + /// \param read_func Function to use for read operations + void read_primitive(ReadPrimitive read_func) { read_primitive_ = read_func; } - void write_primitive(write_primitive_t write_func) { + /// \brief Set the write primitive function + /// \param write_func Function to use for write operations + void write_primitive(WritePrimitive write_func) { write_primitive_ = write_func; } - std::expected read(void* buffer, const std::uintptr_t address, const std::size_t size) const { + /// \brief Read memory + /// \param buffer Pointer to the output buffer + /// \param address Source address to read from + /// \param size Number of bytes to read + /// \return Expected number of bytes read or an error code + std::expected read(void* buffer, const std::uintptr_t address, const std::size_t size) const { return read_primitive_(buffer, address, size); } - template - std::expected read(Ty* dst, const std::uintptr_t src) const { + /// \brief Read a trivially copyable type from memory + /// \tparam Ty Type to read (must be trivially copyable) + /// \param dst Pointer to the destination object + /// \param src Source address to read from + /// \return Expected number of bytes read or an error code + template + std::expected read(Ty* dst, const std::uintptr_t src) const { return read(dst, src, sizeof(Ty)); } - template - std::expected read(const std::uintptr_t src) const { - Ty _obj = {}; - - if (const auto res = read(&_obj, src); !res.has_value()) { + /// \brief Read and return a trivially copyable type from memory + /// \tparam Ty Type to read (must be trivially copyable) + /// \param src Source address to read from + /// \return Expected object of type Ty or an error code + template + std::expected read(const std::uintptr_t src) const { + Ty obj = {}; + if (const auto res = read(&obj, src); !res.has_value()) { return std::unexpected(res.error()); } - - return _obj; + return obj; } - std::expected write(std::uintptr_t address, const void* buffer, const std::size_t size) const { + /// \brief Write memory + /// \param address Destination address to write to + /// \param buffer Pointer to the data to write + /// \param size Number of bytes to write + /// \return Expected number of bytes written or an error code + std::expected write(const std::uintptr_t address, const void* buffer, const std::size_t size) const { return write_primitive_(address, buffer, size); } - template - std::expected write(const Ty* src, const std::uintptr_t dst) const { + /// \brief Write a trivially copyable type to memory + /// \tparam Ty Type to write (must be trivially copyable) + /// \param src Pointer to the source object + /// \param dst Destination address to write to + /// \return Expected number of bytes written or an error code + template + std::expected write(const Ty* src, const std::uintptr_t dst) const { return write(dst, src, sizeof(Ty)); } private: - read_primitive_t read_primitive_; - write_primitive_t write_primitive_; + ReadPrimitive read_primitive_; + WritePrimitive write_primitive_; }; - /// Shared reader instance - inline constinit auto reader = Reader(); + inline constinit auto reader = Reader(); ///< Global memory reader instance } // namespace memory diff --git a/src/lib/es3n1n/common/platform.hpp b/src/lib/es3n1n/common/platform.hpp index e05a5b1..c8cf3f7 100644 --- a/src/lib/es3n1n/common/platform.hpp +++ b/src/lib/es3n1n/common/platform.hpp @@ -2,8 +2,8 @@ #include #include -/// Systems -/// +/// \name System Detection +/// \{ #if defined(_WIN64) #define PLATFORM_IS_WIN true #define PLATFORM_IS_WIN32 false @@ -55,10 +55,10 @@ #else #error UNKNOWN SYSTEM #endif +/// \} -/// -/// Compilers -/// +/// \name Compiler Detection +/// \{ #if defined(__GNUC__) #define PLATFORM_IS_GCC true #define PLATFORM_IS_CLANG false @@ -74,9 +74,9 @@ #else #error UNKNOWN_COMPILER #endif +/// \} -/// cxx interface -/// +/// \brief Namespace containing platform-specific information namespace platform { [[maybe_unused]] constexpr size_t bitness = std::numeric_limits::digits; [[maybe_unused]] constexpr bool is_x64 = bitness == 64; @@ -96,28 +96,14 @@ namespace platform { [[maybe_unused]] constexpr bool is_msvc = PLATFORM_IS_MSVC; } // namespace platform -/// \note: @es3n1n: this is needed because on gcc we'll get some warnings -/// since `[[maybe_unused]]` attribute is getting ignored on a member of -/// a class or struct -/// -#if PLATFORM_IS_GCC - #define MAYBE_UNUSED_FIELD -#else - #define MAYBE_UNUSED_FIELD [[maybe_unused]] -#endif - -/// Platform-specific includes -/// +/// \brief Include platform-specific headers #ifndef COMMON_NO_COMMON_INCLUDES #if PLATFORM_IS_WIN - #ifndef NONOGDI - #define NOGDI - #endif #include #endif #endif -/// Compiler-specific definitions +/// \brief Force inline macro #if PLATFORM_IS_MSVC #define COMMON_FORCE_INLINE __forceinline #else diff --git a/src/lib/es3n1n/common/progress.hpp b/src/lib/es3n1n/common/progress.hpp index 362bcb1..6dfc821 100644 --- a/src/lib/es3n1n/common/progress.hpp +++ b/src/lib/es3n1n/common/progress.hpp @@ -32,13 +32,9 @@ namespace progress { } private: - /// \brief Stopwatch - stopwatch::Stopwatch stopwatch_ = {}; - /// \brief Progress bar title - std::string title_ = {}; - /// \brief Total number of steps - std::size_t steps_ = {}; - /// \brief Current step - std::ptrdiff_t step_ = -1; // we start at -1, and it will automatically increment it to 0 + stopwatch::Stopwatch stopwatch_ = {}; ///< Stopwatch for elapsed time + std::string title_ = {}; ///< Title of the progress + std::size_t steps_ = {}; ///< Total steps + std::ptrdiff_t step_ = -1; ///< Current step. We start at -1, and it will automatically increment it to 0 }; } // namespace progress diff --git a/src/lib/es3n1n/common/random.hpp b/src/lib/es3n1n/common/random.hpp index 9fa2538..c7f4751 100644 --- a/src/lib/es3n1n/common/random.hpp +++ b/src/lib/es3n1n/common/random.hpp @@ -3,14 +3,16 @@ #include "types.hpp" #include +#include #include #include #include +/// Intentionally named rnd and not random to avoid conflicts with the standard library (libc++, libstdc++) namespace rnd { namespace detail { - /// We are gonna use the mersenne twister prng because its pretty convenient - /// and its already present in std + /// We are going to use the Mersenne Twister PRNG because it's pretty convenient + /// and it's already present in std inline std::mt19937_64 prng; /// \brief Set the MT seed @@ -41,7 +43,7 @@ namespace rnd { explicit UniformIntDistribution(ResultTy min, ResultTy max = (std::numeric_limits::max)()): min_(min), max_(max) { } /// \brief Generates a random integer within the distribution range. - /// \engine The random engine instance to use. + /// \param engine The random engine instance to use. template ResultTy operator()(Engine& engine) { return eval(engine, min_, max_); @@ -76,7 +78,7 @@ namespace rnd { }; } // namespace detail - /// \brief Get random number in desired range + /// \brief Get a random number in the desired range /// \tparam Ty result type /// \param min minimal value, by default set to the min limit of the `Ty` type /// \param max maximal value, by default set to the max limit of the `Ty` type @@ -89,14 +91,14 @@ namespace rnd { } /// \brief Generate a number of bytes - /// \param ptr pointer where it should write these bytes to - /// \param size size + /// \param ptr pointer where it should write these bytes + /// \param size number of bytes to generate inline void bytes(std::uint8_t* ptr, const std::size_t size) { std::generate_n(ptr, size, []() -> std::uint8_t { return number(); }); } /// \brief Generate a number of bytes and return them as a vector - /// \param size size + /// \param size number of bytes to generate /// \return vector filled with random bytes [[nodiscard]] inline std::vector bytes(const std::size_t size) { std::vector result = {}; @@ -106,17 +108,17 @@ namespace rnd { return result; } - /// \brief - /// \param chance (from 0 to 100)% chance - /// \return true/false + /// \brief Generate a random boolean based on a percentage chance + /// \param chance percentage chance (from 0 to 100) + /// \return true or false [[nodiscard]] inline bool chance(const std::uint8_t chance) { return number(0, 100) <= chance; } /// \brief Get a random item from the container - /// \tparam Rng Range + /// \tparam Rng Range type /// \param range Range value (vector/array/anything) - /// \return random value reference + /// \return reference to a random value from the range template [[nodiscard]] const std::ranges::range_value_t& item(Rng&& range) { auto it = std::ranges::begin(range); @@ -126,9 +128,9 @@ namespace rnd { } /// \brief Select between values - /// \tparam TArgs typename of the operands + /// \tparam TArgs types of the operands /// \param args variadic options - /// \return random choosen result + /// \return randomly chosen result template [[nodiscard]] auto or_(TArgs... args) { return item(types::to_array(std::forward(args)...)); diff --git a/src/lib/es3n1n/common/stopwatch.hpp b/src/lib/es3n1n/common/stopwatch.hpp index 935bd73..5afe334 100644 --- a/src/lib/es3n1n/common/stopwatch.hpp +++ b/src/lib/es3n1n/common/stopwatch.hpp @@ -1,115 +1,113 @@ #pragma once #include "base.hpp" #include +#include +#include namespace stopwatch { - /// \brief Our custom elapsed time storage + /// \brief Custom elapsed time storage class class ElapsedTime { public: - /// \brief Explicit conversion from chrono duration to our own stuff - /// \tparam Rep Duration rep - /// \tparam Period Duration period - /// \param elapsed Duration value + /// \brief Construct ElapsedTime from a chrono duration + /// \tparam Rep The arithmetic type representing the number of ticks + /// \tparam Period A std::ratio representing the tick period + /// \param elapsed The duration to convert template - explicit ElapsedTime(const std::chrono::duration elapsed) { - microseconds_ = std::chrono::duration_cast(elapsed); - hours_ = remainder_microseconds_cast(); - minutes_ = remainder_microseconds_cast(); - seconds_ = remainder_microseconds_cast(); - milliseconds_ = remainder_microseconds_cast(); + explicit ElapsedTime(const std::chrono::duration& elapsed) { + total_microseconds_ = std::chrono::duration_cast(elapsed); + hours_ = extract_component(); + minutes_ = extract_component(); + seconds_ = extract_component(); + milliseconds_ = extract_component(); } - /// \brief Convert elapsed time to string in format "{} hr {} min {} sec {} ms" - /// \return String + /// \brief Convert elapsed time to a formatted string + /// \return A string representation in the format "X hr Y min Z sec W ms" or "V microseconds" [[nodiscard]] std::string str() const { - std::string result = {}; - /// Convert hours - if (auto hr = hours_.count()) { - result += std::format(" {} hr", hr); - } - - /// Convert minutes - if (auto min = minutes_.count()) { - result += std::format(" {} min", min); - } - - /// Convert seconds - if (auto sec = seconds_.count()) { - result += std::format(" {} sec", sec); - } - - /// Convert milliseconds - if (auto ms = milliseconds_.count()) { - result += std::format(" {} ms", ms); - } + std::string result; + append_if_non_zero(result, hours_, "hr"); + append_if_non_zero(result, minutes_, "min"); + append_if_non_zero(result, seconds_, "sec"); + append_if_non_zero(result, milliseconds_, "ms"); - /// Convert microseconds only if others are empty if (result.empty()) { - result += std::format(" {} microseconds", microseconds_.count()); + return std::format("{} microseconds", total_microseconds_.count()); } - /// Remove the leading space - result = result.substr(1); - + result = result.substr(1); // Remove leading space return result; } private: - /// \brief Get remainder from total microseconds for a given duration - /// \tparam Dst Destination duration type - /// \return Converted amount - template - [[nodiscard]] Dst remainder_microseconds_cast() noexcept { - const auto result = std::chrono::duration_cast(microseconds_); - microseconds_ -= std::chrono::duration_cast(result); - return result; + /// \brief Extract a time component from the total microseconds + /// \tparam DurationType The type of duration to extract + /// \return The extracted duration component + template + [[nodiscard]] DurationType extract_component() noexcept { + const auto component = std::chrono::duration_cast(total_microseconds_); + total_microseconds_ -= std::chrono::duration_cast(component); + return component; + } + + /// \brief Append a non-zero time component to the result string + /// \tparam Ty The arithmetic type representing the number of ticks + /// \tparam Period A std::ratio representing the tick period of the duration + /// \param result The string to append to + /// \param duration The std::chrono::duration to check and potentially append + /// \param unit The string representation of the time unit (e.g., "hr", "min", "sec") + template + static void append_if_non_zero(std::string& result, const std::chrono::duration& duration, const char* unit) { + if (const auto count = duration.count(); count > 0) { + result += std::format(" {} {}", count, unit); + } } - /// \brief Elapsed hours - std::chrono::hours hours_ = {}; - /// \brief Elapsed minutes - std::chrono::minutes minutes_ = {}; - /// \brief Elapsed seconds - std::chrono::seconds seconds_ = {}; - /// \brief Elapsed milliseconds - std::chrono::milliseconds milliseconds_ = {}; - /// \brief Elapsed **total** microseconds - std::chrono::microseconds microseconds_ = {}; + std::chrono::hours hours_{}; ///< Elapsed hours + std::chrono::minutes minutes_{}; ///< Elapsed minutes + std::chrono::seconds seconds_{}; ///< Elapsed seconds + std::chrono::milliseconds milliseconds_{}; ///< Elapsed milliseconds + std::chrono::microseconds total_microseconds_{}; ///< Total elapsed microseconds }; - /// \brief A stopwatch class that should be used for all the time elapsing stuff + /// \brief A high-resolution stopwatch class for time measurements class Stopwatch : public base::NonCopyable { using Clock = std::chrono::high_resolution_clock; using TimePoint = std::chrono::time_point; public: - /// \brief General constructor + /// \brief Default constructor + /// \note Automatically calls reset() to set the start time Stopwatch() noexcept { reset(); } - /// \brief Start time reset + /// \brief Reset the stopwatch to the current time void reset() { started_ = Clock::now(); } - /// \brief Get the difference between current and start time - /// \return ElapsedTime struct - [[nodiscard]] auto elapsed() const noexcept { + /// \brief Get the elapsed time since the last reset + /// \return An ElapsedTime object representing the time difference + [[nodiscard]] ElapsedTime elapsed() const noexcept { return ElapsedTime(Clock::now() - started_); } private: - /// \brief Start time - TimePoint started_ = {}; + TimePoint started_{}; ///< The start time point }; + } // namespace stopwatch -/// \brief Elapsed time formatter +/// \brief Custom formatter for ElapsedTime to allow use with std::format template <> struct std::formatter : std::formatter { - template - constexpr auto format(const stopwatch::ElapsedTime& instance, FormatContextTy& ctx) const { + /// \brief Format the ElapsedTime object + /// \tparam FormatContext The type of the format context + /// \param instance The ElapsedTime instance to format + /// \param ctx The format context + /// \return An iterator past the last character written + template + constexpr auto format(const stopwatch::ElapsedTime& instance, FormatContext& ctx) const { return std::formatter::format(instance.str(), ctx); } }; diff --git a/src/lib/es3n1n/common/string_parser.hpp b/src/lib/es3n1n/common/string_parser.hpp index a2bd429..f643233 100644 --- a/src/lib/es3n1n/common/string_parser.hpp +++ b/src/lib/es3n1n/common/string_parser.hpp @@ -5,17 +5,15 @@ #include #include #include +#include +#include #include namespace string_parser { namespace detail { - /// \note: @annihilatorq: this scope is a mess, but idk how to make - /// it more readable & cleaner, unfortunately, std::from_chars - /// does not support strings with "0x" prefixes - - /// Since std::from_chars doesn't support "0x" prefixed hex strings, - /// we need to process and remove prefixes before usage. - /// + /// \brief Removes the "0x" prefix from hexadecimal strings + /// \param str The string to process + /// \param is_negative Whether the number is negative void strip_hex_prefix(std::string& str, bool is_negative) { /// We trust the is_negative, we also trust that the input is indeed in hexadecimal form. if (str.size() < 2) { @@ -33,6 +31,13 @@ namespace string_parser { str.erase(0, 2); } + /// \brief Parses a string to an integral type using std::from_chars + /// \tparam Ty The integral type to parse to + /// \param s The string to parse + /// \param base The numeric base of the string (default: 10) + /// \return The parsed integral value + /// \throws std::invalid_argument if parsing fails due to invalid input + /// \throws std::out_of_range if the parsed value is out of range for the type template [[nodiscard]] Ty parse_from_chars(std::string s, int base = 10) { const auto is_negative = s.front() == '-'; @@ -50,46 +55,46 @@ namespace string_parser { throw std::out_of_range("Failed to parse integer from string: out of range"); } - assert(ec == static_cast(0)); + assert(ec == std::errc{}); return result; } } // namespace detail /// \brief Parse int32 from string - /// \param s string that contain int32 - /// \param base base (10 for decimal, 16 for hex, etc) - /// \return parsed value + /// \param s String containing an int32 value + /// \param base Numeric base (10 for decimal, 16 for hex, etc.) + /// \return Parsed int32 value [[nodiscard]] inline std::int32_t parse_int32(const std::string_view s, const std::size_t base = 10) { - return detail::parse_from_chars(s.data(), static_cast(base)); + return detail::parse_from_chars(std::string(s), static_cast(base)); } /// \brief Parse uint32 from string - /// \param s string that contain uint32 - /// \param base base (10 for decimal, 16 for hex, etc) - /// \return parsed value + /// \param s String containing a uint32 value + /// \param base Numeric base (10 for decimal, 16 for hex, etc.) + /// \return Parsed uint32 value [[nodiscard]] inline std::uint32_t parse_uint32(const std::string_view s, const std::size_t base = 10) { - return detail::parse_from_chars(s.data(), static_cast(base)); + return detail::parse_from_chars(std::string(s), static_cast(base)); } /// \brief Parse int8 from string - /// \param s string that contain int8 - /// \param base base (10 for decimal, 16 for hex, etc) - /// \return parsed value + /// \param s String containing an int8 value + /// \param base Numeric base (10 for decimal, 16 for hex, etc.) + /// \return Parsed int8 value [[nodiscard]] inline std::int8_t parse_int8(const std::string_view s, const std::size_t base = 10) { return static_cast(parse_int32(s, base) & 0xFF); } /// \brief Parse uint8 from string - /// \param s string that contain uint8 - /// \param base base (10 for decimal, 16 for hex, etc) - /// \return parsed value + /// \param s String containing a uint8 value + /// \param base Numeric base (10 for decimal, 16 for hex, etc.) + /// \return Parsed uint8 value [[nodiscard]] inline std::uint8_t parse_uint8(const std::string_view s, const std::size_t base = 10) { return parse_uint32(s, base) & 0xFF; } /// \brief Parse bool from string - /// \param s stirng that contain bool - /// \return parsed value + /// \param s String containing a boolean value + /// \return Parsed boolean value [[nodiscard]] inline bool parse_bool(const std::string_view s) { return s == "true" || s == "1"; } @@ -107,10 +112,10 @@ namespace string_parser { }; } // namespace detail - /// \brief Parse the value from string using template - /// \tparam Ty type that it should return - /// \param s string - /// \return parsed value + /// \brief Parse a value from string using a template + /// \tparam Ty Type to parse the string into + /// \param s String to parse + /// \return Parsed value of type Ty template > [[nodiscard]] Ty parse(const std::string_view s) { if constexpr (Ctx::is_int32) { @@ -129,10 +134,10 @@ namespace string_parser { } } - /// \brief Serialize value to string - /// \tparam Ty type that we're serializing - /// \param value value that we should serialize - /// \return serialized value + /// \brief Serialize a value to string + /// \tparam Ty Type of the value to serialize + /// \param value Value to serialize + /// \return Serialized string representation of the value template > [[nodiscard]] std::string serialize(const Ty value) { if constexpr (Ctx::is_number) { @@ -145,9 +150,10 @@ namespace string_parser { } } - /// \brief Parse string to the `out` type and store it in the std::any ref - /// \param out output reference - /// \param s string that it should parse + /// \brief Parse a string and store the result in a std::any + /// \param out Reference to the std::any where the result will be stored + /// \param s String to parse + /// \throws std::runtime_error if the type is unsupported inline void parse_to_any(std::any& out, const std::string_view s) { assert(out.has_value()); @@ -172,9 +178,10 @@ namespace string_parser { throw std::runtime_error(std::format("parse_to_any: Unable to parse '{}' -> unsupported type", s)); } - /// \brief Serialize any value to string - /// \param ref any reference - /// \return serialized string + /// \brief Serialize a std::any value to string + /// \param ref Reference to the std::any to serialize + /// \return Serialized string representation of the value + /// \throws std::runtime_error if the type is unsupported [[nodiscard]] inline std::string serialize_any(const std::any& ref) { assert(ref.has_value()); const auto hash = ref.type().hash_code(); @@ -194,6 +201,6 @@ namespace string_parser { #undef MAKE_CASE - throw std::runtime_error(std::format("serialize_any: Unable to serialize -> unsupported type")); + throw std::runtime_error("serialize_any: Unable to serialize -> unsupported type"); } } // namespace string_parser diff --git a/src/lib/es3n1n/common/traits.hpp b/src/lib/es3n1n/common/traits.hpp index da56dac..a994e3b 100644 --- a/src/lib/es3n1n/common/traits.hpp +++ b/src/lib/es3n1n/common/traits.hpp @@ -4,13 +4,28 @@ #include namespace traits { - /// Used for static assertions - template concept always_false_v = false; + /// \brief Concept for static assertions that always evaluate to false + /// \tparam T A template parameter (defaulted to std::monostate) + /// \details This concept is useful for creating compile-time errors in template specializations + template concept always_false_v = false; + /// \brief Type trait to check if a type is any of the specified types + /// \tparam Ty The type to check + /// \tparam Types Pack of types to check against + /// \returns true if Ty is any of the Types, false otherwise template inline constexpr bool is_any_of_v = std::disjunction_v...>; - template concept trivially_copyable = std::is_trivially_copyable_v; - template concept number = std::integral || std::floating_point; - template concept float_number = is_any_of_v, float, double, long double, numeric::flt_range_t>; -} // namespace traits \ No newline at end of file + /// \brief Concept to check if a type is trivially copyable + /// \tparam Ty The type to check + template concept TriviallyCopyable = std::is_trivially_copyable_v; + + /// \brief Concept to check if a type is a number (integral or floating-point) + /// \tparam Ty The type to check + template concept Number = std::integral || std::floating_point; + + /// \brief Concept to check if a type is a floating-point number or a specific floating-point type + /// \tparam Ty The type to check + /// \details This concept checks for built-in floating-point types and a custom flt_range_t type + template concept FloatNumber = is_any_of_v, float, double, long double, numeric::flt_range_t>; +} // namespace traits diff --git a/src/lib/es3n1n/common/types.hpp b/src/lib/es3n1n/common/types.hpp index f15272a..f314c04 100644 --- a/src/lib/es3n1n/common/types.hpp +++ b/src/lib/es3n1n/common/types.hpp @@ -1,5 +1,7 @@ #pragma once +#include #include +#include #include "base.hpp" #include "memory/address.hpp" @@ -7,41 +9,65 @@ #include "traits.hpp" namespace types { - template - constexpr auto to_array(Args&&... args) { + /// \brief Converts a list of arguments into an std::array + /// \tparam Args Variadic template parameter for the argument types + /// \param args The arguments to convert into an array + /// \return An std::array containing the provided arguments + template + [[nodiscard]] constexpr auto to_array(Args&&... args) { return std::array, sizeof...(Args)>{std::forward(args)...}; } + /// \brief A template class for creating singleton objects + /// \tparam Ty The type of the singleton object template class Singleton : public base::NonCopyable { public: + /// \brief Get the singleton instance + /// \return A reference to the singleton instance [[nodiscard]] static Ty& get() { static Ty instance = {}; return instance; } + + protected: + /// \brief Protected constructor to prevent direct instantiation + Singleton() = default; }; - template - struct ct_string_t { + /// \brief A compile-time string class + /// \tparam N The size of the string including the null terminator + template + struct CtString { std::array data{}; - [[nodiscard]] constexpr size_t size() const { + /// \brief Get the size of the string (excluding null terminator) + /// \return The size of the string + [[nodiscard]] constexpr std::size_t size() const { return N - 1; } - constexpr /* implicit */ ct_string_t(const char (&init)[N]) { + /// \brief Implicit constructor from a char array + /// \param init The char array to initialize the CtString with + constexpr /* implicit */ CtString(const char (&init)[N]) { std::copy_n(init, N, data.begin()); } }; + /// \brief A type that represents a compile-time string as a type + /// \tparam str A CtString instance template - requires std::is_same_v, ct_string_t> - struct type_string_t { - static constexpr const char* data() { + requires std::is_same_v, CtString> + struct TypeString { + /// \brief Get the underlying string data + /// \return A pointer to the string data + [[nodiscard]] static constexpr const char* data() { return str.data.data(); } - static constexpr size_t size() { + /// \brief Get the size of the string (excluding null terminator) + /// \return The size of the string + [[nodiscard]] static constexpr std::size_t size() { return str.size(); } }; diff --git a/src/tests/files.cpp b/src/tests/files.cpp index b098dd8..e0ea43a 100644 --- a/src/tests/files.cpp +++ b/src/tests/files.cpp @@ -13,6 +13,7 @@ TEST(files, basics) { auto test_out_data = files::read_file(path); - EXPECT_EQ(std::memcmp(test_data, test_out_data.data(), sizeof(test_data)), 0); + EXPECT_TRUE(test_out_data.has_value()); + EXPECT_EQ(std::memcmp(test_data, test_out_data->data(), sizeof(test_data)), 0); remove(path); } \ No newline at end of file diff --git a/src/tests/memory/address.cpp b/src/tests/memory/address.cpp index 5412e88..c98e5a8 100644 --- a/src/tests/memory/address.cpp +++ b/src/tests/memory/address.cpp @@ -118,16 +118,16 @@ TEST(address, error_handling) { auto read_result = addr.read(); EXPECT_FALSE(read_result.has_value()); - EXPECT_EQ(read_result.error(), memory::e_error_code::INVALID_ADDRESS); + EXPECT_EQ(read_result.error(), memory::ErrorCode::INVALID_ADDRESS); int value = 42; auto write_result = addr.write(value); EXPECT_FALSE(write_result.has_value()); - EXPECT_EQ(write_result.error(), memory::e_error_code::INVALID_ADDRESS); + EXPECT_EQ(write_result.error(), memory::ErrorCode::INVALID_ADDRESS); auto get_result = addr.get(5); EXPECT_FALSE(get_result.has_value()); - EXPECT_EQ(get_result.error(), memory::e_error_code::INVALID_ADDRESS); + EXPECT_EQ(get_result.error(), memory::ErrorCode::INVALID_ADDRESS); } TEST(address, formatting) { diff --git a/src/tests/memory/range.cpp b/src/tests/memory/range.cpp index 5e3c212..f993036 100644 --- a/src/tests/memory/range.cpp +++ b/src/tests/memory/range.cpp @@ -1,3 +1,24 @@ #include "es3n1n/common/memory/range.hpp" -static_assert(memory::range_t{.start = 2, .end = 4}.size() == 2); +static_assert(memory::Range{.start = nullptr, .end = 10}.size() == 10); +static_assert(memory::Range{.start = 100, .end = 200}.size() == 100); +static_assert(memory::Range{.start = nullptr, .end = nullptr}.size() == 0); + +static_assert(memory::Range{.start = nullptr, .end = nullptr}.is_empty()); +static_assert(!memory::Range{.start = nullptr, .end = 1}.is_empty()); + +static_assert(memory::Range{.start = nullptr, .end = 10}.contains(5)); +static_assert(memory::Range{.start = nullptr, .end = 10}.contains(nullptr)); +static_assert(!memory::Range{.start = nullptr, .end = 10}.contains(10)); +static_assert(!memory::Range{.start = nullptr, .end = 10}.contains(15)); + +static_assert(memory::Range{.start = nullptr, .end = 10}.overlaps(memory::Range{.start = 5, .end = 15})); +static_assert(memory::Range{.start = nullptr, .end = 10}.overlaps(memory::Range{.start = nullptr, .end = 5})); +static_assert(memory::Range{.start = nullptr, .end = 10}.overlaps(memory::Range{.start = nullptr, .end = 10})); +static_assert(!memory::Range{.start = nullptr, .end = 10}.overlaps(memory::Range{.start = 10, .end = 20})); +static_assert(!memory::Range{.start = nullptr, .end = 10}.overlaps(memory::Range{.start = 20, .end = 30})); + +static_assert(memory::Range{.start = nullptr, .end = static_cast(-1)}.size() == static_cast(-1)); + +static_assert(std::is_standard_layout_v); +static_assert(std::is_trivially_copyable_v); diff --git a/src/tests/memory/reader.cpp b/src/tests/memory/reader.cpp index 873286c..fb768c4 100644 --- a/src/tests/memory/reader.cpp +++ b/src/tests/memory/reader.cpp @@ -3,11 +3,11 @@ #include #include -inline std::expected read_impl(void*, const std::uintptr_t, const std::size_t) { +inline std::expected read_impl(void*, const std::uintptr_t, const std::size_t) { throw std::runtime_error(""); } -inline std::expected write_impl(std::uintptr_t, const void*, const std::size_t) { +inline std::expected write_impl(std::uintptr_t, const void*, const std::size_t) { throw std::runtime_error(""); } diff --git a/src/tests/traits.cpp b/src/tests/traits.cpp index 50f42df..a99c764 100644 --- a/src/tests/traits.cpp +++ b/src/tests/traits.cpp @@ -7,11 +7,11 @@ static_assert(!traits::always_false_v); static_assert(traits::is_any_of_v); static_assert(!traits::is_any_of_v); -static_assert(traits::trivially_copyable); -static_assert(!traits::trivially_copyable); +static_assert(traits::TriviallyCopyable); +static_assert(!traits::TriviallyCopyable); -static_assert(traits::number); -static_assert(!traits::number); +static_assert(traits::Number); +static_assert(!traits::Number); -static_assert(traits::float_number); -static_assert(!traits::float_number); +static_assert(traits::FloatNumber); +static_assert(!traits::FloatNumber); diff --git a/src/tests/types.cpp b/src/tests/types.cpp index 40b942b..89d9571 100644 --- a/src/tests/types.cpp +++ b/src/tests/types.cpp @@ -43,9 +43,9 @@ constexpr bool check_impl(std::index_sequence) { return (ensure() && ...); } -template +template consteval auto operator""_ct() { - using s = types::type_string_t; + using s = types::TypeString; static_assert(s::size() == 5); return check_impl(std::make_index_sequence{}); }