summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/new_uuid.cpp182
-rw-r--r--src/common/new_uuid.h138
3 files changed, 322 insertions, 0 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index adf70eb8b..3dd460191 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -99,6 +99,8 @@ add_library(common STATIC
microprofile.cpp
microprofile.h
microprofileui.h
+ new_uuid.cpp
+ new_uuid.h
nvidia_flags.cpp
nvidia_flags.h
page_table.cpp
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
diff --git a/src/common/new_uuid.h b/src/common/new_uuid.h
new file mode 100644
index 000000000..bd4468ad2
--- /dev/null
+++ b/src/common/new_uuid.h
@@ -0,0 +1,138 @@
+// Copyright 2022 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <functional>
+#include <string>
+#include <string_view>
+
+#include "common/common_types.h"
+
+namespace Common {
+
+struct NewUUID {
+ std::array<u8, 0x10> uuid{};
+
+ /// Constructs an invalid UUID.
+ constexpr NewUUID() = default;
+
+ /// Constructs a UUID from a reference to a 128 bit array.
+ constexpr explicit NewUUID(const std::array<u8, 16>& uuid_) : uuid{uuid_} {}
+
+ /**
+ * Constructs a UUID from either:
+ * 1. A 32 hexadecimal character string representing the bytes of the UUID
+ * 2. A RFC 4122 formatted UUID string, in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+ *
+ * The input string may contain uppercase or lowercase characters, but they must:
+ * 1. Contain valid hexadecimal characters (0-9, a-f, A-F)
+ * 2. Not contain the "0x" hexadecimal prefix
+ *
+ * Should the input string not meet the above requirements,
+ * an assert will be triggered and an invalid UUID is set instead.
+ */
+ explicit NewUUID(std::string_view uuid_string);
+
+ ~NewUUID() = default;
+
+ constexpr NewUUID(const NewUUID&) noexcept = default;
+ constexpr NewUUID(NewUUID&&) noexcept = default;
+
+ constexpr NewUUID& operator=(const NewUUID&) noexcept = default;
+ constexpr NewUUID& operator=(NewUUID&&) noexcept = default;
+
+ /**
+ * Returns whether the stored UUID is valid or not.
+ *
+ * @returns True if the stored UUID is valid, false otherwise.
+ */
+ constexpr bool IsValid() const {
+ return uuid != std::array<u8, 0x10>{};
+ }
+
+ /**
+ * Returns whether the stored UUID is invalid or not.
+ *
+ * @returns True if the stored UUID is invalid, false otherwise.
+ */
+ constexpr bool IsInvalid() const {
+ return !IsValid();
+ }
+
+ /**
+ * Returns a 32 hexadecimal character string representing the bytes of the UUID.
+ *
+ * @returns A 32 hexadecimal character string of the UUID.
+ */
+ std::string RawString() const;
+
+ /**
+ * Returns a RFC 4122 formatted UUID string in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
+ *
+ * @returns A RFC 4122 formatted UUID string.
+ */
+ std::string FormattedString() const;
+
+ /**
+ * Returns a 64-bit hash of the UUID for use in hash table data structures.
+ *
+ * @returns A 64-bit hash of the UUID.
+ */
+ size_t Hash() const noexcept;
+
+ /**
+ * Creates a default UUID "yuzu Default UID".
+ *
+ * @returns A UUID with its bytes set to the ASCII values of "yuzu Default UID".
+ */
+ static constexpr NewUUID MakeDefault() {
+ return NewUUID{
+ {'y', 'u', 'z', 'u', ' ', 'D', 'e', 'f', 'a', 'u', 'l', 't', ' ', 'U', 'I', 'D'},
+ };
+ }
+
+ /**
+ * Creates a random UUID.
+ *
+ * @returns A random UUID.
+ */
+ static NewUUID MakeRandom();
+
+ /**
+ * Creates a random UUID with a seed.
+ *
+ * @param seed A seed to initialize the Mersenne-Twister RNG
+ *
+ * @returns A random UUID.
+ */
+ static NewUUID MakeRandomWithSeed(u32 seed);
+
+ /**
+ * Creates a random UUID. The generated UUID is RFC 4122 Version 4 compliant.
+ *
+ * @returns A random UUID that is RFC 4122 Version 4 compliant.
+ */
+ static NewUUID MakeRandomRFC4122V4();
+
+ friend constexpr bool operator==(const NewUUID& lhs, const NewUUID& rhs) = default;
+};
+static_assert(sizeof(NewUUID) == 0x10, "UUID has incorrect size.");
+
+/// An invalid UUID. This UUID has all its bytes set to 0.
+constexpr NewUUID InvalidUUID = {};
+
+} // namespace Common
+
+namespace std {
+
+template <>
+struct hash<Common::NewUUID> {
+ size_t operator()(const Common::NewUUID& uuid) const noexcept {
+ return uuid.Hash();
+ }
+};
+
+} // namespace std