1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
// Copyright Epic Games, Inc. All Rights Reserved.
#include <zencore/uid.h>
#include <zencore/endian.h>
#include <zencore/string.h>
#include <zencore/testing.h>
#include <atomic>
#include <bit>
#include <chrono>
#include <random>
#include <set>
#include <unordered_map>
namespace zen {
//////////////////////////////////////////////////////////////////////////
namespace detail {
static bool OidInitialised;
static uint32_t RunId;
static std::atomic_uint32_t Serial;
} // namespace detail
//////////////////////////////////////////////////////////////////////////
const Oid Oid::Zero = {{0u, 0u, 0u}};
const Oid Oid::Max = {{~0u, ~0u, ~0u}};
void
Oid::Initialize()
{
if (!detail::OidInitialised)
{
std::random_device Rng;
detail::RunId = Rng();
detail::Serial = Rng();
detail::OidInitialised = true;
}
}
const Oid&
Oid::Generate()
{
if (!detail::OidInitialised)
{
Oid::Initialize();
}
const uint64_t kOffset = 1'609'459'200; // Seconds from 1970 -> 2021
const uint64_t Time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) - kOffset;
OidBits[0] = ToNetworkOrder(uint32_t(Time));
OidBits[1] = ToNetworkOrder(uint32_t(++detail::Serial));
OidBits[2] = detail::RunId;
return *this;
}
Oid
Oid::NewOid()
{
return Oid().Generate();
}
Oid
Oid::FromHexString(const std::string_view String)
{
ZEN_ASSERT(String.size() == 2 * sizeof(Oid::OidBits));
Oid Id;
if (ParseHexBytes(String.data(), String.size(), reinterpret_cast<uint8_t*>(Id.OidBits)))
{
return Id;
}
else
{
return Oid::Zero;
}
}
Oid
Oid::FromMemory(const void* Ptr)
{
Oid Id;
memcpy(Id.OidBits, Ptr, sizeof Id);
return Id;
}
void
Oid::ToString(char OutString[StringLength]) const
{
ToHexBytes(reinterpret_cast<const uint8_t*>(OidBits), sizeof(Oid::OidBits), OutString);
OutString[StringLength] = '\0';
}
StringBuilderBase&
Oid::ToString(StringBuilderBase& OutString) const
{
String_t Str;
ToHexBytes(reinterpret_cast<const uint8_t*>(OidBits), sizeof(Oid::OidBits), Str);
OutString.AppendRange(Str, &Str[StringLength]);
return OutString;
}
#if ZEN_WITH_TESTS
TEST_CASE("Oid")
{
SUBCASE("Basic")
{
Oid id1 = Oid::NewOid();
ZEN_UNUSED(id1);
std::vector<Oid> ids;
std::set<Oid> idset;
std::unordered_map<Oid, int, Oid::Hasher> idmap;
const int Count = 1000;
for (int i = 0; i < Count; ++i)
{
Oid id;
id.Generate();
ids.emplace_back(id);
idset.insert(id);
idmap.insert({id, i});
}
CHECK(ids.size() == Count);
CHECK(idset.size() == Count); // All ids should be unique
CHECK(idmap.size() == Count); // Ditto
}
}
void
uid_forcelink()
{
}
#endif
} // namespace zen
|