1 /**
2 * Copyright 2021 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "async/uuid_base.h"
18 #include <memory.h>
19 #include <atomic>
20 #include <random>
21
22 namespace mindspore {
23 namespace uuids {
24 constexpr int DASH_POS0 = 4;
25 constexpr int DASH_POS1 = 6;
26 constexpr int DASH_POS2 = 8;
27 constexpr int DASH_POS3 = 10;
28 constexpr int SHIFT_BIT = 4;
29
BeginAddress() const30 const uint8_t *uuid::BeginAddress() const { return uuidData; }
31
EndAddress() const32 const uint8_t *uuid::EndAddress() const { return uuidData + UUID_SIZE; }
33
Size()34 std::size_t uuid::Size() { return UUID_SIZE; }
35
ToBytes(const uuid & u)36 std::string uuid::ToBytes(const uuid &u) {
37 MINDRT_ASSERT(sizeof(u) == UUID_SIZE);
38 return std::string(reinterpret_cast<const char *>(u.uuidData), sizeof(u.uuidData));
39 }
40
FromBytes(const std::string & s)41 Option<uuid> uuid::FromBytes(const std::string &s) {
42 if (s.size() != UUID_SIZE) {
43 return Option<uuid>(MindrtNone());
44 }
45 uuid u;
46 (void)memcpy(&u.uuidData, s.data(), s.size());
47 return Option<uuid>(u);
48 }
49
GetValue(char c)50 Option<unsigned char> uuid::GetValue(char c) {
51 static char const digitsBegin[] = "0123456789abcdefABCDEF";
52 static const size_t digitsLen = (sizeof(digitsBegin) / sizeof(char)) - 1;
53 static const char *const digitsEnd = digitsBegin + digitsLen;
54 static unsigned char const values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 10, 11, 12, 13, 14, 15};
55 size_t pos = std::find(digitsBegin, digitsEnd, c) - digitsBegin;
56 if (pos >= digitsLen) {
57 MS_LOG(ERROR) << "invalid char";
58 return Option<unsigned char>(MindrtNone());
59 }
60 return Option<unsigned char>(values[pos]);
61 }
62
FromString(const std::string & s)63 Option<uuid> uuid::FromString(const std::string &s) {
64 auto sBegin = s.begin();
65 if (sBegin == s.end()) {
66 return Option<uuid>(MindrtNone());
67 }
68 auto c = *sBegin;
69 bool hasOpenBrace = (c == '{');
70 bool hasDashes = false;
71 if (hasOpenBrace) {
72 ++sBegin;
73 }
74 uuid u;
75 for (size_t i = 0; sBegin != s.end(); ++i) {
76 c = *(sBegin++);
77 if ((i == DASH_POS0) && (c == '-')) {
78 hasDashes = true;
79 c = *(sBegin++);
80 } else if ((i == DASH_POS1 || i == DASH_POS2 || i == DASH_POS3) && (hasDashes == true)) {
81 if (c == '-' && sBegin != s.end()) {
82 c = *(sBegin++);
83 } else {
84 MS_LOG(ERROR) << "str invalid";
85 return Option<uuid>(MindrtNone());
86 }
87 }
88 Option<unsigned char> oc1 = GetValue(c);
89 if (oc1.IsNone()) {
90 return Option<uuid>(MindrtNone());
91 }
92 u.uuidData[i] = oc1.Get();
93 if (sBegin != s.end()) {
94 c = *(sBegin++);
95 }
96 u.uuidData[i] <<= SHIFT_BIT;
97 Option<unsigned char> oc2 = GetValue(c);
98 if (oc2.IsNone()) {
99 return Option<uuid>(MindrtNone());
100 }
101 u.uuidData[i] |= oc2.Get();
102 }
103 if ((hasOpenBrace && (c != '}')) || (sBegin != s.end())) {
104 MS_LOG(ERROR) << "No } end or leng invalid";
105 return Option<uuid>(MindrtNone());
106 }
107 return Option<uuid>(u);
108 }
109
110 // To check whether uuid looks like 0000000-000-000-000-000000000000000
IsNilUUID() const111 bool uuid::IsNilUUID() const {
112 for (std::size_t i = 0; i < Size(); i++) {
113 if (uuidData[i]) {
114 return false;
115 }
116 }
117 return true;
118 }
119
Get() const120 const uint8_t *uuid::Get() const { return uuidData; }
121
BeginAddress()122 uint8_t *uuid::BeginAddress() { return uuidData; }
123
EndAddress()124 uint8_t *uuid::EndAddress() { return uuidData + UUID_SIZE; }
125
GenerateRandomUuid()126 uuid RandomBasedGenerator::GenerateRandomUuid() {
127 const int VARIANT_BIT_OFFSET = 8;
128 const int VERSION_BIT_OFFSET = 6;
129 const int RIGHT_SHIFT_BITS = 8;
130 uuid tmpUUID;
131
132 // This is used to generate a random number as a random seed
133 std::random_device rd;
134
135 // Mersenne Twister algorithm, as a generator engine,
136 // which is used to generate a random number
137 std::mt19937 gen(rd());
138
139 // We use uniform distribution
140 std::uniform_int_distribution<uint64_t> distribution((std::numeric_limits<uint64_t>::min)(),
141 (std::numeric_limits<uint64_t>::max)());
142 uint64_t randomValue = distribution(gen);
143
144 unsigned int i = 0;
145 for (uint8_t *it = tmpUUID.BeginAddress(); it != tmpUUID.EndAddress(); ++it, ++i) {
146 if (i == sizeof(uint64_t)) {
147 randomValue = distribution(gen);
148 i = 0;
149 }
150 *it = static_cast<uint8_t>((randomValue >> (i * RIGHT_SHIFT_BITS)) & 0xFF);
151 }
152
153 // use atomic ++ to replace random
154 static std::atomic<uint64_t> ul(1);
155 uint64_t lCount = ul.fetch_add(1);
156 uint64_t offSet = distribution(gen) % RIGHT_SHIFT_BITS;
157 (void)memcpy(tmpUUID.BeginAddress() + offSet, &lCount, sizeof(lCount));
158
159 // set the variant
160 *(tmpUUID.BeginAddress() + VARIANT_BIT_OFFSET) &= 0xBF;
161 *(tmpUUID.BeginAddress() + VARIANT_BIT_OFFSET) |= 0x80;
162
163 // set the uuid generation version
164 *(tmpUUID.BeginAddress() + VERSION_BIT_OFFSET) &= 0x4F;
165 *(tmpUUID.BeginAddress() + VERSION_BIT_OFFSET) |= 0x40;
166
167 return tmpUUID;
168 }
169 } // namespace uuids
170 } // namespace mindspore
171