diff options
Diffstat (limited to '')
-rw-r--r-- | src/common/assert.h | 8 | ||||
-rw-r--r-- | src/common/uuid.cpp | 54 | ||||
-rw-r--r-- | src/common/uuid.h | 30 |
3 files changed, 90 insertions, 2 deletions
diff --git a/src/common/assert.h b/src/common/assert.h index b3ba35c0f..33060d865 100644 --- a/src/common/assert.h +++ b/src/common/assert.h @@ -52,8 +52,12 @@ assert_noinline_call(const Fn& fn) { #define DEBUG_ASSERT(_a_) ASSERT(_a_) #define DEBUG_ASSERT_MSG(_a_, ...) ASSERT_MSG(_a_, __VA_ARGS__) #else // not debug -#define DEBUG_ASSERT(_a_) -#define DEBUG_ASSERT_MSG(_a_, _desc_, ...) +#define DEBUG_ASSERT(_a_) \ + do { \ + } while (0) +#define DEBUG_ASSERT_MSG(_a_, _desc_, ...) \ + do { \ + } while (0) #endif #define UNIMPLEMENTED() ASSERT_MSG(false, "Unimplemented code!") diff --git a/src/common/uuid.cpp b/src/common/uuid.cpp index 18303a1e3..d7435a6e9 100644 --- a/src/common/uuid.cpp +++ b/src/common/uuid.cpp @@ -6,10 +6,64 @@ #include <fmt/format.h> +#include "common/assert.h" #include "common/uuid.h" namespace Common { +namespace { + +bool IsHexDigit(char c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); +} + +u8 HexCharToByte(char c) { + if (c >= '0' && c <= '9') { + return static_cast<u8>(c - '0'); + } + if (c >= 'a' && c <= 'f') { + return static_cast<u8>(c - 'a' + 10); + } + if (c >= 'A' && c <= 'F') { + return static_cast<u8>(c - 'A' + 10); + } + ASSERT_MSG(false, "{} is not a hexadecimal digit!", c); + return u8{0}; +} + +} // Anonymous namespace + +u128 HexStringToU128(std::string_view hex_string) { + const size_t length = hex_string.length(); + + // Detect "0x" prefix. + const bool has_0x_prefix = length > 2 && hex_string[0] == '0' && hex_string[1] == 'x'; + const size_t offset = has_0x_prefix ? 2 : 0; + + // Check length. + if (length > 32 + offset) { + ASSERT_MSG(false, "hex_string has more than 32 hexadecimal characters!"); + return INVALID_UUID; + } + + u64 lo = 0; + u64 hi = 0; + for (size_t i = 0; i < length - offset; ++i) { + const char c = hex_string[length - 1 - i]; + if (!IsHexDigit(c)) { + ASSERT_MSG(false, "{} is not a hexadecimal digit!", c); + return INVALID_UUID; + } + if (i < 16) { + lo |= u64{HexCharToByte(c)} << (i * 4); + } + if (i >= 16) { + hi |= u64{HexCharToByte(c)} << ((i - 16) * 4); + } + } + return u128{lo, hi}; +} + UUID UUID::Generate() { std::random_device device; std::mt19937 gen(device()); diff --git a/src/common/uuid.h b/src/common/uuid.h index 0ffa37e7c..2353179d8 100644 --- a/src/common/uuid.h +++ b/src/common/uuid.h @@ -5,6 +5,7 @@ #pragma once #include <string> +#include <string_view> #include "common/common_types.h" @@ -12,12 +13,30 @@ namespace Common { constexpr u128 INVALID_UUID{{0, 0}}; +/** + * Converts a hex string to a 128-bit unsigned integer. + * + * The hex string can be formatted in lowercase or uppercase, with or without the "0x" prefix. + * + * This function will assert and return INVALID_UUID under the following conditions: + * - If the hex string is more than 32 characters long + * - If the hex string contains non-hexadecimal characters + * + * @param hex_string Hexadecimal string + * + * @returns A 128-bit unsigned integer if successfully converted, INVALID_UUID otherwise. + */ +[[nodiscard]] u128 HexStringToU128(std::string_view hex_string); + struct UUID { // UUIDs which are 0 are considered invalid! u128 uuid; UUID() = default; constexpr explicit UUID(const u128& id) : uuid{id} {} constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {} + explicit UUID(std::string_view hex_string) { + uuid = HexStringToU128(hex_string); + } [[nodiscard]] constexpr explicit operator bool() const { return uuid != INVALID_UUID; @@ -50,3 +69,14 @@ struct UUID { static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); } // namespace Common + +namespace std { + +template <> +struct hash<Common::UUID> { + size_t operator()(const Common::UUID& uuid) const noexcept { + return uuid.uuid[1] ^ uuid.uuid[0]; + } +}; + +} // namespace std |