1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef Sk64_DEFINED 18 #define Sk64_DEFINED 19 20 #include "SkFixed.h" 21 #include "SkMath.h" 22 23 /** \class Sk64 24 25 Sk64 is a 64-bit math package that does not require long long support from the compiler. 26 */ 27 struct Sk64 { 28 int32_t fHi; //!< the high 32 bits of the number (including sign) 29 uint32_t fLo; //!< the low 32 bits of the number 30 31 /** Returns non-zero if the Sk64 can be represented as a signed 32 bit integer 32 */ 33 SkBool is32() const { return fHi == ((int32_t)fLo >> 31); } 34 35 /** Returns non-zero if the Sk64 cannot be represented as a signed 32 bit integer 36 */ 37 SkBool is64() const { return fHi != ((int32_t)fLo >> 31); } 38 39 /** Returns non-zero if the Sk64 can be represented as a signed 48 bit integer. Used to know 40 if we can shift the value down by 16 to treat it as a SkFixed. 41 */ 42 SkBool isFixed() const; 43 44 /** Return the signed 32 bit integer equivalent. Asserts that is32() returns non-zero. 45 */ 46 int32_t get32() const { SkASSERT(this->is32()); return (int32_t)fLo; } 47 48 /** Return the number >> 16. Asserts that this does not loose any significant high bits. 49 */ 50 SkFixed getFixed() const { 51 SkASSERT(this->isFixed()); 52 53 uint32_t sum = fLo + (1 << 15); 54 int32_t hi = fHi; 55 if (sum < fLo) { 56 hi += 1; 57 } 58 return (hi << 16) | (sum >> 16); 59 } 60 61 /** Return the number >> 30. Asserts that this does not loose any 62 significant high bits. 63 */ 64 SkFract getFract() const; 65 66 /** Returns the square-root of the number as a signed 32 bit value. */ 67 int32_t getSqrt() const; 68 69 /** Returns the number of leading zeros of the absolute value of this. 70 Will return in the range [0..64] 71 */ 72 int getClzAbs() const; 73 74 /** Returns non-zero if the number is zero */ 75 SkBool isZero() const { return (fHi | fLo) == 0; } 76 77 /** Returns non-zero if the number is non-zero */ 78 SkBool nonZero() const { return fHi | fLo; } 79 80 /** Returns non-zero if the number is negative (number < 0) */ 81 SkBool isNeg() const { return (uint32_t)fHi >> 31; } 82 83 /** Returns non-zero if the number is positive (number > 0) */ 84 SkBool isPos() const { return ~(fHi >> 31) & (fHi | fLo); } 85 86 /** Returns -1,0,+1 based on the sign of the number */ 87 int getSign() const { return (fHi >> 31) | Sk32ToBool(fHi | fLo); } 88 89 /** Negate the number */ 90 void negate(); 91 92 /** If the number < 0, negate the number 93 */ 94 void abs(); 95 96 /** Returns the number of bits needed to shift the Sk64 to the right 97 in order to make it fit in a signed 32 bit integer. 98 */ 99 int shiftToMake32() const; 100 101 /** Set the number to zero */ 102 void setZero() { fHi = fLo = 0; } 103 104 /** Set the high and low 32 bit values of the number */ 105 void set(int32_t hi, uint32_t lo) { fHi = hi; fLo = lo; } 106 107 /** Set the number to the specified 32 bit integer */ 108 void set(int32_t a) { fHi = a >> 31; fLo = a; } 109 110 /** Set the number to the product of the two 32 bit integers */ 111 void setMul(int32_t a, int32_t b); 112 113 /** extract 32bits after shifting right by bitCount. 114 Note: itCount must be [0..63]. 115 Asserts that no significant high bits were lost. 116 */ 117 int32_t getShiftRight(unsigned bitCount) const; 118 119 /** Shift the number left by the specified number of bits. 120 @param bits How far to shift left, must be [0..63] 121 */ 122 void shiftLeft(unsigned bits); 123 124 /** Shift the number right by the specified number of bits. 125 @param bits How far to shift right, must be [0..63]. This 126 performs an arithmetic right-shift (sign extending). 127 */ 128 void shiftRight(unsigned bits); 129 130 /** Shift the number right by the specified number of bits, but 131 round the result. 132 @param bits How far to shift right, must be [0..63]. This 133 performs an arithmetic right-shift (sign extending). 134 */ 135 void roundRight(unsigned bits); 136 137 /** Add the specified 32 bit integer to the number */ 138 void add(int32_t lo) { 139 int32_t hi = lo >> 31; // 0 or -1 140 uint32_t sum = fLo + (uint32_t)lo; 141 142 fHi = fHi + hi + (sum < fLo); 143 fLo = sum; 144 } 145 146 /** Add the specified Sk64 to the number */ 147 void add(int32_t hi, uint32_t lo) { 148 uint32_t sum = fLo + lo; 149 150 fHi = fHi + hi + (sum < fLo); 151 fLo = sum; 152 } 153 154 /** Add the specified Sk64 to the number */ 155 void add(const Sk64& other) { this->add(other.fHi, other.fLo); } 156 157 /** Subtract the specified Sk64 from the number. (*this) = (*this) - num 158 */ 159 void sub(const Sk64& num); 160 161 /** Subtract the number from the specified Sk64. (*this) = num - (*this) 162 */ 163 void rsub(const Sk64& num); 164 165 /** Multiply the number by the specified 32 bit integer 166 */ 167 void mul(int32_t); 168 169 enum DivOptions { 170 kTrunc_DivOption, //!< truncate the result when calling div() 171 kRound_DivOption //!< round the result when calling div() 172 }; 173 174 /** Divide the number by the specified 32 bit integer, using the specified 175 divide option (either truncate or round). 176 */ 177 void div(int32_t, DivOptions); 178 179 /** return (this + other >> 16) as a 32bit result */ 180 SkFixed addGetFixed(const Sk64& other) const { 181 return this->addGetFixed(other.fHi, other.fLo); 182 } 183 184 /** return (this + Sk64(hi, lo) >> 16) as a 32bit result */ 185 SkFixed addGetFixed(int32_t hi, uint32_t lo) const { 186 #ifdef SK_DEBUG 187 Sk64 tmp(*this); 188 tmp.add(hi, lo); 189 #endif 190 191 uint32_t sum = fLo + lo; 192 hi += fHi + (sum < fLo); 193 lo = sum; 194 195 sum = lo + (1 << 15); 196 if (sum < lo) 197 hi += 1; 198 199 hi = (hi << 16) | (sum >> 16); 200 SkASSERT(hi == tmp.getFixed()); 201 return hi; 202 } 203 204 /** Return the result of dividing the number by denom, treating the answer 205 as a SkFixed. (*this) << 16 / denom. It is an error for denom to be 0. 206 */ 207 SkFixed getFixedDiv(const Sk64& denom) const; 208 209 friend bool operator==(const Sk64& a, const Sk64& b) { 210 return 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.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 friend bool operator>(const Sk64& a, const Sk64& b) { 226 return a.fHi > b.fHi || (a.fHi == b.fHi && a.fLo > b.fLo); 227 } 228 229 friend bool operator>=(const Sk64& a, const Sk64& b) { 230 return a.fHi > b.fHi || (a.fHi == b.fHi && a.fLo >= b.fLo); 231 } 232 233 #ifdef SkLONGLONG 234 SkLONGLONG getLongLong() const; 235 #endif 236 }; 237 238 #endif 239 240