Blender  V3.3
uuid.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "BLI_assert.h"
8 #include "BLI_uuid.h"
9 
10 #include <cstdio>
11 #include <cstring>
12 #include <ctime>
13 #include <random>
14 #include <sstream>
15 #include <string>
16 #include <tuple>
17 
18 /* Ensure the UUID struct doesn't have any padding, to be compatible with memcmp(). */
19 static_assert(sizeof(bUUID) == 16, "expect UUIDs to be 128 bit exactly");
20 
22 {
23  static std::mt19937_64 rng = []() {
24  std::mt19937_64 rng;
25 
26  /* Ensure the RNG really can output 64-bit values. */
27  static_assert(std::mt19937_64::min() == 0LL);
28  static_assert(std::mt19937_64::max() == 0xffffffffffffffffLL);
29 
30  struct timespec ts;
31 #ifdef __APPLE__
32  /* `timespec_get()` is only available on macOS 10.15+, so until that's the minimum version
33  * supported by Blender, use another function to get the timespec.
34  *
35  * `clock_gettime()` is only available on POSIX, so not on Windows; Linux uses the newer C++11
36  * function `timespec_get()` as well. */
37  clock_gettime(CLOCK_REALTIME, &ts);
38 #else
39  timespec_get(&ts, TIME_UTC);
40 #endif
41  /* XOR the nanosecond and second fields, just in case the clock only has seconds resolution. */
42  uint64_t seed = ts.tv_nsec;
43  seed ^= ts.tv_sec;
44  rng.seed(seed);
45 
46  return rng;
47  }();
48 
49  bUUID uuid;
50 
51  /* RFC4122 suggests setting certain bits to a fixed value, and then randomizing the remaining
52  * bits. The opposite is easier to implement, though, so that's what's done here. */
53 
54  /* Read two 64-bit numbers to randomize all 128 bits of the UUID. */
55  uint64_t *uuid_as_int64 = reinterpret_cast<uint64_t *>(&uuid);
56  uuid_as_int64[0] = rng();
57  uuid_as_int64[1] = rng();
58 
59  /* Set the most significant four bits to 0b0100 to indicate version 4 (random UUID). */
60  uuid.time_hi_and_version &= ~0xF000;
61  uuid.time_hi_and_version |= 0x4000;
62 
63  /* Set the most significant two bits to 0b10 to indicate compatibility with RFC4122. */
64  uuid.clock_seq_hi_and_reserved &= ~0x40;
65  uuid.clock_seq_hi_and_reserved |= 0x80;
66 
67  return uuid;
68 }
69 
71 {
72  const bUUID nil = {0, 0, 0, 0, 0, {0}};
73  return nil;
74 }
75 
77 {
78  return BLI_uuid_equal(BLI_uuid_nil(), uuid);
79 }
80 
81 bool BLI_uuid_equal(const bUUID uuid1, const bUUID uuid2)
82 {
83  return std::memcmp(&uuid1, &uuid2, sizeof(uuid1)) == 0;
84 }
85 
86 void BLI_uuid_format(char *buffer, const bUUID uuid)
87 {
88  std::sprintf(buffer,
89  "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
90  uuid.time_low,
91  uuid.time_mid,
94  uuid.clock_seq_low,
95  uuid.node[0],
96  uuid.node[1],
97  uuid.node[2],
98  uuid.node[3],
99  uuid.node[4],
100  uuid.node[5]);
101 }
102 
103 bool BLI_uuid_parse_string(bUUID *uuid, const char *buffer)
104 {
105  const int fields_parsed_num = std::sscanf(
106  buffer,
107  "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
108  &uuid->time_low,
109  &uuid->time_mid,
110  &uuid->time_hi_and_version,
112  &uuid->clock_seq_low,
113  &uuid->node[0],
114  &uuid->node[1],
115  &uuid->node[2],
116  &uuid->node[3],
117  &uuid->node[4],
118  &uuid->node[5]);
119  return fields_parsed_num == 11;
120 }
121 
122 std::ostream &operator<<(std::ostream &stream, bUUID uuid)
123 {
124  std::string buffer(36, '\0');
125  BLI_uuid_format(buffer.data(), uuid);
126  stream << buffer;
127  return stream;
128 }
129 
130 namespace blender {
131 
132 bUUID::bUUID(const std::initializer_list<uint32_t> field_values)
133 {
134  BLI_assert_msg(field_values.size() == 11, "bUUID requires 5 regular fields + 6 `node` values");
135 
136  const auto *field_iter = field_values.begin();
137 
138  this->time_low = *field_iter++;
139  this->time_mid = static_cast<uint16_t>(*field_iter++);
140  this->time_hi_and_version = static_cast<uint16_t>(*field_iter++);
141  this->clock_seq_hi_and_reserved = static_cast<uint8_t>(*field_iter++);
142  this->clock_seq_low = static_cast<uint8_t>(*field_iter++);
143 
144  std::copy(field_iter, field_values.end(), this->node);
145 }
146 
147 bUUID::bUUID(const std::string &string_formatted_uuid)
148 {
149  const bool parsed_ok = BLI_uuid_parse_string(this, string_formatted_uuid.c_str());
150  if (!parsed_ok) {
151  std::stringstream ss;
152  ss << "invalid UUID string " << string_formatted_uuid;
153  throw std::runtime_error(ss.str());
154  }
155 }
156 
157 bUUID::bUUID(const ::bUUID &struct_uuid)
158 {
159  *(static_cast<::bUUID *>(this)) = struct_uuid;
160 }
161 
162 uint64_t bUUID::hash() const
163 {
164  /* Convert the struct into two 64-bit numbers, and XOR them to get the hash. */
165  const uint64_t *uuid_as_int64 = reinterpret_cast<const uint64_t *>(this);
166  return uuid_as_int64[0] ^ uuid_as_int64[1];
167 }
168 
169 bool operator==(const bUUID uuid1, const bUUID uuid2)
170 {
171  return BLI_uuid_equal(uuid1, uuid2);
172 }
173 
174 bool operator!=(const bUUID uuid1, const bUUID uuid2)
175 {
176  return !(uuid1 == uuid2);
177 }
178 
179 bool operator<(const bUUID uuid1, const bUUID uuid2)
180 {
181  auto simple_fields1 = std::tie(uuid1.time_low,
182  uuid1.time_mid,
183  uuid1.time_hi_and_version,
185  uuid1.clock_seq_low);
186  auto simple_fields2 = std::tie(uuid2.time_low,
187  uuid2.time_mid,
188  uuid2.time_hi_and_version,
190  uuid2.clock_seq_low);
191  if (simple_fields1 == simple_fields2) {
192  return std::memcmp(uuid1.node, uuid2.node, sizeof(uuid1.node)) < 0;
193  }
194  return simple_fields1 < simple_fields2;
195 }
196 
197 } // namespace blender
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
struct bUUID bUUID
Universally Unique Identifier according to RFC4122.
static unsigned long seed
Definition: btSoftBody.h:39
ccl_global float * buffer
constexpr bool operator!=(StringRef a, StringRef b)
constexpr bool operator==(StringRef a, StringRef b)
constexpr bool operator<(StringRef a, StringRef b)
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
#define hash
Definition: noise.c:153
#define min(a, b)
Definition: sort.c:35
unsigned short uint16_t
Definition: stdint.h:79
unsigned char uint8_t
Definition: stdint.h:78
unsigned __int64 uint64_t
Definition: stdint.h:90
Universally Unique Identifier according to RFC4122.
uint8_t clock_seq_hi_and_reserved
uint8_t clock_seq_low
uint16_t time_mid
uint32_t time_low
uint8_t node[6]
uint16_t time_hi_and_version
float max
void BLI_uuid_format(char *buffer, const bUUID uuid)
Definition: uuid.cc:86
bUUID BLI_uuid_nil()
Definition: uuid.cc:70
bool BLI_uuid_equal(const bUUID uuid1, const bUUID uuid2)
Definition: uuid.cc:81
bool BLI_uuid_parse_string(bUUID *uuid, const char *buffer)
Definition: uuid.cc:103
bool BLI_uuid_is_nil(bUUID uuid)
Definition: uuid.cc:76
bUUID BLI_uuid_generate_random()
Definition: uuid.cc:21
std::ostream & operator<<(std::ostream &stream, bUUID uuid)
Definition: uuid.cc:122