1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30#ifndef GOOGLE_PROTOBUF_STUBS_INT128_H_
31#define GOOGLE_PROTOBUF_STUBS_INT128_H_
32
33#include <google/protobuf/stubs/common.h>
34
35#include <iosfwd>
36
37#include <google/protobuf/port_def.inc>
38
39namespace google {
40namespace protobuf {
41
42struct uint128_pod;
43
44// TODO(xiaofeng): Define GOOGLE_PROTOBUF_HAS_CONSTEXPR when constexpr is
45// available.
46#ifdef GOOGLE_PROTOBUF_HAS_CONSTEXPR
47# define UINT128_CONSTEXPR constexpr
48#else
49# define UINT128_CONSTEXPR
50#endif
51
52// An unsigned 128-bit integer type. Thread-compatible.
53class PROTOBUF_EXPORT uint128 {
54 public:
55 UINT128_CONSTEXPR uint128(); // Sets to 0, but don't trust on this behavior.
56 UINT128_CONSTEXPR uint128(uint64_t top, uint64_t bottom);
57#ifndef SWIG
58 UINT128_CONSTEXPR uint128(int bottom);
59 UINT128_CONSTEXPR uint128(uint32_t bottom); // Top 96 bits = 0
60#endif
61 UINT128_CONSTEXPR uint128(uint64_t bottom); // hi_ = 0
62 UINT128_CONSTEXPR uint128(const uint128_pod &val);
63
64 // Trivial copy constructor, assignment operator and destructor.
65
66 void Initialize(uint64_t top, uint64_t bottom);
67
68 // Arithmetic operators.
69 uint128& operator+=(const uint128& b);
70 uint128& operator-=(const uint128& b);
71 uint128& operator*=(const uint128& b);
72 // Long division/modulo for uint128.
73 uint128& operator/=(const uint128& b);
74 uint128& operator%=(const uint128& b);
75 uint128 operator++(int);
76 uint128 operator--(int);
77 uint128& operator<<=(int);
78 uint128& operator>>=(int);
79 uint128& operator&=(const uint128& b);
80 uint128& operator|=(const uint128& b);
81 uint128& operator^=(const uint128& b);
82 uint128& operator++();
83 uint128& operator--();
84
85 friend uint64_t Uint128Low64(const uint128& v);
86 friend uint64_t Uint128High64(const uint128& v);
87
88 // We add "std::" to avoid including all of port.h.
89 PROTOBUF_EXPORT friend std::ostream& operator<<(std::ostream& o,
90 const uint128& b);
91
92 private:
93 static void DivModImpl(uint128 dividend, uint128 divisor,
94 uint128* quotient_ret, uint128* remainder_ret);
95
96 // Little-endian memory order optimizations can benefit from
97 // having lo_ first, hi_ last.
98 // See util/endian/endian.h and Load128/Store128 for storing a uint128.
99 uint64_t lo_;
100 uint64_t hi_;
101
102 // Not implemented, just declared for catching automatic type conversions.
103 uint128(uint8_t);
104 uint128(uint16_t);
105 uint128(float v);
106 uint128(double v);
107};
108
109// This is a POD form of uint128 which can be used for static variables which
110// need to be operated on as uint128.
111struct uint128_pod {
112 // Note: The ordering of fields is different than 'class uint128' but the
113 // same as its 2-arg constructor. This enables more obvious initialization
114 // of static instances, which is the primary reason for this struct in the
115 // first place. This does not seem to defeat any optimizations wrt
116 // operations involving this struct.
117 uint64_t hi;
118 uint64_t lo;
119};
120
121PROTOBUF_EXPORT extern const uint128_pod kuint128max;
122
123// allow uint128 to be logged
124PROTOBUF_EXPORT extern std::ostream& operator<<(std::ostream& o,
125 const uint128& b);
126
127// Methods to access low and high pieces of 128-bit value.
128// Defined externally from uint128 to facilitate conversion
129// to native 128-bit types when compilers support them.
130inline uint64_t Uint128Low64(const uint128& v) { return v.lo_; }
131inline uint64_t Uint128High64(const uint128& v) { return v.hi_; }
132
133// TODO: perhaps it would be nice to have int128, a signed 128-bit type?
134
135// --------------------------------------------------------------------------
136// Implementation details follow
137// --------------------------------------------------------------------------
138inline bool operator==(const uint128& lhs, const uint128& rhs) {
139 return (Uint128Low64(v: lhs) == Uint128Low64(v: rhs) &&
140 Uint128High64(v: lhs) == Uint128High64(v: rhs));
141}
142inline bool operator!=(const uint128& lhs, const uint128& rhs) {
143 return !(lhs == rhs);
144}
145
146inline UINT128_CONSTEXPR uint128::uint128() : lo_(0), hi_(0) {}
147inline UINT128_CONSTEXPR uint128::uint128(uint64_t top, uint64_t bottom)
148 : lo_(bottom), hi_(top) {}
149inline UINT128_CONSTEXPR uint128::uint128(const uint128_pod& v)
150 : lo_(v.lo), hi_(v.hi) {}
151inline UINT128_CONSTEXPR uint128::uint128(uint64_t bottom)
152 : lo_(bottom), hi_(0) {}
153#ifndef SWIG
154inline UINT128_CONSTEXPR uint128::uint128(uint32_t bottom)
155 : lo_(bottom), hi_(0) {}
156inline UINT128_CONSTEXPR uint128::uint128(int bottom)
157 : lo_(bottom), hi_(static_cast<int64_t>((bottom < 0) ? -1 : 0)) {}
158#endif
159
160#undef UINT128_CONSTEXPR
161
162inline void uint128::Initialize(uint64_t top, uint64_t bottom) {
163 hi_ = top;
164 lo_ = bottom;
165}
166
167// Comparison operators.
168
169#define CMP128(op) \
170inline bool operator op(const uint128& lhs, const uint128& rhs) { \
171 return (Uint128High64(lhs) == Uint128High64(rhs)) ? \
172 (Uint128Low64(lhs) op Uint128Low64(rhs)) : \
173 (Uint128High64(lhs) op Uint128High64(rhs)); \
174}
175
176CMP128(<)
177CMP128(>)
178CMP128(>=)
179CMP128(<=)
180
181#undef CMP128
182
183// Unary operators
184
185inline uint128 operator-(const uint128& val) {
186 const uint64_t hi_flip = ~Uint128High64(v: val);
187 const uint64_t lo_flip = ~Uint128Low64(v: val);
188 const uint64_t lo_add = lo_flip + 1;
189 if (lo_add < lo_flip) {
190 return uint128(hi_flip + 1, lo_add);
191 }
192 return uint128(hi_flip, lo_add);
193}
194
195inline bool operator!(const uint128& val) {
196 return !Uint128High64(v: val) && !Uint128Low64(v: val);
197}
198
199// Logical operators.
200
201inline uint128 operator~(const uint128& val) {
202 return uint128(~Uint128High64(v: val), ~Uint128Low64(v: val));
203}
204
205#define LOGIC128(op) \
206inline uint128 operator op(const uint128& lhs, const uint128& rhs) { \
207 return uint128(Uint128High64(lhs) op Uint128High64(rhs), \
208 Uint128Low64(lhs) op Uint128Low64(rhs)); \
209}
210
211LOGIC128(|)
212LOGIC128(&)
213LOGIC128(^)
214
215#undef LOGIC128
216
217#define LOGICASSIGN128(op) \
218inline uint128& uint128::operator op(const uint128& other) { \
219 hi_ op other.hi_; \
220 lo_ op other.lo_; \
221 return *this; \
222}
223
224LOGICASSIGN128(|=)
225LOGICASSIGN128(&=)
226LOGICASSIGN128(^=)
227
228#undef LOGICASSIGN128
229
230// Shift operators.
231
232inline uint128 operator<<(const uint128& val, int amount) {
233 // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
234 if (amount < 64) {
235 if (amount == 0) {
236 return val;
237 }
238 uint64_t new_hi = (Uint128High64(v: val) << amount) |
239 (Uint128Low64(v: val) >> (64 - amount));
240 uint64_t new_lo = Uint128Low64(v: val) << amount;
241 return uint128(new_hi, new_lo);
242 } else if (amount < 128) {
243 return uint128(Uint128Low64(v: val) << (amount - 64), 0);
244 } else {
245 return uint128(0, 0);
246 }
247}
248
249inline uint128 operator>>(const uint128& val, int amount) {
250 // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
251 if (amount < 64) {
252 if (amount == 0) {
253 return val;
254 }
255 uint64_t new_hi = Uint128High64(v: val) >> amount;
256 uint64_t new_lo = (Uint128Low64(v: val) >> amount) |
257 (Uint128High64(v: val) << (64 - amount));
258 return uint128(new_hi, new_lo);
259 } else if (amount < 128) {
260 return uint128(0, Uint128High64(v: val) >> (amount - 64));
261 } else {
262 return uint128(0, 0);
263 }
264}
265
266inline uint128& uint128::operator<<=(int amount) {
267 // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
268 if (amount < 64) {
269 if (amount != 0) {
270 hi_ = (hi_ << amount) | (lo_ >> (64 - amount));
271 lo_ = lo_ << amount;
272 }
273 } else if (amount < 128) {
274 hi_ = lo_ << (amount - 64);
275 lo_ = 0;
276 } else {
277 hi_ = 0;
278 lo_ = 0;
279 }
280 return *this;
281}
282
283inline uint128& uint128::operator>>=(int amount) {
284 // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
285 if (amount < 64) {
286 if (amount != 0) {
287 lo_ = (lo_ >> amount) | (hi_ << (64 - amount));
288 hi_ = hi_ >> amount;
289 }
290 } else if (amount < 128) {
291 lo_ = hi_ >> (amount - 64);
292 hi_ = 0;
293 } else {
294 lo_ = 0;
295 hi_ = 0;
296 }
297 return *this;
298}
299
300inline uint128 operator+(const uint128& lhs, const uint128& rhs) {
301 return uint128(lhs) += rhs;
302}
303
304inline uint128 operator-(const uint128& lhs, const uint128& rhs) {
305 return uint128(lhs) -= rhs;
306}
307
308inline uint128 operator*(const uint128& lhs, const uint128& rhs) {
309 return uint128(lhs) *= rhs;
310}
311
312inline uint128 operator/(const uint128& lhs, const uint128& rhs) {
313 return uint128(lhs) /= rhs;
314}
315
316inline uint128 operator%(const uint128& lhs, const uint128& rhs) {
317 return uint128(lhs) %= rhs;
318}
319
320inline uint128& uint128::operator+=(const uint128& b) {
321 hi_ += b.hi_;
322 uint64_t lolo = lo_ + b.lo_;
323 if (lolo < lo_)
324 ++hi_;
325 lo_ = lolo;
326 return *this;
327}
328
329inline uint128& uint128::operator-=(const uint128& b) {
330 hi_ -= b.hi_;
331 if (b.lo_ > lo_)
332 --hi_;
333 lo_ -= b.lo_;
334 return *this;
335}
336
337inline uint128& uint128::operator*=(const uint128& b) {
338 uint64_t a96 = hi_ >> 32;
339 uint64_t a64 = hi_ & 0xffffffffu;
340 uint64_t a32 = lo_ >> 32;
341 uint64_t a00 = lo_ & 0xffffffffu;
342 uint64_t b96 = b.hi_ >> 32;
343 uint64_t b64 = b.hi_ & 0xffffffffu;
344 uint64_t b32 = b.lo_ >> 32;
345 uint64_t b00 = b.lo_ & 0xffffffffu;
346 // multiply [a96 .. a00] x [b96 .. b00]
347 // terms higher than c96 disappear off the high side
348 // terms c96 and c64 are safe to ignore carry bit
349 uint64_t c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96;
350 uint64_t c64 = a64 * b00 + a32 * b32 + a00 * b64;
351 this->hi_ = (c96 << 32) + c64;
352 this->lo_ = 0;
353 // add terms after this one at a time to capture carry
354 *this += uint128(a32 * b00) << 32;
355 *this += uint128(a00 * b32) << 32;
356 *this += a00 * b00;
357 return *this;
358}
359
360inline uint128 uint128::operator++(int) {
361 uint128 tmp(*this);
362 *this += 1;
363 return tmp;
364}
365
366inline uint128 uint128::operator--(int) {
367 uint128 tmp(*this);
368 *this -= 1;
369 return tmp;
370}
371
372inline uint128& uint128::operator++() {
373 *this += 1;
374 return *this;
375}
376
377inline uint128& uint128::operator--() {
378 *this -= 1;
379 return *this;
380}
381
382} // namespace protobuf
383} // namespace google
384
385#include <google/protobuf/port_undef.inc>
386
387#endif // GOOGLE_PROTOBUF_STUBS_INT128_H_
388