Line data Source code
1 :
2 : /* Copyright (c) 2011-2016, Stefan Eilemann <eile@eyescale.ch>
3 : *
4 : * This file is part of Servus <https://github.com/HBPVIS/Servus>
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 3.0 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "uint128_t.h"
21 : #include "md5/md5.hh"
22 :
23 : #include <mutex>
24 : #include <random>
25 :
26 : #include <cassert>
27 : #include <cstdlib> // for strtoull
28 : #include <cstring> // for strcmp
29 :
30 : #ifdef _MSC_VER
31 : #define strtoull _strtoui64
32 : #endif
33 :
34 : using ScopedLock = std::unique_lock<std::mutex>;
35 : namespace chrono = std::chrono;
36 :
37 : namespace servus
38 : {
39 4 : uint128_t& uint128_t::operator=(const std::string& from)
40 : {
41 4 : if (from.empty())
42 : {
43 1 : _high = 0;
44 1 : _low = 0;
45 1 : return *this;
46 : }
47 :
48 3 : char* next = 0;
49 3 : _high = ::strtoull(from.c_str(), &next, 16);
50 3 : assert(next != from.c_str());
51 :
52 3 : if (*next == '\0') // short representation, high was 0
53 : {
54 1 : _low = _high;
55 1 : _high = 0;
56 : }
57 : else
58 : {
59 2 : if (strncmp(next, "\\058" /* utf-8 ':' */, 4) == 0)
60 1 : next += 4;
61 : else
62 : {
63 : #ifndef NDEBUG
64 1 : if (*next != ':')
65 0 : std::cerr << from << ", " << next << std::endl;
66 : #endif
67 1 : assert(*next == ':');
68 1 : ++next;
69 : }
70 2 : _low = ::strtoull(next, 0, 16);
71 : }
72 3 : return *this;
73 : }
74 :
75 5 : uint128_t make_uint128(const char* string)
76 : {
77 5 : const md5::MD5 md5((unsigned char*)string);
78 5 : uint128_t value;
79 5 : md5.raw_digest(value.high(), value.low());
80 5 : return value;
81 : }
82 :
83 99983 : uint128_t make_UUID()
84 : {
85 99983 : uint128_t value;
86 299995 : while (value.high() == 0)
87 : {
88 99983 : static std::random_device device;
89 99983 : static std::mt19937_64 engine(device());
90 : static std::uniform_int_distribution<uint64_t> generator(
91 99983 : 0, std::numeric_limits<uint64_t>::max());
92 : #ifndef _MSC_VER
93 : // The static state is hidden to users, so the function is made
94 : // thread safe for robustness over performance.
95 : // Also, creating a new generator each call seems to increases the
96 : // chances of collissions up to a noticeable level.
97 :
98 : // http://stackoverflow.com/questions/14711263
99 : static std::mutex mutex;
100 199990 : ScopedLock lock(mutex);
101 : #endif
102 100007 : value.high() = generator(engine);
103 100007 : value.low() = generator(engine);
104 : }
105 100007 : return value;
106 : }
107 15 : }
|