1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_BASE_INT128_H_ 6 #define NET_BASE_INT128_H_ 7 8 #include <iosfwd> 9 #include "base/basictypes.h" 10 #include "net/base/net_export.h" 11 12 struct uint128_pod; 13 14 // An unsigned 128-bit integer type. Thread-compatible. 15 class uint128 { 16 public: 17 uint128(); // Sets to 0, but don't trust on this behavior. 18 uint128(uint64 top, uint64 bottom); 19 uint128(int bottom); 20 uint128(uint32 bottom); // Top 96 bits = 0 21 uint128(uint64 bottom); // hi_ = 0 22 uint128(const uint128 &val); 23 uint128(const uint128_pod &val); 24 25 void Initialize(uint64 top, uint64 bottom); 26 27 uint128& operator=(const uint128& b); 28 29 // Arithmetic operators. 30 // TODO: division, etc. 31 uint128& operator+=(const uint128& b); 32 uint128& operator-=(const uint128& b); 33 uint128& operator*=(const uint128& b); 34 uint128 operator++(int); 35 uint128 operator--(int); 36 uint128& operator<<=(int); 37 uint128& operator>>=(int); 38 uint128& operator&=(const uint128& b); 39 uint128& operator|=(const uint128& b); 40 uint128& operator^=(const uint128& b); 41 uint128& operator++(); 42 uint128& operator--(); 43 44 friend uint64 Uint128Low64(const uint128& v); 45 friend uint64 Uint128High64(const uint128& v); 46 47 // We add "std::" to avoid including all of port.h. 48 friend NET_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& o, 49 const uint128& b); 50 51 private: 52 // Little-endian memory order optimizations can benefit from 53 // having lo_ first, hi_ last. 54 // See util/endian/endian.h and Load128/Store128 for storing a uint128. 55 uint64 lo_; 56 uint64 hi_; 57 58 // Not implemented, just declared for catching automatic type conversions. 59 uint128(uint8); 60 uint128(uint16); 61 uint128(float v); 62 uint128(double v); 63 }; 64 65 // This is a POD form of uint128 which can be used for static variables which 66 // need to be operated on as uint128. 67 struct uint128_pod { 68 // Note: The ordering of fields is different than 'class uint128' but the 69 // same as its 2-arg constructor. This enables more obvious initialization 70 // of static instances, which is the primary reason for this struct in the 71 // first place. This does not seem to defeat any optimizations wrt 72 // operations involving this struct. 73 uint64 hi; 74 uint64 lo; 75 }; 76 77 NET_EXPORT_PRIVATE extern const uint128_pod kuint128max; 78 79 // allow uint128 to be logged 80 NET_EXPORT_PRIVATE extern std::ostream& operator<<(std::ostream& o, 81 const uint128& b); 82 83 // Methods to access low and high pieces of 128-bit value. 84 // Defined externally from uint128 to facilitate conversion 85 // to native 128-bit types when compilers support them. 86 inline uint64 Uint128Low64(const uint128& v) { return v.lo_; } 87 inline uint64 Uint128High64(const uint128& v) { return v.hi_; } 88 89 // TODO: perhaps it would be nice to have int128, a signed 128-bit type? 90 91 // -------------------------------------------------------------------------- 92 // Implementation details follow 93 // -------------------------------------------------------------------------- 94 inline bool operator==(const uint128& lhs, const uint128& rhs) { 95 return (Uint128Low64(lhs) == Uint128Low64(rhs) && 96 Uint128High64(lhs) == Uint128High64(rhs)); 97 } 98 inline bool operator!=(const uint128& lhs, const uint128& rhs) { 99 return !(lhs == rhs); 100 } 101 inline uint128& uint128::operator=(const uint128& b) { 102 lo_ = b.lo_; 103 hi_ = b.hi_; 104 return *this; 105 } 106 107 inline uint128::uint128(): lo_(0), hi_(0) { } 108 inline uint128::uint128(uint64 top, uint64 bottom) : lo_(bottom), hi_(top) { } 109 inline uint128::uint128(const uint128 &v) : lo_(v.lo_), hi_(v.hi_) { } 110 inline uint128::uint128(const uint128_pod &v) : lo_(v.lo), hi_(v.hi) { } 111 inline uint128::uint128(uint64 bottom) : lo_(bottom), hi_(0) { } 112 inline uint128::uint128(uint32 bottom) : lo_(bottom), hi_(0) { } 113 inline uint128::uint128(int bottom) : lo_(bottom), hi_(0) { 114 if (bottom < 0) { 115 --hi_; 116 } 117 } 118 inline void uint128::Initialize(uint64 top, uint64 bottom) { 119 hi_ = top; 120 lo_ = bottom; 121 } 122 123 // Comparison operators. 124 125 #define CMP128(op) \ 126 inline bool operator op(const uint128& lhs, const uint128& rhs) { \ 127 return (Uint128High64(lhs) == Uint128High64(rhs)) ? \ 128 (Uint128Low64(lhs) op Uint128Low64(rhs)) : \ 129 (Uint128High64(lhs) op Uint128High64(rhs)); \ 130 } 131 132 CMP128(<) 133 CMP128(>) 134 CMP128(>=) 135 CMP128(<=) 136 137 #undef CMP128 138 139 // Unary operators 140 141 inline uint128 operator-(const uint128& val) { 142 const uint64 hi_flip = ~Uint128High64(val); 143 const uint64 lo_flip = ~Uint128Low64(val); 144 const uint64 lo_add = lo_flip + 1; 145 if (lo_add < lo_flip) { 146 return uint128(hi_flip + 1, lo_add); 147 } 148 return uint128(hi_flip, lo_add); 149 } 150 151 inline bool operator!(const uint128& val) { 152 return !Uint128High64(val) && !Uint128Low64(val); 153 } 154 155 // Logical operators. 156 157 inline uint128 operator~(const uint128& val) { 158 return uint128(~Uint128High64(val), ~Uint128Low64(val)); 159 } 160 161 #define LOGIC128(op) \ 162 inline uint128 operator op(const uint128& lhs, const uint128& rhs) { \ 163 return uint128(Uint128High64(lhs) op Uint128High64(rhs), \ 164 Uint128Low64(lhs) op Uint128Low64(rhs)); \ 165 } 166 167 LOGIC128(|) 168 LOGIC128(&) 169 LOGIC128(^) 170 171 #undef LOGIC128 172 173 #define LOGICASSIGN128(op) \ 174 inline uint128& uint128::operator op(const uint128& other) { \ 175 hi_ op other.hi_; \ 176 lo_ op other.lo_; \ 177 return *this; \ 178 } 179 180 LOGICASSIGN128(|=) 181 LOGICASSIGN128(&=) 182 LOGICASSIGN128(^=) 183 184 #undef LOGICASSIGN128 185 186 // Shift operators. 187 188 inline uint128 operator<<(const uint128& val, int amount) { 189 // uint64 shifts of >= 64 are undefined, so we will need some special-casing. 190 if (amount < 64) { 191 if (amount == 0) { 192 return val; 193 } 194 uint64 new_hi = (Uint128High64(val) << amount) | 195 (Uint128Low64(val) >> (64 - amount)); 196 uint64 new_lo = Uint128Low64(val) << amount; 197 return uint128(new_hi, new_lo); 198 } else if (amount < 128) { 199 return uint128(Uint128Low64(val) << (amount - 64), 0); 200 } else { 201 return uint128(0, 0); 202 } 203 } 204 205 inline uint128 operator>>(const uint128& val, int amount) { 206 // uint64 shifts of >= 64 are undefined, so we will need some special-casing. 207 if (amount < 64) { 208 if (amount == 0) { 209 return val; 210 } 211 uint64 new_hi = Uint128High64(val) >> amount; 212 uint64 new_lo = (Uint128Low64(val) >> amount) | 213 (Uint128High64(val) << (64 - amount)); 214 return uint128(new_hi, new_lo); 215 } else if (amount < 128) { 216 return uint128(0, Uint128High64(val) >> (amount - 64)); 217 } else { 218 return uint128(0, 0); 219 } 220 } 221 222 inline uint128& uint128::operator<<=(int amount) { 223 // uint64 shifts of >= 64 are undefined, so we will need some special-casing. 224 if (amount < 64) { 225 if (amount != 0) { 226 hi_ = (hi_ << amount) | (lo_ >> (64 - amount)); 227 lo_ = lo_ << amount; 228 } 229 } else if (amount < 128) { 230 hi_ = lo_ << (amount - 64); 231 lo_ = 0; 232 } else { 233 hi_ = 0; 234 lo_ = 0; 235 } 236 return *this; 237 } 238 239 inline uint128& uint128::operator>>=(int amount) { 240 // uint64 shifts of >= 64 are undefined, so we will need some special-casing. 241 if (amount < 64) { 242 if (amount != 0) { 243 lo_ = (lo_ >> amount) | (hi_ << (64 - amount)); 244 hi_ = hi_ >> amount; 245 } 246 } else if (amount < 128) { 247 hi_ = 0; 248 lo_ = hi_ >> (amount - 64); 249 } else { 250 hi_ = 0; 251 lo_ = 0; 252 } 253 return *this; 254 } 255 256 inline uint128 operator+(const uint128& lhs, const uint128& rhs) { 257 return uint128(lhs) += rhs; 258 } 259 260 inline uint128 operator-(const uint128& lhs, const uint128& rhs) { 261 return uint128(lhs) -= rhs; 262 } 263 264 inline uint128 operator*(const uint128& lhs, const uint128& rhs) { 265 return uint128(lhs) *= rhs; 266 } 267 268 inline uint128& uint128::operator+=(const uint128& b) { 269 hi_ += b.hi_; 270 uint64 lolo = lo_ + b.lo_; 271 if (lolo < lo_) 272 ++hi_; 273 lo_ = lolo; 274 return *this; 275 } 276 277 inline uint128& uint128::operator-=(const uint128& b) { 278 hi_ -= b.hi_; 279 if (b.lo_ > lo_) 280 --hi_; 281 lo_ -= b.lo_; 282 return *this; 283 } 284 285 inline uint128& uint128::operator*=(const uint128& b) { 286 uint64 a96 = hi_ >> 32; 287 uint64 a64 = hi_ & 0xffffffffu; 288 uint64 a32 = lo_ >> 32; 289 uint64 a00 = lo_ & 0xffffffffu; 290 uint64 b96 = b.hi_ >> 32; 291 uint64 b64 = b.hi_ & 0xffffffffu; 292 uint64 b32 = b.lo_ >> 32; 293 uint64 b00 = b.lo_ & 0xffffffffu; 294 // multiply [a96 .. a00] x [b96 .. b00] 295 // terms higher than c96 disappear off the high side 296 // terms c96 and c64 are safe to ignore carry bit 297 uint64 c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96; 298 uint64 c64 = a64 * b00 + a32 * b32 + a00 * b64; 299 this->hi_ = (c96 << 32) + c64; 300 this->lo_ = 0; 301 // add terms after this one at a time to capture carry 302 *this += uint128(a32 * b00) << 32; 303 *this += uint128(a00 * b32) << 32; 304 *this += a00 * b00; 305 return *this; 306 } 307 308 inline uint128 uint128::operator++(int) { 309 uint128 tmp(*this); 310 *this += 1; 311 return tmp; 312 } 313 314 inline uint128 uint128::operator--(int) { 315 uint128 tmp(*this); 316 *this -= 1; 317 return tmp; 318 } 319 320 inline uint128& uint128::operator++() { 321 *this += 1; 322 return *this; 323 } 324 325 inline uint128& uint128::operator--() { 326 *this -= 1; 327 return *this; 328 } 329 330 #endif // NET_BASE_INT128_H_ 331