1 2 /* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #ifndef Sk64_DEFINED 11 #define Sk64_DEFINED 12 13 #include "SkFixed.h" 14 15 /** \class Sk64 16 17 Sk64 is a 64-bit math package that does not require long long support from the compiler. 18 */ 19 struct SK_API Sk64 { 20 int32_t fHi; //!< the high 32 bits of the number (including sign) 21 uint32_t fLo; //!< the low 32 bits of the number 22 23 /** Returns non-zero if the Sk64 can be represented as a signed 32 bit integer 24 */ is32Sk6425 SkBool is32() const { return fHi == ((int32_t)fLo >> 31); } 26 27 /** Returns non-zero if the Sk64 cannot be represented as a signed 32 bit integer 28 */ is64Sk6429 SkBool is64() const { return fHi != ((int32_t)fLo >> 31); } 30 31 /** Returns non-zero if the Sk64 can be represented as a signed 48 bit integer. Used to know 32 if we can shift the value down by 16 to treat it as a SkFixed. 33 */ 34 SkBool isFixed() const; 35 36 /** Return the signed 32 bit integer equivalent. Asserts that is32() returns non-zero. 37 */ get32Sk6438 int32_t get32() const { SkASSERT(this->is32()); return (int32_t)fLo; } 39 40 /** Return the number >> 16. Asserts that this does not loose any significant high bits. 41 */ getFixedSk6442 SkFixed getFixed() const { 43 SkASSERT(this->isFixed()); 44 45 uint32_t sum = fLo + (1 << 15); 46 int32_t hi = fHi; 47 if (sum < fLo) { 48 hi += 1; 49 } 50 return (hi << 16) | (sum >> 16); 51 } 52 53 /** Return the number >> 30. Asserts that this does not loose any 54 significant high bits. 55 */ 56 SkFract getFract() const; 57 58 /** Returns the square-root of the number as a signed 32 bit value. */ 59 int32_t getSqrt() const; 60 61 /** Returns the number of leading zeros of the absolute value of this. 62 Will return in the range [0..64] 63 */ 64 int getClzAbs() const; 65 66 /** Returns non-zero if the number is zero */ isZeroSk6467 SkBool isZero() const { return (fHi | fLo) == 0; } 68 69 /** Returns non-zero if the number is non-zero */ nonZeroSk6470 SkBool nonZero() const { return fHi | fLo; } 71 72 /** Returns non-zero if the number is negative (number < 0) */ isNegSk6473 SkBool isNeg() const { return (uint32_t)fHi >> 31; } 74 75 /** Returns non-zero if the number is positive (number > 0) */ isPosSk6476 SkBool isPos() const { return ~(fHi >> 31) & (fHi | fLo); } 77 78 /** Returns -1,0,+1 based on the sign of the number */ getSignSk6479 int getSign() const { return (fHi >> 31) | Sk32ToBool(fHi | fLo); } 80 81 /** Negate the number */ 82 void negate(); 83 84 /** If the number < 0, negate the number 85 */ 86 void abs(); 87 88 /** Returns the number of bits needed to shift the Sk64 to the right 89 in order to make it fit in a signed 32 bit integer. 90 */ 91 int shiftToMake32() const; 92 93 /** Set the number to zero */ setZeroSk6494 void setZero() { fHi = fLo = 0; } 95 96 /** Set the high and low 32 bit values of the number */ setSk6497 void set(int32_t hi, uint32_t lo) { fHi = hi; fLo = lo; } 98 99 /** Set the number to the specified 32 bit integer */ setSk64100 void set(int32_t a) { fHi = a >> 31; fLo = a; } 101 102 /** Set the number to the product of the two 32 bit integers */ 103 void setMul(int32_t a, int32_t b); 104 105 /** extract 32bits after shifting right by bitCount. 106 Note: itCount must be [0..63]. 107 Asserts that no significant high bits were lost. 108 */ 109 int32_t getShiftRight(unsigned bitCount) const; 110 111 /** Shift the number left by the specified number of bits. 112 @param bits How far to shift left, must be [0..63] 113 */ 114 void shiftLeft(unsigned bits); 115 116 /** Shift the number right by the specified number of bits. 117 @param bits How far to shift right, must be [0..63]. This 118 performs an arithmetic right-shift (sign extending). 119 */ 120 void shiftRight(unsigned bits); 121 122 /** Shift the number right by the specified number of bits, but 123 round the result. 124 @param bits How far to shift right, must be [0..63]. This 125 performs an arithmetic right-shift (sign extending). 126 */ 127 void roundRight(unsigned bits); 128 129 /** Add the specified 32 bit integer to the number */ addSk64130 void add(int32_t lo) { 131 int32_t hi = lo >> 31; // 0 or -1 132 uint32_t sum = fLo + (uint32_t)lo; 133 134 fHi = fHi + hi + (sum < fLo); 135 fLo = sum; 136 } 137 138 /** Add the specified Sk64 to the number */ addSk64139 void add(int32_t hi, uint32_t lo) { 140 uint32_t sum = fLo + lo; 141 142 fHi = fHi + hi + (sum < fLo); 143 fLo = sum; 144 } 145 146 /** Add the specified Sk64 to the number */ addSk64147 void add(const Sk64& other) { this->add(other.fHi, other.fLo); } 148 149 /** Subtract the specified Sk64 from the number. (*this) = (*this) - num 150 */ 151 void sub(const Sk64& num); 152 153 /** Subtract the number from the specified Sk64. (*this) = num - (*this) 154 */ 155 void rsub(const Sk64& num); 156 157 /** Multiply the number by the specified 32 bit integer 158 */ 159 void mul(int32_t); 160 161 enum DivOptions { 162 kTrunc_DivOption, //!< truncate the result when calling div() 163 kRound_DivOption //!< round the result when calling div() 164 }; 165 166 /** Divide the number by the specified 32 bit integer, using the specified 167 divide option (either truncate or round). 168 */ 169 void div(int32_t, DivOptions); 170 171 /** return (this + other >> 16) as a 32bit result */ addGetFixedSk64172 SkFixed addGetFixed(const Sk64& other) const { 173 return this->addGetFixed(other.fHi, other.fLo); 174 } 175 176 /** return (this + Sk64(hi, lo) >> 16) as a 32bit result */ addGetFixedSk64177 SkFixed addGetFixed(int32_t hi, uint32_t lo) const { 178 #ifdef SK_DEBUG 179 Sk64 tmp(*this); 180 tmp.add(hi, lo); 181 #endif 182 183 uint32_t sum = fLo + lo; 184 hi += fHi + (sum < fLo); 185 lo = sum; 186 187 sum = lo + (1 << 15); 188 if (sum < lo) 189 hi += 1; 190 191 hi = (hi << 16) | (sum >> 16); 192 SkASSERT(hi == tmp.getFixed()); 193 return hi; 194 } 195 196 /** Return the result of dividing the number by denom, treating the answer 197 as a SkFixed. (*this) << 16 / denom. It is an error for denom to be 0. 198 */ 199 SkFixed getFixedDiv(const Sk64& denom) const; 200 201 friend bool operator==(const Sk64& a, const Sk64& b) { 202 return a.fHi == b.fHi && a.fLo == b.fLo; 203 } 204 205 friend bool operator!=(const Sk64& a, const Sk64& b) { 206 return a.fHi != b.fHi || a.fLo != b.fLo; 207 } 208 209 friend bool operator<(const Sk64& a, const Sk64& b) { 210 return a.fHi < b.fHi || (a.fHi == b.fHi && a.fLo < b.fLo); 211 } 212 213 friend bool operator<=(const Sk64& a, const Sk64& b) { 214 return a.fHi < b.fHi || (a.fHi == b.fHi && a.fLo <= b.fLo); 215 } 216 217 friend bool operator>(const Sk64& a, const Sk64& b) { 218 return a.fHi > b.fHi || (a.fHi == b.fHi && a.fLo > b.fLo); 219 } 220 221 friend bool operator>=(const Sk64& a, const Sk64& b) { 222 return a.fHi > b.fHi || (a.fHi == b.fHi && a.fLo >= b.fLo); 223 } 224 225 #ifdef SkLONGLONG 226 SkLONGLONG getLongLong() const; 227 #endif 228 }; 229 230 #endif 231 232