TurtleBrains  0.3.5
High quality, portable, C++ framework for rapid 2D game development.
tb_uuid.hpp
1 
8 #ifndef TurtleBrains_uuid_hpp
9 #define TurtleBrains_uuid_hpp
10 
11 
12 // @note 2023-11-08: While uuid doesn't itself need platform related stuff, the sole dependency is using platform stuff.
13 // We are including this file to get "ahead" of the curve and include the platform stuff for the sole dependency in
14 // order to not have issues with Windows defining min/max or other similar issues.
15 #include <turtle_brains/core/tb_platform.hpp>
16 #include <turtle_brains/core/tb_string.hpp>
17 #include <turtle_brains/core/tb_types.hpp>
18 
19 #include <sole/sole.hpp>
20 
21 #include <array>
22 
23 namespace TurtleBrains::Core
24 {
32  template<typename Type> class TypedUUID
33  {
34  public:
35 
36  // UUID v0, pro: unique; cons: MAC revealed, pid revealed, predictable.
37  static TypedUUID Generate0(void) { TypedUUID value; value.mUUID = sole::uuid0(); return value; }
38 
39  // UUID v1, pro: unique; cons: MAC revealed, predictable.
40  static TypedUUID Generate1(void) { TypedUUID value; value.mUUID = sole::uuid1(); return value; }
41 
42  // UUID v4, pros: anonymous, fast; con: uuids "can clash"
43  static TypedUUID Generate4(void) { TypedUUID value; value.mUUID = sole::uuid4(); return value; }
44 
45  static TypedUUID Invalid(void) { return TypedUUID(0, 0); }
46 
47  static TypedUUID FromRawData(const std::array<tbCore::byte, 16>& uuidData) { return TypedUUID(uuidData); }
48 
49  TypedUUID(void) :
50  mUUID(sole::rebuild(0, 0))
51  {
52  }
53 
54  explicit TypedUUID(const String& uuidString) :
55  mUUID(sole::rebuild(uuidString))
56  {
57  }
58 
59  explicit TypedUUID(const tbCore::uint64& first64, const tbCore::uint64& last64) :
60  mUUID(sole::rebuild(first64, last64))
61  {
62  }
63 
64  explicit TypedUUID(const std::array<tbCore::byte, 16>& uuidData) :
65  mUUID(sole::rebuild(0, 0))
66  {
67  tbCore::uint64 first = 0;
68  tbCore::uint64 last = 0;
69  for (size_t index = 0; index < 8; ++index)
70  {
71  reinterpret_cast<tbCore::byte*>(&first)[index] = uuidData[index];
72  reinterpret_cast<tbCore::byte*>(&last)[index] = uuidData[index + 8];
73  }
74 
75  mUUID = sole::rebuild(first, last);
76  }
77 
78  TypedUUID(const TypedUUID<Type>& other) :
79  mUUID(other.mUUID)
80  {
81  }
82 
83  TypedUUID(TypedUUID<Type>&& other) noexcept :
84  mUUID(sole::rebuild(0, 0))
85  {
86  std::swap(mUUID, other.mUUID);
87  }
88 
89  ~TypedUUID(void)
90  {
91  }
92 
93  inline tbCore::String String(void) const { return tbCore::String(mUUID.str()); }
94 
95  inline std::array<tbCore::byte, 16> RawData(void) const
96  {
97  std::array<tbCore::byte, 16> data;
98  for (size_t index = 0; index < 8; ++index)
99  {
100  data[index] = reinterpret_cast<const tbCore::byte*>(&mUUID.ab)[index];
101  data[index + 8] = reinterpret_cast<const tbCore::byte*>(&mUUID.cd)[index];
102  }
103 
104  return data;
105  }
106 
107  inline TypedUUID& operator=(const TypedUUID& other)
108  {
109  mUUID = other.mUUID;
110  return *this;
111  }
112 
113  inline TypedUUID& operator=(TypedUUID&& other) noexcept
114  {
115  std::swap(mUUID, other.mUUID);
116  return *this;
117  }
118 
119  inline bool operator==(const TypedUUID& other) const { return mUUID == other.mUUID; }
120  inline bool operator!=(const TypedUUID& other) const { return mUUID != other.mUUID; }
121  inline bool operator<(const TypedUUID& other) const { return mUUID < other.mUUID; }
122 
123  template<typename ToType> friend class TypedUUID;
124  template<typename ToType> explicit operator TypedUUID<ToType>() const
125  {
126  TypedUUID<ToType> value;
127  value.mUUID = mUUID;
128  return value;
129  }
130 
131  friend inline std::ostream& operator<<(std::ostream& output, const TypedUUID<Type>& object)
132  {
133  return output << object.String();
134  }
135 
136  friend std::istream& operator>>(std::istream& input, TypedUUID<Type>& data)
137  {
138  tbCore::String temporaryString;
139  input >> temporaryString;
140  data.mUUID = sole::rebuild(temporaryString);
141  return input;
142  }
143 
144  private:
145  // @note: 2023-12-17: I attempted to add a debug string to make debugging support much better, since it is
146  // very easy to confuse the String vs the UUID when debugging, the two values will never match and it makes
147  // things painful, forcing dev to use temporary code to grab the string. However, adding that string here
148  // changes the size of the UUID object which is saved/loaded to binary files as POD, and adding a string
149  // breaks that...
150  sole::uuid mUUID;
151  };
152 
153  enum class DefaultKeyType {};
154  using uuid = TypedUUID<DefaultKeyType>;
155 
156 }; /* namespace TurtleBrains::Core */
157 
158 namespace tbCore = TurtleBrains::Core;
159 
160 //--------------------------------------------------------------------------------------------------------------------//
161 
162 // 2025-11-09: This fixes an issue where std::unordered_map<TypedUUID<Type>> would complain about the std::hash not being
163 // defined/usable. It does have to be in global space to work.
164 template<typename Type> struct std::hash<tbCore::TypedUUID<Type>>
165 {
166  std::size_t operator()(const tbCore::TypedUUID<Type>& uuid) const noexcept
167  {
168  return std::hash<std::string>{}(TurtleBrains::Core::ToString(uuid));
169  }
170 };
171 
172 #endif /* TurtleBrains_uuid_hpp */
Definition: tb_uuid.hpp:33
Contains core functionality for each component of the API.
Definition: tb_debug_logger.hpp:125
String ToString(const Type &object)
Definition: tb_string.hpp:317
std::string String
Definition: tb_string.hpp:302
std::uint8_t byte
Unsigned integer with a size of 8 bits. Supports values from 0 to 255.
Definition: tb_types.hpp:23
std::uint64_t uint64
Unsigned integer with a size of 64 bits, Supports values from 0 to (2^64 - 1).
Definition: tb_types.hpp:29