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