Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #include "eid.h"
23 :
24 : #include <string>
25 : #include <random>
26 :
27 : #include "global/log.h"
28 :
29 : using namespace mu::engraving;
30 :
31 : static constexpr char SEPARATOR = '_';
32 :
33 213150 : static char* toBase64Chars(char* const first, char* const last, uint64_t n)
34 : {
35 : static constexpr char CHARS[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
36 :
37 213150 : IF_ASSERT_FAILED(static_cast<size_t>(last - first) >= EID::MAX_UINT64_BASE64_SIZE) {
38 0 : return first;
39 : }
40 :
41 213150 : char* it = first;
42 : do {
43 409484 : *it++ = CHARS[n % 64];
44 409484 : n = n / 64;
45 409484 : } while (n != 0);
46 :
47 213150 : return it;
48 : }
49 :
50 443885 : static constexpr uint64_t charToInt(char c)
51 : {
52 443885 : switch (c) {
53 5887 : case 'A': return 0;
54 20154 : case 'B': return 1;
55 14160 : case 'C': return 2;
56 13926 : case 'D': return 3;
57 10972 : case 'E': return 4;
58 8110 : case 'F': return 5;
59 8214 : case 'G': return 6;
60 8564 : case 'H': return 7;
61 8576 : case 'I': return 8;
62 8283 : case 'J': return 9;
63 7984 : case 'K': return 10;
64 8132 : case 'L': return 11;
65 8158 : case 'M': return 12;
66 8076 : case 'N': return 13;
67 8331 : case 'O': return 14;
68 8671 : case 'P': return 15;
69 6673 : case 'Q': return 16;
70 6139 : case 'R': return 17;
71 5668 : case 'S': return 18;
72 6022 : case 'T': return 19;
73 6361 : case 'U': return 20;
74 6377 : case 'V': return 21;
75 5914 : case 'W': return 22;
76 6047 : case 'X': return 23;
77 6131 : case 'Y': return 24;
78 5906 : case 'Z': return 25;
79 5732 : case 'a': return 26;
80 5886 : case 'b': return 27;
81 5807 : case 'c': return 28;
82 6249 : case 'd': return 29;
83 5967 : case 'e': return 30;
84 5863 : case 'f': return 31;
85 6148 : case 'g': return 32;
86 5826 : case 'h': return 33;
87 6021 : case 'i': return 34;
88 5914 : case 'j': return 35;
89 5971 : case 'k': return 36;
90 5887 : case 'l': return 37;
91 5731 : case 'm': return 38;
92 6178 : case 'n': return 39;
93 6365 : case 'o': return 40;
94 5954 : case 'p': return 41;
95 5866 : case 'q': return 42;
96 5937 : case 'r': return 43;
97 5885 : case 's': return 44;
98 5831 : case 't': return 45;
99 5830 : case 'u': return 46;
100 5689 : case 'v': return 47;
101 6029 : case 'w': return 48;
102 5914 : case 'x': return 49;
103 5879 : case 'y': return 50;
104 6081 : case 'z': return 51;
105 6093 : case '0': return 52;
106 5952 : case '1': return 53;
107 5832 : case '2': return 54;
108 6149 : case '3': return 55;
109 6180 : case '4': return 56;
110 5969 : case '5': return 57;
111 6047 : case '6': return 58;
112 5623 : case '7': return 59;
113 6268 : case '8': return 60;
114 5698 : case '9': return 61;
115 6012 : case '+': return 62;
116 6186 : case '/': return 63;
117 0 : default:
118 0 : UNREACHABLE;
119 : return uint64_t(-1);
120 : }
121 : }
122 :
123 75730 : static uint64_t base64StrToInt64(const std::string& s)
124 : {
125 75730 : uint64_t result = 0;
126 :
127 519615 : for (auto iter = s.rbegin(); iter != s.rend(); ++iter) {
128 443885 : result = result << 6;
129 443885 : result |= charToInt(*iter);
130 : }
131 :
132 75730 : return result;
133 : }
134 :
135 106575 : char* EID::toChars(char* const first, char* const last) const
136 : {
137 106575 : IF_ASSERT_FAILED(static_cast<size_t>(last - first) >= MAX_STR_SIZE) {
138 0 : return first;
139 : }
140 :
141 106575 : char* it = toBase64Chars(first, last, m_first);
142 106575 : *it++ = SEPARATOR;
143 106575 : it = toBase64Chars(it, last, m_second);
144 :
145 106575 : return it;
146 : }
147 :
148 12537 : std::string EID::toStdString() const
149 : {
150 12537 : std::string base64Repr(MAX_STR_SIZE, char {});
151 12537 : const char* last = toChars(base64Repr.data(), base64Repr.data() + base64Repr.size());
152 12537 : base64Repr.resize(last - base64Repr.data());
153 :
154 12537 : return base64Repr;
155 0 : }
156 :
157 39455 : EID EID::fromStdString(const std::string& s)
158 : {
159 39455 : std::stringstream ss(s);
160 39455 : std::string str;
161 39455 : std::vector<std::string> strings;
162 :
163 116775 : while (std::getline(ss, str, SEPARATOR)) {
164 77320 : strings.push_back(str);
165 : }
166 :
167 39455 : if (strings.size() != 2) {
168 1590 : return EID::invalid();
169 : }
170 :
171 37865 : const std::string& first = strings[0];
172 37865 : const std::string& second = strings[1];
173 :
174 37865 : return EID(base64StrToInt64(first), base64StrToInt64(second));
175 39455 : }
176 :
177 39454 : EID EID::fromStdString(const std::string_view& s)
178 : {
179 78908 : return fromStdString(std::string(s));
180 : }
181 :
182 0 : EID EID::newUnique()
183 : {
184 0 : static std::random_device s_device;
185 0 : thread_local static std::mt19937_64 s_engine(s_device());
186 0 : thread_local static std::uniform_int_distribution<uint64_t> s_unifDist;
187 :
188 0 : return EID(s_unifDist(s_engine), s_unifDist(s_engine));
189 : }
190 :
191 : // FOR UNIT TESTING
192 : // EIDs are creates sequentially instead of randomly for test repeatability
193 :
194 70256 : EID EID::newUniqueTestMode(uint64_t& maxVal)
195 : {
196 70256 : ++maxVal;
197 70256 : return EID(maxVal, maxVal);
198 : }
199 :
200 102289 : void EID::updateMaxValTestMode(const EID& curEID, uint64_t& maxVal)
201 : {
202 102289 : maxVal = std::max(maxVal, curEID.m_first);
203 102289 : maxVal = std::max(maxVal, curEID.m_second);
204 102289 : }
|