Line data Source code
1 : /* Copyright (c) 2010-2017, Cedric Stalder <cedric.stalder@gmail.com>
2 : * Stefan Eilemann <eile@eyescale.ch>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : *
5 : * This file is part of Servus <https://github.com/HBPVIS/Servus>
6 : *
7 : * This library is free software; you can redistribute it and/or modify it under
8 : * the terms of the GNU Lesser General Public License version 3.0 as published
9 : * by the Free Software Foundation.
10 : *
11 : * This library is distributed in the hope that it will be useful, but WITHOUT
12 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 : * details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public License
17 : * along with this library; if not, write to the Free Software Foundation, Inc.,
18 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 : */
20 :
21 : #ifndef SERVUS_UINT128_H
22 : #define SERVUS_UINT128_H
23 :
24 : #include <servus/api.h>
25 : #include <servus/types.h>
26 :
27 : #include <sstream>
28 : #ifdef _MSC_VER
29 : // Don't include <servus/types.h> to be minimally intrusive for apps
30 : // using uint128_t
31 : #include <basetsd.h>
32 : typedef UINT64 uint64_t;
33 : #define snprintf _snprintf
34 : #else
35 : #include <stdint.h>
36 : #endif
37 :
38 : namespace servus
39 : {
40 : class uint128_t;
41 : std::ostream& operator<<(std::ostream& os, const uint128_t& id);
42 :
43 : /**
44 : * A base type for 128 bit unsigned integer values.
45 : *
46 : * Example: @include tests/uint128_t.cpp
47 : */
48 : class uint128_t
49 : {
50 : public:
51 : /**
52 : * Construct a new 128 bit integer with a default value.
53 : */
54 99993 : explicit uint128_t(const unsigned long long low_ = 0)
55 99993 : : _high(0)
56 99993 : , _low(low_)
57 : {
58 99993 : }
59 :
60 : /**
61 : * Construct a new 128 bit integer with a default value.
62 : */
63 : explicit uint128_t(const unsigned long low_)
64 : : _high(0)
65 : , _low(low_)
66 : {
67 : }
68 :
69 : /**
70 : * Construct a new 128 bit integer with a default value.
71 : */
72 1 : explicit uint128_t(const int low_)
73 1 : : _high(0)
74 1 : , _low(low_)
75 : {
76 1 : }
77 :
78 : /**
79 : * Construct a new 128 bit integer with default values.
80 : **/
81 6 : uint128_t(const uint64_t high_, const uint64_t low_)
82 6 : : _high(high_)
83 6 : , _low(low_)
84 : {
85 6 : }
86 :
87 : /**
88 : * Construct a new 128 bit integer from a string representation.
89 : **/
90 : explicit uint128_t(const std::string& string)
91 : : _high(0)
92 : , _low(0)
93 : {
94 : *this = string;
95 : }
96 :
97 : /**
98 : * @return true if the uint128_t is a generated universally unique
99 : * identifier.
100 : */
101 100003 : bool isUUID() const { return high() != 0; }
102 : /** Assign another 128 bit value. */
103 11 : uint128_t& operator=(const servus::uint128_t& rhs)
104 : {
105 11 : _high = rhs._high;
106 11 : _low = rhs._low;
107 11 : return *this;
108 : }
109 :
110 : /** Assign another 64 bit value. */
111 : uint128_t& operator=(const uint64_t rhs)
112 : {
113 : _high = 0;
114 : _low = rhs;
115 : return *this;
116 : }
117 :
118 : /** Assign an integer value. */
119 : uint128_t& operator=(const int rhs)
120 : {
121 : _high = 0;
122 : _low = rhs;
123 : return *this;
124 : }
125 :
126 : /** Assign an 128 bit value from a std::string. */
127 : SERVUS_API uint128_t& operator=(const std::string& from);
128 :
129 : /**
130 : * @return true if the values are equal, false if not.
131 : **/
132 10 : bool operator==(const servus::uint128_t& rhs) const
133 : {
134 10 : return _high == rhs._high && _low == rhs._low;
135 : }
136 :
137 : /**
138 : * @return true if the values are different, false otherwise.
139 : **/
140 5 : bool operator!=(const servus::uint128_t& rhs) const
141 : {
142 5 : return _high != rhs._high || _low != rhs._low;
143 : }
144 :
145 : /**
146 : * @return true if the values are equal, false otherwise.
147 : **/
148 : bool operator==(const unsigned long long& low_) const
149 : {
150 : return *this == uint128_t(low_);
151 : }
152 :
153 : /**
154 : * @return true if the values are different, false otherwise.
155 : **/
156 : bool operator!=(const unsigned long long& low_) const
157 : {
158 : return *this != uint128_t(low_);
159 : }
160 :
161 : /**
162 : * @return true if this value is smaller than the RHS value.
163 : **/
164 : bool operator<(const servus::uint128_t& rhs) const
165 : {
166 : if (_high < rhs._high)
167 : return true;
168 : if (_high > rhs._high)
169 : return false;
170 : return _low < rhs._low;
171 : }
172 :
173 : /**
174 : * @return true if this value is bigger than the rhs value.
175 : */
176 : bool operator>(const servus::uint128_t& rhs) const
177 : {
178 : if (_high > rhs._high)
179 : return true;
180 : if (_high < rhs._high)
181 : return false;
182 : return _low > rhs._low;
183 : }
184 :
185 : /**
186 : * @return true if this value is smaller or equal than the
187 : * RHS value.
188 : */
189 : bool operator<=(const servus::uint128_t& rhs) const
190 : {
191 : if (_high < rhs._high)
192 : return true;
193 : if (_high > rhs._high)
194 : return false;
195 : return _low <= rhs._low;
196 : }
197 :
198 : /**
199 : * @return true if this value is smaller or equal than the
200 : * RHS value.
201 : */
202 : bool operator>=(const servus::uint128_t& rhs) const
203 : {
204 : if (_high > rhs._high)
205 : return true;
206 : if (_high < rhs._high)
207 : return false;
208 : return _low >= rhs._low;
209 : }
210 :
211 : /** Increment the value. */
212 2 : uint128_t& operator++()
213 : {
214 2 : ++_low;
215 2 : if (!_low)
216 1 : ++_high;
217 :
218 2 : return *this;
219 : }
220 :
221 : /** Decrement the value. */
222 2 : uint128_t& operator--()
223 : {
224 2 : if (!_low)
225 1 : --_high;
226 2 : --_low;
227 2 : return *this;
228 : }
229 :
230 : /** Add value and return the new value. */
231 : uint128_t& operator+=(const servus::uint128_t& rhs)
232 : {
233 : const uint64_t oldLow = _low;
234 : _low += rhs._low;
235 : if (_low < oldLow) // overflow
236 : _high += rhs._high + 1;
237 : else
238 : _high += rhs._high;
239 : return *this;
240 : }
241 :
242 : /** @return the reference to the lower 64 bits of this 128 bit value. */
243 199986 : const uint64_t& low() const { return _low; }
244 : /** @return the reference to the high 64 bits of this 128 bit value. */
245 299829 : const uint64_t& high() const { return _high; }
246 : /** @return the reference to the lower 64 bits of this 128 bit value. */
247 100035 : uint64_t& low() { return _low; }
248 : /** @return the reference to the high 64 bits of this 128 bit value. */
249 299884 : uint64_t& high() { return _high; }
250 : /** @return a short, but not necessarily unique, string of the value. */
251 : std::string getShortString() const
252 : {
253 : std::stringstream stream;
254 : stream << std::hex << _high << _low;
255 : const std::string str = stream.str();
256 : return str.substr(0, 3) + ".." +
257 : str.substr(str.length() - 3, std::string::npos);
258 : }
259 :
260 : /** @return the full string representation of the value. */
261 3 : std::string getString() const
262 : {
263 : // OPT: snprintf is faster than using std::stringstream
264 : char buffer[34] /* 2 x 16 bytes + : + \0 */;
265 3 : snprintf(buffer, 34, "%llx:%llx", ull_t(high()), ull_t(low()));
266 3 : return std::string(buffer);
267 : }
268 :
269 : /** Serialize this object to a boost archive. */
270 : template <class Archive>
271 : void serialize(Archive& ar, const unsigned int /*version*/)
272 : {
273 : ar& low();
274 : ar& high();
275 : }
276 :
277 : private:
278 : uint64_t _high;
279 : uint64_t _low;
280 : };
281 :
282 : /** ostream operator for 128 bit unsigned integers. */
283 2 : inline std::ostream& operator<<(std::ostream& os, const uint128_t& id)
284 : {
285 2 : if (id.high() == 0)
286 1 : os << std::hex << id.low() << std::dec;
287 : else
288 1 : os << std::hex << id.high() << ':' << id.low() << std::dec;
289 2 : return os;
290 : }
291 :
292 : /** istream operator for 128 bit unsigned integers. */
293 : inline std::istream& operator>>(std::istream& is, uint128_t& id)
294 : {
295 : std::string str;
296 : is >> str;
297 : id = str;
298 : return is;
299 : }
300 :
301 : /** Add a 64 bit value to a 128 bit value. */
302 2 : inline uint128_t operator+(const servus::uint128_t& a, const uint64_t& b)
303 : {
304 2 : uint128_t result = a;
305 2 : result.low() += b;
306 2 : if (result.low() < a.low())
307 1 : ++result.high();
308 2 : return result;
309 : }
310 :
311 : /** Add two 128 bit values. */
312 : inline uint128_t operator+(const servus::uint128_t& a,
313 : const servus::uint128_t& b)
314 : {
315 : uint128_t result = a;
316 : result += b;
317 : return result;
318 : }
319 :
320 : /** Subtract a 64 bit value from a 128 bit value. */
321 2 : inline uint128_t operator-(const servus::uint128_t& a, const uint64_t& b)
322 : {
323 2 : uint128_t result = a;
324 2 : result.low() -= b;
325 2 : if (result.low() > a.low())
326 1 : --result.high();
327 2 : return result;
328 : }
329 :
330 : /** Bitwise and operation on two 128 bit values. */
331 : inline uint128_t operator&(const servus::uint128_t& a,
332 : const servus::uint128_t& b)
333 : {
334 : uint128_t result = a;
335 : result.high() &= b.high();
336 : result.low() &= b.low();
337 : return result;
338 : }
339 :
340 : /** Bitwise or operation on two 128 bit values. */
341 : inline uint128_t operator|(const servus::uint128_t& a,
342 : const servus::uint128_t& b)
343 : {
344 : uint128_t result = a;
345 : result.high() |= b.high();
346 : result.low() |= b.low();
347 : return result;
348 : }
349 :
350 : /**
351 : * Create a 128 bit integer based on a string.
352 : *
353 : * The MD5 hash of the given text is used to form the uint128_t.
354 : *
355 : * @param string the string to form the uint128_t from.
356 : */
357 : SERVUS_API uint128_t make_uint128(const char* string);
358 :
359 : /** Create a 128 bit integer based on a string. */
360 3 : inline uint128_t make_uint128(const std::string& string)
361 : {
362 3 : return make_uint128(string.c_str());
363 : }
364 :
365 : /**
366 : * Construct a new 128 bit integer with a generated universally unique
367 : * identifier.
368 : */
369 : SERVUS_API uint128_t make_UUID();
370 : }
371 :
372 : namespace std
373 : {
374 : template <>
375 : struct hash<servus::uint128_t>
376 : {
377 : typedef size_t result_type;
378 :
379 : result_type operator()(const servus::uint128_t& in) const
380 : {
381 : hash<uint64_t> forward;
382 : return forward(in.high()) ^ forward(in.low());
383 : }
384 : };
385 :
386 1 : inline string to_string(const servus::uint128_t& value)
387 : {
388 1 : return value.getString();
389 : }
390 : }
391 :
392 : #endif // SERVUS_UINT128_H
|