Home | History | Annotate | Download | only in stubs
      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 namespace google {
     38 namespace protobuf {
     39 
     40 struct uint128_pod;
     41 
     42 // TODO(xiaofeng): Define GOOGLE_PROTOBUF_HAS_CONSTEXPR when constexpr is
     43 // available.
     44 #ifdef GOOGLE_PROTOBUF_HAS_CONSTEXPR
     45 # define UINT128_CONSTEXPR constexpr
     46 #else
     47 # define UINT128_CONSTEXPR
     48 #endif
     49 
     50 // An unsigned 128-bit integer type. Thread-compatible.
     51 class LIBPROTOBUF_EXPORT uint128 {
     52  public:
     53   UINT128_CONSTEXPR uint128();  // Sets to 0, but don't trust on this behavior.
     54   UINT128_CONSTEXPR uint128(uint64 top, uint64 bottom);
     55 #ifndef SWIG
     56   UINT128_CONSTEXPR uint128(int bottom);
     57   UINT128_CONSTEXPR uint128(uint32 bottom);   // Top 96 bits = 0
     58 #endif
     59   UINT128_CONSTEXPR uint128(uint64 bottom);   // hi_ = 0
     60   UINT128_CONSTEXPR uint128(const uint128_pod &val);
     61 
     62   // Trivial copy constructor, assignment operator and destructor.
     63 
     64   void Initialize(uint64 top, uint64 bottom);
     65 
     66   // Arithmetic operators.
     67   uint128& operator+=(const uint128& b);
     68   uint128& operator-=(const uint128& b);
     69   uint128& operator*=(const uint128& b);
     70   // Long division/modulo for uint128.
     71   uint128& operator/=(const uint128& b);
     72   uint128& operator%=(const uint128& b);
     73   uint128 operator++(int);
     74   uint128 operator--(int);
     75   uint128& operator<<=(int);
     76   uint128& operator>>=(int);
     77   uint128& operator&=(const uint128& b);
     78   uint128& operator|=(const uint128& b);
     79   uint128& operator^=(const uint128& b);
     80   uint128& operator++();
     81   uint128& operator--();
     82 
     83   friend uint64 Uint128Low64(const uint128& v);
     84   friend uint64 Uint128High64(const uint128& v);
     85 
     86   // We add "std::" to avoid including all of port.h.
     87   LIBPROTOBUF_EXPORT friend std::ostream& operator<<(std::ostream& o,
     88                                                      const uint128& b);
     89 
     90  private:
     91   static void DivModImpl(uint128 dividend, uint128 divisor,
     92                          uint128* quotient_ret, uint128* remainder_ret);
     93 
     94   // Little-endian memory order optimizations can benefit from
     95   // having lo_ first, hi_ last.
     96   // See util/endian/endian.h and Load128/Store128 for storing a uint128.
     97   uint64        lo_;
     98   uint64        hi_;
     99 
    100   // Not implemented, just declared for catching automatic type conversions.
    101   uint128(uint8);
    102   uint128(uint16);
    103   uint128(float v);
    104   uint128(double v);
    105 };
    106 
    107 // This is a POD form of uint128 which can be used for static variables which
    108 // need to be operated on as uint128.
    109 struct uint128_pod {
    110   // Note: The ordering of fields is different than 'class uint128' but the
    111   // same as its 2-arg constructor.  This enables more obvious initialization
    112   // of static instances, which is the primary reason for this struct in the
    113   // first place.  This does not seem to defeat any optimizations wrt
    114   // operations involving this struct.
    115   uint64 hi;
    116   uint64 lo;
    117 };
    118 
    119 LIBPROTOBUF_EXPORT extern const uint128_pod kuint128max;
    120 
    121 // allow uint128 to be logged
    122 LIBPROTOBUF_EXPORT extern std::ostream& operator<<(std::ostream& o,
    123                                                    const uint128& b);
    124 
    125 // Methods to access low and high pieces of 128-bit value.
    126 // Defined externally from uint128 to facilitate conversion
    127 // to native 128-bit types when compilers support them.
    128 inline uint64 Uint128Low64(const uint128& v) { return v.lo_; }
    129 inline uint64 Uint128High64(const uint128& v) { return v.hi_; }
    130 
    131 // TODO: perhaps it would be nice to have int128, a signed 128-bit type?
    132 
    133 // --------------------------------------------------------------------------
    134 //                      Implementation details follow
    135 // --------------------------------------------------------------------------
    136 inline bool operator==(const uint128& lhs, const uint128& rhs) {
    137   return (Uint128Low64(lhs) == Uint128Low64(rhs) &&
    138           Uint128High64(lhs) == Uint128High64(rhs));
    139 }
    140 inline bool operator!=(const uint128& lhs, const uint128& rhs) {
    141   return !(lhs == rhs);
    142 }
    143 
    144 inline UINT128_CONSTEXPR uint128::uint128() : lo_(0), hi_(0) {}
    145 inline UINT128_CONSTEXPR uint128::uint128(uint64 top, uint64 bottom)
    146     : lo_(bottom), hi_(top) {}
    147 inline UINT128_CONSTEXPR uint128::uint128(const uint128_pod& v)
    148     : lo_(v.lo), hi_(v.hi) {}
    149 inline UINT128_CONSTEXPR uint128::uint128(uint64 bottom)
    150     : lo_(bottom), hi_(0) {}
    151 #ifndef SWIG
    152 inline UINT128_CONSTEXPR uint128::uint128(uint32 bottom)
    153     : lo_(bottom), hi_(0) {}
    154 inline UINT128_CONSTEXPR uint128::uint128(int bottom)
    155     : lo_(bottom), hi_(static_cast<int64>((bottom < 0) ? -1 : 0)) {}
    156 #endif
    157 
    158 #undef UINT128_CONSTEXPR
    159 
    160 inline void uint128::Initialize(uint64 top, uint64 bottom) {
    161   hi_ = top;
    162   lo_ = bottom;
    163 }
    164 
    165 // Comparison operators.
    166 
    167 #define CMP128(op)                                                \
    168 inline bool operator op(const uint128& lhs, const uint128& rhs) { \
    169   return (Uint128High64(lhs) == Uint128High64(rhs)) ?             \
    170       (Uint128Low64(lhs) op Uint128Low64(rhs)) :                  \
    171       (Uint128High64(lhs) op Uint128High64(rhs));                 \
    172 }
    173 
    174 CMP128(<)
    175 CMP128(>)
    176 CMP128(>=)
    177 CMP128(<=)
    178 
    179 #undef CMP128
    180 
    181 // Unary operators
    182 
    183 inline uint128 operator-(const uint128& val) {
    184   const uint64 hi_flip = ~Uint128High64(val);
    185   const uint64 lo_flip = ~Uint128Low64(val);
    186   const uint64 lo_add = lo_flip + 1;
    187   if (lo_add < lo_flip) {
    188     return uint128(hi_flip + 1, lo_add);
    189   }
    190   return uint128(hi_flip, lo_add);
    191 }
    192 
    193 inline bool operator!(const uint128& val) {
    194   return !Uint128High64(val) && !Uint128Low64(val);
    195 }
    196 
    197 // Logical operators.
    198 
    199 inline uint128 operator~(const uint128& val) {
    200   return uint128(~Uint128High64(val), ~Uint128Low64(val));
    201 }
    202 
    203 #define LOGIC128(op)                                                 \
    204 inline uint128 operator op(const uint128& lhs, const uint128& rhs) { \
    205   return uint128(Uint128High64(lhs) op Uint128High64(rhs),           \
    206                  Uint128Low64(lhs) op Uint128Low64(rhs));            \
    207 }
    208 
    209 LOGIC128(|)
    210 LOGIC128(&)
    211 LOGIC128(^)
    212 
    213 #undef LOGIC128
    214 
    215 #define LOGICASSIGN128(op)                                   \
    216 inline uint128& uint128::operator op(const uint128& other) { \
    217   hi_ op other.hi_;                                          \
    218   lo_ op other.lo_;                                          \
    219   return *this;                                              \
    220 }
    221 
    222 LOGICASSIGN128(|=)
    223 LOGICASSIGN128(&=)
    224 LOGICASSIGN128(^=)
    225 
    226 #undef LOGICASSIGN128
    227 
    228 // Shift operators.
    229 
    230 inline uint128 operator<<(const uint128& val, int amount) {
    231   // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
    232   if (amount < 64) {
    233     if (amount == 0) {
    234       return val;
    235     }
    236     uint64 new_hi = (Uint128High64(val) << amount) |
    237                     (Uint128Low64(val) >> (64 - amount));
    238     uint64 new_lo = Uint128Low64(val) << amount;
    239     return uint128(new_hi, new_lo);
    240   } else if (amount < 128) {
    241     return uint128(Uint128Low64(val) << (amount - 64), 0);
    242   } else {
    243     return uint128(0, 0);
    244   }
    245 }
    246 
    247 inline uint128 operator>>(const uint128& val, int amount) {
    248   // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
    249   if (amount < 64) {
    250     if (amount == 0) {
    251       return val;
    252     }
    253     uint64 new_hi = Uint128High64(val) >> amount;
    254     uint64 new_lo = (Uint128Low64(val) >> amount) |
    255                     (Uint128High64(val) << (64 - amount));
    256     return uint128(new_hi, new_lo);
    257   } else if (amount < 128) {
    258     return uint128(0, Uint128High64(val) >> (amount - 64));
    259   } else {
    260     return uint128(0, 0);
    261   }
    262 }
    263 
    264 inline uint128& uint128::operator<<=(int amount) {
    265   // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
    266   if (amount < 64) {
    267     if (amount != 0) {
    268       hi_ = (hi_ << amount) | (lo_ >> (64 - amount));
    269       lo_ = lo_ << amount;
    270     }
    271   } else if (amount < 128) {
    272     hi_ = lo_ << (amount - 64);
    273     lo_ = 0;
    274   } else {
    275     hi_ = 0;
    276     lo_ = 0;
    277   }
    278   return *this;
    279 }
    280 
    281 inline uint128& uint128::operator>>=(int amount) {
    282   // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
    283   if (amount < 64) {
    284     if (amount != 0) {
    285       lo_ = (lo_ >> amount) | (hi_ << (64 - amount));
    286       hi_ = hi_ >> amount;
    287     }
    288   } else if (amount < 128) {
    289     lo_ = hi_ >> (amount - 64);
    290     hi_ = 0;
    291   } else {
    292     lo_ = 0;
    293     hi_ = 0;
    294   }
    295   return *this;
    296 }
    297 
    298 inline uint128 operator+(const uint128& lhs, const uint128& rhs) {
    299   return uint128(lhs) += rhs;
    300 }
    301 
    302 inline uint128 operator-(const uint128& lhs, const uint128& rhs) {
    303   return uint128(lhs) -= rhs;
    304 }
    305 
    306 inline uint128 operator*(const uint128& lhs, const uint128& rhs) {
    307   return uint128(lhs) *= rhs;
    308 }
    309 
    310 inline uint128 operator/(const uint128& lhs, const uint128& rhs) {
    311   return uint128(lhs) /= rhs;
    312 }
    313 
    314 inline uint128 operator%(const uint128& lhs, const uint128& rhs) {
    315   return uint128(lhs) %= rhs;
    316 }
    317 
    318 inline uint128& uint128::operator+=(const uint128& b) {
    319   hi_ += b.hi_;
    320   uint64 lolo = lo_ + b.lo_;
    321   if (lolo < lo_)
    322     ++hi_;
    323   lo_ = lolo;
    324   return *this;
    325 }
    326 
    327 inline uint128& uint128::operator-=(const uint128& b) {
    328   hi_ -= b.hi_;
    329   if (b.lo_ > lo_)
    330     --hi_;
    331   lo_ -= b.lo_;
    332   return *this;
    333 }
    334 
    335 inline uint128& uint128::operator*=(const uint128& b) {
    336   uint64 a96 = hi_ >> 32;
    337   uint64 a64 = hi_ & 0xffffffffu;
    338   uint64 a32 = lo_ >> 32;
    339   uint64 a00 = lo_ & 0xffffffffu;
    340   uint64 b96 = b.hi_ >> 32;
    341   uint64 b64 = b.hi_ & 0xffffffffu;
    342   uint64 b32 = b.lo_ >> 32;
    343   uint64 b00 = b.lo_ & 0xffffffffu;
    344   // multiply [a96 .. a00] x [b96 .. b00]
    345   // terms higher than c96 disappear off the high side
    346   // terms c96 and c64 are safe to ignore carry bit
    347   uint64 c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96;
    348   uint64 c64 = a64 * b00 + a32 * b32 + a00 * b64;
    349   this->hi_ = (c96 << 32) + c64;
    350   this->lo_ = 0;
    351   // add terms after this one at a time to capture carry
    352   *this += uint128(a32 * b00) << 32;
    353   *this += uint128(a00 * b32) << 32;
    354   *this += a00 * b00;
    355   return *this;
    356 }
    357 
    358 inline uint128 uint128::operator++(int) {
    359   uint128 tmp(*this);
    360   *this += 1;
    361   return tmp;
    362 }
    363 
    364 inline uint128 uint128::operator--(int) {
    365   uint128 tmp(*this);
    366   *this -= 1;
    367   return tmp;
    368 }
    369 
    370 inline uint128& uint128::operator++() {
    371   *this += 1;
    372   return *this;
    373 }
    374 
    375 inline uint128& uint128::operator--() {
    376   *this -= 1;
    377   return *this;
    378 }
    379 
    380 }  // namespace protobuf
    381 }  // namespace google
    382 
    383 #endif  // GOOGLE_PROTOBUF_STUBS_INT128_H_
    384