• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef ASTC_CODEC_BASE_UINT128_H_
16 #define ASTC_CODEC_BASE_UINT128_H_
17 
18 #include <cassert>
19 #include <cstdint>
20 
21 namespace astc_codec {
22 namespace base {
23 
24 class UInt128 {
25  public:
26   UInt128() = default;
UInt128(uint64_t low)27   UInt128(uint64_t low) : low_(low) { }
UInt128(uint64_t high,uint64_t low)28   UInt128(uint64_t high, uint64_t low) : low_(low), high_(high) { }
UInt128(const UInt128 & other)29   UInt128(const UInt128& other) : low_(other.low_), high_(other.high_) { }
30 
LowBits()31   uint64_t LowBits() const { return low_; }
HighBits()32   uint64_t HighBits() const { return high_; }
33 
34   // Allow explicit casts to uint64_t.
uint64_t()35   explicit operator uint64_t() const { return low_; }
36 
37   // Copy operators.
38   UInt128& operator=(const UInt128& other) {
39     high_ = other.high_;
40     low_ = other.low_;
41     return *this;
42   }
43 
44   // Equality operators.
45   bool operator==(const UInt128& other) const {
46     return high_ == other.high_ && low_ == other.low_;
47   }
48 
49   bool operator!=(const UInt128& other) const {
50     return high_ != other.high_ || low_ != other.low_;
51   }
52 
53   // Shifting.
54   UInt128& operator<<=(int shift) {
55     high_ = shift >= 64 ? (shift >= 128 ? 0 : low_ << (shift - 64))
56                         : high_ << shift;
57 
58     if (shift > 0 && shift < 64) {
59       const uint64_t overlappingBits = low_ >> (64 - shift);
60       high_ |= overlappingBits;
61     }
62 
63     low_ = shift >= 64 ? 0 : low_ << shift;
64     return *this;
65   }
66 
67   UInt128 operator<<(int shift) const {
68     UInt128 result = *this;
69     result <<= shift;
70     return result;
71   }
72 
73   UInt128& operator>>=(int shift) {
74     low_ = shift >= 64 ? (shift >= 128 ? 0 : high_ >> (shift - 64))
75                        : low_ >> shift;
76 
77     if (shift > 0 && shift < 64) {
78       const uint64_t overlappingBits = high_ << (64 - shift);
79       low_ |= overlappingBits;
80     }
81 
82     high_ = shift >= 64 ? 0 : high_ >> shift;
83 
84     return *this;
85   }
86 
87   UInt128 operator>>(int shift) const {
88     UInt128 result = *this;
89     result >>= shift;
90     return result;
91   }
92 
93   // Binary operations.
94   UInt128& operator|=(const UInt128& other) {
95     high_ |= other.high_;
96     low_ |= other.low_;
97     return *this;
98   }
99 
100   UInt128 operator|(const UInt128& other) const {
101     UInt128 result = *this;
102     result |= other;
103     return result;
104   }
105 
106   UInt128& operator&=(const UInt128& other) {
107     high_ &= other.high_;
108     low_ &= other.low_;
109     return *this;
110   }
111 
112   UInt128 operator&(const UInt128& other) const {
113     UInt128 result = *this;
114     result &= other;
115     return result;
116   }
117 
118   UInt128& operator^=(const UInt128& other) {
119     high_ ^= other.high_;
120     low_ ^= other.low_;
121     return *this;
122   }
123 
124   UInt128 operator^(const UInt128& other) const {
125     UInt128 result = *this;
126     result ^= other;
127     return result;
128   }
129 
130   UInt128 operator~() const {
131     UInt128 result = *this;
132     result.high_ = ~high_;
133     result.low_ = ~low_;
134     return result;
135   }
136 
137   // Addition/subtraction.
138   UInt128& operator+=(const UInt128& other) {
139     const uint64_t carry =
140         (((low_ & other.low_) & 1) + (low_ >> 1) + (other.low_ >> 1)) >> 63;
141     high_ += other.high_ + carry;
142     low_ += other.low_;
143     return *this;
144   }
145 
146   UInt128 operator+(const UInt128& other) const {
147     UInt128 result = *this;
148     result += other;
149     return result;
150   }
151 
152   UInt128& operator-=(const UInt128& other) {
153     low_ -= other.low_;
154     const uint64_t carry =
155         (((low_ & other.low_) & 1) + (low_ >> 1) + (other.low_ >> 1)) >> 63;
156     high_ -= other.high_ + carry;
157     return *this;
158   }
159 
160   UInt128 operator-(const UInt128& other) const {
161     UInt128 result = *this;
162     result -= other;
163     return result;
164   }
165 
166  private:
167   // TODO(google): Different order for little endian.
168   uint64_t low_ = 0;
169   uint64_t high_ = 0;
170 };
171 
172 }  // namespace base
173 }  // namespace astc_codec
174 
175 #endif  // ASTC_CODEC_BASE_UINT128_H_
176