• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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