33
33
#include < google/protobuf/stubs/common.h>
34
34
35
35
#include < iosfwd>
36
+ #include < limits>
37
+ #include < string>
36
38
37
39
#include < google/protobuf/port_def.inc>
38
40
39
41
namespace google {
40
42
namespace protobuf {
41
-
42
- struct 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
43
+ namespace int128_internal {
51
44
52
45
// An unsigned 128-bit integer type. Thread-compatible.
53
46
class PROTOBUF_EXPORT uint128 {
54
47
public:
55
- UINT128_CONSTEXPR uint128 (); // Sets to 0, but don't trust on this behavior.
56
- UINT128_CONSTEXPR uint128 (uint64 top, uint64 bottom);
48
+ uint128 () = default ;
49
+
50
+ private:
51
+ // Use `MakeUint128` instead.
52
+ constexpr uint128 (uint64 top, uint64 bottom);
53
+
54
+ public:
57
55
#ifndef SWIG
58
- UINT128_CONSTEXPR uint128 (int bottom);
59
- UINT128_CONSTEXPR uint128 (uint32 bottom); // Top 96 bits = 0
56
+ constexpr uint128 (int bottom);
57
+ constexpr uint128 (uint32 bottom); // Top 96 bits = 0
60
58
#endif
61
- UINT128_CONSTEXPR uint128 (uint64 bottom); // hi_ = 0
62
- UINT128_CONSTEXPR uint128 (const uint128_pod &val);
59
+ constexpr uint128 (uint64 bottom); // hi_ = 0
63
60
64
61
// Trivial copy constructor, assignment operator and destructor.
65
62
66
- void Initialize (uint64 top, uint64 bottom);
67
-
68
63
// Arithmetic operators.
69
64
uint128& operator +=(const uint128& b);
70
65
uint128& operator -=(const uint128& b);
@@ -82,8 +77,10 @@ class PROTOBUF_EXPORT uint128 {
82
77
uint128& operator ++();
83
78
uint128& operator --();
84
79
85
- friend uint64 Uint128Low64 (const uint128& v);
86
- friend uint64 Uint128High64 (const uint128& v);
80
+ friend constexpr uint64 Uint128Low64 (const uint128& v);
81
+ friend constexpr uint64 Uint128High64 (const uint128& v);
82
+
83
+ friend constexpr uint128 MakeUint128 (uint64_t high, uint64_t low);
87
84
88
85
// We add "std::" to avoid including all of port.h.
89
86
PROTOBUF_EXPORT friend std::ostream& operator <<(std::ostream& o,
@@ -100,35 +97,25 @@ class PROTOBUF_EXPORT uint128 {
100
97
uint64 hi_;
101
98
102
99
// Not implemented, just declared for catching automatic type conversions.
103
- uint128 (uint8);
104
- uint128 (uint16);
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.
111
- struct 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 hi;
118
- uint64 lo;
100
+ uint128 (uint8) = delete ;
101
+ uint128 (uint16) = delete ;
102
+ uint128 (float v) = delete ;
103
+ uint128 (double v) = delete ;
119
104
};
120
105
121
- PROTOBUF_EXPORT extern const uint128_pod kuint128max;
122
-
123
106
// allow uint128 to be logged
124
107
PROTOBUF_EXPORT extern std::ostream& operator <<(std::ostream& o,
125
108
const uint128& b);
126
109
127
110
// Methods to access low and high pieces of 128-bit value.
128
111
// Defined externally from uint128 to facilitate conversion
129
112
// to native 128-bit types when compilers support them.
130
- inline uint64 Uint128Low64 (const uint128& v) { return v.lo_ ; }
131
- inline uint64 Uint128High64 (const uint128& v) { return v.hi_ ; }
113
+ inline constexpr uint64 Uint128Low64 (const uint128& v) { return v.lo_ ; }
114
+ inline constexpr uint64 Uint128High64 (const uint128& v) { return v.hi_ ; }
115
+
116
+ constexpr uint128 MakeUint128 (uint64_t high, uint64_t low) {
117
+ return uint128 (high, low);
118
+ }
132
119
133
120
// TODO: perhaps it would be nice to have int128, a signed 128-bit type?
134
121
@@ -143,27 +130,17 @@ inline bool operator!=(const uint128& lhs, const uint128& rhs) {
143
130
return !(lhs == rhs);
144
131
}
145
132
146
- inline UINT128_CONSTEXPR uint128::uint128 () : lo_(0 ), hi_(0 ) {}
147
- inline UINT128_CONSTEXPR uint128::uint128 (uint64 top, uint64 bottom)
133
+ inline constexpr uint128::uint128 (uint64 top, uint64 bottom)
148
134
: lo_(bottom), hi_(top) {}
149
- inline UINT128_CONSTEXPR uint128::uint128 (const uint128_pod& v)
150
- : lo_(v.lo), hi_(v.hi) {}
151
- inline UINT128_CONSTEXPR uint128::uint128 (uint64 bottom)
135
+ inline constexpr uint128::uint128 (uint64 bottom)
152
136
: lo_(bottom), hi_(0 ) {}
153
137
#ifndef SWIG
154
- inline UINT128_CONSTEXPR uint128::uint128 (uint32 bottom)
138
+ inline constexpr uint128::uint128 (uint32 bottom)
155
139
: lo_(bottom), hi_(0 ) {}
156
- inline UINT128_CONSTEXPR uint128::uint128 (int bottom)
140
+ inline constexpr uint128::uint128 (int bottom)
157
141
: lo_(bottom), hi_(static_cast <int64>((bottom < 0 ) ? -1 : 0)) {}
158
142
#endif
159
143
160
- #undef UINT128_CONSTEXPR
161
-
162
- inline void uint128::Initialize (uint64 top, uint64 bottom) {
163
- hi_ = top;
164
- lo_ = bottom;
165
- }
166
-
167
144
// Comparison operators.
168
145
169
146
#define CMP128 (op ) \
@@ -187,9 +164,9 @@ inline uint128 operator-(const uint128& val) {
187
164
const uint64 lo_flip = ~Uint128Low64 (val);
188
165
const uint64 lo_add = lo_flip + 1 ;
189
166
if (lo_add < lo_flip) {
190
- return uint128 (hi_flip + 1 , lo_add);
167
+ return MakeUint128 (hi_flip + 1 , lo_add);
191
168
}
192
- return uint128 (hi_flip, lo_add);
169
+ return MakeUint128 (hi_flip, lo_add);
193
170
}
194
171
195
172
inline bool operator !(const uint128& val) {
@@ -199,13 +176,13 @@ inline bool operator!(const uint128& val) {
199
176
// Logical operators.
200
177
201
178
inline uint128 operator ~(const uint128& val) {
202
- return uint128 (~Uint128High64 (val), ~Uint128Low64 (val));
179
+ return MakeUint128 (~Uint128High64 (val), ~Uint128Low64 (val));
203
180
}
204
181
205
182
#define LOGIC128 (op ) \
206
183
inline uint128 operator op (const uint128& lhs, const uint128& rhs) { \
207
- return uint128 (Uint128High64 (lhs) op Uint128High64 (rhs), \
208
- Uint128Low64 (lhs) op Uint128Low64 (rhs)); \
184
+ return MakeUint128 (Uint128High64 (lhs) op Uint128High64 (rhs), \
185
+ Uint128Low64 (lhs) op Uint128Low64 (rhs)); \
209
186
}
210
187
211
188
LOGIC128 (|)
@@ -229,7 +206,11 @@ LOGICASSIGN128(^=)
229
206
230
207
// Shift operators.
231
208
209
+ void VerifyValidShift (std::string op, int amount);
210
+
232
211
inline uint128 operator <<(const uint128& val, int amount) {
212
+ VerifyValidShift (" <<" , amount);
213
+
233
214
// uint64 shifts of >= 64 are undefined, so we will need some special-casing.
234
215
if (amount < 64 ) {
235
216
if (amount == 0 ) {
@@ -238,15 +219,14 @@ inline uint128 operator<<(const uint128& val, int amount) {
238
219
uint64 new_hi = (Uint128High64 (val) << amount) |
239
220
(Uint128Low64 (val) >> (64 - amount));
240
221
uint64 new_lo = Uint128Low64 (val) << amount;
241
- return uint128 (new_hi, new_lo);
242
- } else if (amount < 128 ) {
243
- return uint128 (Uint128Low64 (val) << (amount - 64 ), 0 );
244
- } else {
245
- return uint128 (0 , 0 );
222
+ return MakeUint128 (new_hi, new_lo);
246
223
}
224
+ return MakeUint128 (Uint128Low64 (val) << (amount - 64 ), 0 );
247
225
}
248
226
249
227
inline uint128 operator >>(const uint128& val, int amount) {
228
+ VerifyValidShift (" >>" , amount);
229
+
250
230
// uint64 shifts of >= 64 are undefined, so we will need some special-casing.
251
231
if (amount < 64 ) {
252
232
if (amount == 0 ) {
@@ -255,12 +235,10 @@ inline uint128 operator>>(const uint128& val, int amount) {
255
235
uint64 new_hi = Uint128High64 (val) >> amount;
256
236
uint64 new_lo = (Uint128Low64 (val) >> amount) |
257
237
(Uint128High64 (val) << (64 - amount));
258
- return uint128 (new_hi, new_lo);
259
- } else if (amount < 128 ) {
260
- return uint128 (0 , Uint128High64 (val) >> (amount - 64 ));
261
- } else {
262
- return uint128 (0 , 0 );
238
+ return MakeUint128 (new_hi, new_lo);
263
239
}
240
+
241
+ return MakeUint128 (0 , Uint128High64 (val) >> (amount - 64 ));
264
242
}
265
243
266
244
inline uint128& uint128::operator <<=(int amount) {
@@ -379,6 +357,17 @@ inline uint128& uint128::operator--() {
379
357
return *this ;
380
358
}
381
359
360
+ constexpr uint128 Uint128Max () {
361
+ return MakeUint128 ((std::numeric_limits<uint64>::max)(),
362
+ (std::numeric_limits<uint64>::max)());
363
+ }
364
+
365
+ } // namespace int128_internal
366
+
367
+ using google::protobuf::int128_internal::uint128;
368
+ using google::protobuf::int128_internal::Uint128Max;
369
+ using google::protobuf::int128_internal::MakeUint128;
370
+
382
371
} // namespace protobuf
383
372
} // namespace google
384
373
0 commit comments