summaryrefslogtreecommitdiffstats
path: root/src/common/new_uuid.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/common/new_uuid.cpp182
1 files changed, 182 insertions, 0 deletions
diff --git a/src/common/new_uuid.cpp b/src/common/new_uuid.cpp
new file mode 100644
index 000000000..0442681c8
--- /dev/null
+++ b/src/common/new_uuid.cpp
@@ -0,0 +1,182 @@
+// Copyright 2022 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <bit>
+#include <random>
+
+#include <fmt/format.h>
+
+#include "common/assert.h"
+#include "common/new_uuid.h"
+#include "common/tiny_mt.h"
+
+namespace Common {
+
+namespace {
+
+constexpr size_t RawStringSize = sizeof(NewUUID) * 2;
+constexpr size_t FormattedStringSize = RawStringSize + 4;
+
+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};
+}
+
+std::array<u8, 0x10> ConstructFromRawString(std::string_view raw_string) {
+ std::array<u8, 0x10> uuid;
+
+ for (size_t i = 0; i < RawStringSize; i += 2) {
+ uuid[i / 2] =
+ static_cast<u8>((HexCharToByte(raw_string[i]) << 4) | HexCharToByte(raw_string[i + 1]));
+ }
+
+ return uuid;
+}
+
+std::array<u8, 0x10> ConstructFromFormattedString(std::string_view formatted_string) {
+ std::array<u8, 0x10> uuid;
+
+ size_t i = 0;
+
+ // Process the first 8 characters.
+ const auto* str = formatted_string.data();
+
+ for (; i < 4; ++i) {
+ uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
+ uuid[i] |= HexCharToByte(*(str++));
+ }
+
+ // Process the next 4 characters.
+ ++str;
+
+ for (; i < 6; ++i) {
+ uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
+ uuid[i] |= HexCharToByte(*(str++));
+ }
+
+ // Process the next 4 characters.
+ ++str;
+
+ for (; i < 8; ++i) {
+ uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
+ uuid[i] |= HexCharToByte(*(str++));
+ }
+
+ // Process the next 4 characters.
+ ++str;
+
+ for (; i < 10; ++i) {
+ uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
+ uuid[i] |= HexCharToByte(*(str++));
+ }
+
+ // Process the last 12 characters.
+ ++str;
+
+ for (; i < 16; ++i) {
+ uuid[i] = static_cast<u8>((HexCharToByte(*(str++)) << 4));
+ uuid[i] |= HexCharToByte(*(str++));
+ }
+
+ return uuid;
+}
+
+std::array<u8, 0x10> ConstructUUID(std::string_view uuid_string) {
+ const auto length = uuid_string.length();
+
+ if (length == 0) {
+ return {};
+ }
+
+ // Check if the input string contains 32 hexadecimal characters.
+ if (length == RawStringSize) {
+ return ConstructFromRawString(uuid_string);
+ }
+
+ // Check if the input string has the length of a RFC 4122 formatted UUID string.
+ if (length == FormattedStringSize) {
+ return ConstructFromFormattedString(uuid_string);
+ }
+
+ ASSERT_MSG(false, "UUID string has an invalid length of {} characters!", length);
+
+ return {};
+}
+
+} // Anonymous namespace
+
+NewUUID::NewUUID(std::string_view uuid_string) : uuid{ConstructUUID(uuid_string)} {}
+
+std::string NewUUID::RawString() const {
+ return fmt::format("{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}"
+ "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
+ uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],
+ uuid[15]);
+}
+
+std::string NewUUID::FormattedString() const {
+ return fmt::format("{:02x}{:02x}{:02x}{:02x}"
+ "-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-"
+ "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
+ uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],
+ uuid[15]);
+}
+
+size_t NewUUID::Hash() const noexcept {
+ u64 hash;
+ u64 temp;
+
+ std::memcpy(&hash, uuid.data(), sizeof(u64));
+ std::memcpy(&temp, uuid.data() + 8, sizeof(u64));
+
+ return hash ^ std::rotl(temp, 1);
+}
+
+NewUUID NewUUID::MakeRandom() {
+ std::random_device device;
+
+ return MakeRandomWithSeed(device());
+}
+
+NewUUID NewUUID::MakeRandomWithSeed(u32 seed) {
+ // Create and initialize our RNG.
+ TinyMT rng;
+ rng.Initialize(seed);
+
+ NewUUID uuid;
+
+ // Populate the UUID with random bytes.
+ rng.GenerateRandomBytes(uuid.uuid.data(), sizeof(NewUUID));
+
+ return uuid;
+}
+
+NewUUID NewUUID::MakeRandomRFC4122V4() {
+ auto uuid = MakeRandom();
+
+ // According to Proposed Standard RFC 4122 Section 4.4, we must:
+
+ // 1. Set the two most significant bits (bits 6 and 7) of the
+ // clock_seq_hi_and_reserved to zero and one, respectively.
+ uuid.uuid[8] = 0x80 | (uuid.uuid[8] & 0x3F);
+
+ // 2. Set the four most significant bits (bits 12 through 15) of the
+ // time_hi_and_version field to the 4-bit version number from Section 4.1.3.
+ uuid.uuid[6] = 0x40 | (uuid.uuid[6] & 0xF);
+
+ return uuid;
+}
+
+} // namespace Common