Line data Source code
1 :
2 : /* Copyright (c) 2010, Cedric Stalder <cedric.stalder@gmail.com>
3 : * 2010-2014, Stefan Eilemann <eile@eyescale.ch>
4 : * 2010-2012, Daniel Nachbaur <danielnachbaur@gmail.com>
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 2.1 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 : #ifndef LUNCHBOX_UINT128_H
21 : #define LUNCHBOX_UINT128_H
22 :
23 : #include <lunchbox/api.h>
24 : #include <lunchbox/compiler.h>
25 :
26 : #include <sstream>
27 : #ifdef _MSC_VER
28 : // Don't include <lunchbox/types.h> to be minimally intrusive for apps
29 : // using uint128_t
30 : # include <basetsd.h>
31 : typedef UINT64 uint64_t;
32 : #else
33 : # include <stdint.h>
34 : #endif
35 :
36 : namespace lunchbox
37 : {
38 : class uint128_t;
39 : std::ostream& operator << ( std::ostream& os, const uint128_t& id );
40 :
41 : /**
42 : * A base type for 128 bit unsigned integer values.
43 : *
44 : * Example: @include tests/uint128_t.cpp
45 : */
46 : class uint128_t
47 : {
48 : public:
49 : /**
50 : * Construct a new 128 bit integer with a default value.
51 : * @version 1.0
52 : */
53 199542 : explicit uint128_t( const unsigned long long low_ = 0 )
54 199542 : : _high( 0 ), _low( low_ ) {}
55 :
56 : /**
57 : * Construct a new 128 bit integer with a default value.
58 : * @version 1.9.1
59 : */
60 : explicit uint128_t( const unsigned long low_ ) : _high( 0 ), _low( low_ ) {}
61 :
62 : /**
63 : * Construct a new 128 bit integer with a default value.
64 : * @version 1.9.1
65 : */
66 2 : explicit uint128_t( const int low_ ) : _high( 0 ), _low( low_ ) {}
67 :
68 : #ifdef LUNCHBOX_USE_V1_API
69 : /**
70 : * Construct a new 128 bit integer with a generated universally unique
71 : * identifier.
72 : *
73 : * @param generate if set to false, the uint128_t will be set to 0.
74 : * @version 1.9.1
75 : * @deprecated
76 : */
77 : LUNCHBOX_API explicit uint128_t( const bool generate ) LB_DEPRECATED;
78 : #endif
79 :
80 : /**
81 : * Construct a new 128 bit integer with default values.
82 : * @version 1.0
83 : **/
84 13 : uint128_t( const uint64_t high_, const uint64_t low_ )
85 13 : : _high( high_ ), _low( low_ ) {}
86 :
87 : /**
88 : * Construct a new 128 bit integer from a string representation.
89 : * @version 1.3.2
90 : **/
91 : explicit uint128_t( const std::string& string )
92 : : _high( 0 ), _low( 0 ) { *this = string; }
93 :
94 : /**
95 : * @return true if the uint128_t is a generated universally unique
96 : * identifier.
97 : * @version 1.9.1
98 : */
99 99996 : bool isUUID() const { return high() != 0; }
100 :
101 : /** Assign another 128 bit value. @version 1.0 */
102 400014 : uint128_t& operator = ( const lunchbox::uint128_t& rhs )
103 : {
104 400014 : _high = rhs._high;
105 400014 : _low = rhs._low;
106 400014 : return *this;
107 : }
108 :
109 : /** Assign another 64 bit value. @version 1.1.1 */
110 : uint128_t& operator = ( const uint64_t rhs )
111 : {
112 : _high = 0;
113 : _low = rhs;
114 : return *this;
115 : }
116 :
117 : /** Assign an integer value. @version 1.7.1 */
118 : uint128_t& operator = ( const int rhs )
119 : {
120 : _high = 0;
121 : _low = rhs;
122 : return *this;
123 : }
124 :
125 : /** Assign an 128 bit value from a std::string. @version 1.0 */
126 : LUNCHBOX_API uint128_t& operator = ( const std::string& from );
127 :
128 : /**
129 : * @return true if the values are equal, false if not.
130 : * @version 1.0
131 : **/
132 180011 : bool operator == ( const lunchbox::uint128_t& rhs ) const
133 180011 : { return _high == rhs._high && _low == rhs._low; }
134 :
135 : /**
136 : * @return true if the values are different, false otherwise.
137 : * @version 1.0
138 : **/
139 383661 : bool operator != ( const lunchbox::uint128_t& rhs ) const
140 383661 : { return _high != rhs._high || _low != rhs._low; }
141 :
142 : /**
143 : * @return true if the values are equal, false otherwise.
144 : * @version 1.9.1
145 : **/
146 : bool operator == ( const unsigned long long& low_ ) const
147 : { return *this == uint128_t( low_ ); }
148 :
149 : /**
150 : * @return true if the values are different, false otherwise.
151 : * @version 1.9.1
152 : **/
153 : bool operator != ( const unsigned long long& low_ ) const
154 : { return *this != uint128_t( low_ ); }
155 :
156 : /**
157 : * @return true if this value is smaller than the RHS value.
158 : * @version 1.0
159 : **/
160 : bool operator < ( const lunchbox::uint128_t& rhs ) const
161 : {
162 : if( _high < rhs._high )
163 : return true;
164 : if( _high > rhs._high )
165 : return false;
166 : return _low < rhs._low;
167 : }
168 :
169 : /**
170 : * @return true if this value is bigger than the rhs value.
171 : * @version 1.0
172 : */
173 76731 : bool operator > ( const lunchbox::uint128_t& rhs ) const
174 : {
175 76731 : if( _high > rhs._high )
176 0 : return true;
177 76731 : if( _high < rhs._high )
178 76731 : return false;
179 0 : return _low > rhs._low;
180 : }
181 :
182 : /**
183 : * @return true if this value is smaller or equal than the
184 : * RHS value.
185 : * @version 1.0
186 : */
187 : bool operator <= ( const lunchbox::uint128_t& rhs ) const
188 : {
189 : if( _high < rhs._high )
190 : return true;
191 : if( _high > rhs._high )
192 : return false;
193 : return _low <= rhs._low;
194 : }
195 :
196 : /**
197 : * @return true if this value is smaller or equal than the
198 : * RHS value.
199 : * @version 1.0
200 : */
201 : bool operator >= ( const lunchbox::uint128_t& rhs ) const
202 : {
203 : if( _high > rhs._high )
204 : return true;
205 : if( _high < rhs._high )
206 : return false;
207 : return _low >= rhs._low;
208 : }
209 :
210 : /** Increment the value. @version 1.0 */
211 4 : uint128_t& operator ++()
212 : {
213 4 : ++_low;
214 4 : if( !_low )
215 2 : ++_high;
216 :
217 4 : return *this;
218 : }
219 :
220 : /** Decrement the value. @version 1.0 */
221 4 : uint128_t& operator --()
222 : {
223 4 : if( !_low )
224 2 : --_high;
225 4 : --_low;
226 4 : return *this;
227 : }
228 :
229 : /** Add value and return the new value. @version 1.5.1 */
230 : uint128_t& operator +=( const lunchbox::uint128_t& rhs )
231 : {
232 : const uint64_t oldLow = _low;
233 : _low += rhs._low;
234 : if( _low < oldLow ) // overflow
235 : _high += rhs._high + 1;
236 : else
237 : _high += rhs._high;
238 : return *this;
239 : }
240 :
241 : /** @return the reference to the lower 64 bits of this 128 bit value. */
242 469079 : const uint64_t& low() const { return _low; }
243 : /** @return the reference to the high 64 bits of this 128 bit value. */
244 658418 : const uint64_t& high() const { return _high; }
245 :
246 : /** @return the reference to the lower 64 bits of this 128 bit value. */
247 100044 : uint64_t& low() { return _low; }
248 : /** @return the reference to the high 64 bits of this 128 bit value. */
249 296329 : uint64_t& high() { return _high; }
250 :
251 : /** @return a short, but not necessarily unique, string of the value. */
252 : std::string getShortString() const
253 : {
254 : std::stringstream stream;
255 : stream << std::hex << _high << _low;
256 : const std::string str = stream.str();
257 : return str.substr( 0, 3 ) + ".." +
258 : str.substr( str.length() - 3, std::string::npos );
259 : }
260 :
261 : /** @return the full string representation of the value. */
262 : std::string getString() const
263 : {
264 : std::stringstream stream;
265 : stream << *this;
266 : return stream.str();
267 : }
268 :
269 : /** Serialize this object to a boost archive. @version 1.3.1 */
270 : template< class Archive >
271 4 : void serialize( Archive& ar, const unsigned int /*version*/ )
272 : {
273 4 : ar & low();
274 4 : ar & high();
275 4 : }
276 :
277 : #ifdef LUNCHBOX_USE_V1_API
278 : /** @return true if the uint128_t was generated.
279 : * @deprecated
280 : */
281 : bool isGenerated() const LB_DEPRECATED { return high() != 0; }
282 :
283 : /** @deprecated Don't use, static initializer fiasco. Use 0/uint128_t()*/
284 : static LUNCHBOX_API const uint128_t ZERO LB_DEPRECATED;
285 : #endif
286 :
287 : private:
288 : uint64_t _high;
289 : uint64_t _low;
290 : };
291 :
292 : /** ostream operator for 128 bit unsigned integers. @version 1.0 */
293 90000 : inline std::ostream& operator << ( std::ostream& os, const uint128_t& id )
294 : {
295 90000 : if( id.high() == 0 )
296 0 : os << std::hex << id.low() << std::dec;
297 : else
298 90000 : os << std::hex << id.high() << ':' << id.low() << std::dec;
299 90000 : return os;
300 : }
301 :
302 : /** istream operator for 128 bit unsigned integers. @version 1.7.0 */
303 : inline std::istream& operator >> ( std::istream& is, uint128_t& id )
304 : {
305 : std::string str;
306 : is >> str;
307 : id = str;
308 : return is;
309 : }
310 :
311 : /** Add a 64 bit value to a 128 bit value. @version 1.0 */
312 4 : inline uint128_t operator+ ( const lunchbox::uint128_t& a, const uint64_t& b )
313 : {
314 4 : uint128_t result = a;
315 4 : result.low() += b;
316 4 : if( result.low() < a.low( ))
317 2 : ++result.high();
318 4 : return result;
319 : }
320 :
321 : /** Add two 128 bit values. @version 1.5.1 */
322 : inline uint128_t operator+ ( const lunchbox::uint128_t& a,
323 : const lunchbox::uint128_t& b )
324 : {
325 : uint128_t result = a;
326 : result += b;
327 : return result;
328 : }
329 :
330 : /** Subtract a 64 bit value from a 128 bit value. @version 1.0 */
331 4 : inline uint128_t operator- ( const lunchbox::uint128_t& a, const uint64_t& b )
332 : {
333 4 : uint128_t result = a;
334 4 : result.low() -= b;
335 4 : if( result.low() > a.low( ))
336 2 : --result.high();
337 4 : return result;
338 : }
339 :
340 : /** Bitwise and operation on two 128 bit values. @version 1.1.5 */
341 : inline uint128_t operator & ( const lunchbox::uint128_t& a,
342 : const lunchbox::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 : /** Bitwise or operation on two 128 bit values. @version 1.1.5 */
351 : inline uint128_t operator | ( const lunchbox::uint128_t& a,
352 : const lunchbox::uint128_t& b )
353 : {
354 : uint128_t result = a;
355 : result.high() |= b.high();
356 : result.low() |= b.low();
357 : return result;
358 : }
359 :
360 : /**
361 : * Create a 128 bit integer based on a string.
362 : *
363 : * The MD5 hash of the given text is used to form the uint128_t.
364 : *
365 : * @param string the string to form the uint128_t from.
366 : * @version 1.3.2
367 : */
368 : LUNCHBOX_API uint128_t make_uint128( const char* string );
369 :
370 : /**
371 : * Construct a new 128 bit integer with a generated universally unique
372 : * identifier.
373 : * @version 1.9.1
374 : */
375 : LUNCHBOX_API uint128_t make_UUID();
376 :
377 : }
378 : #endif // LUNCHBOX_UINT128_H
|