| |
| /* |
| * Copyright 2006 The Android Open Source Project |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| |
| #ifndef Sk64_DEFINED |
| #define Sk64_DEFINED |
| |
| #include "SkFixed.h" |
| |
| /** \class Sk64 |
| |
| Sk64 is a 64-bit math package that does not require long long support from the compiler. |
| */ |
| struct SK_API Sk64 { |
| int32_t fHi; //!< the high 32 bits of the number (including sign) |
| uint32_t fLo; //!< the low 32 bits of the number |
| |
| /** Returns non-zero if the Sk64 can be represented as a signed 32 bit integer |
| */ |
| SkBool is32() const { return fHi == ((int32_t)fLo >> 31); } |
| |
| /** Returns non-zero if the Sk64 cannot be represented as a signed 32 bit integer |
| */ |
| SkBool is64() const { return fHi != ((int32_t)fLo >> 31); } |
| |
| /** Returns non-zero if the Sk64 can be represented as a signed 48 bit integer. Used to know |
| if we can shift the value down by 16 to treat it as a SkFixed. |
| */ |
| SkBool isFixed() const; |
| |
| /** Return the signed 32 bit integer equivalent. Asserts that is32() returns non-zero. |
| */ |
| int32_t get32() const { SkASSERT(this->is32()); return (int32_t)fLo; } |
| |
| /** Return the number >> 16. Asserts that this does not loose any significant high bits. |
| */ |
| SkFixed getFixed() const { |
| SkASSERT(this->isFixed()); |
| |
| uint32_t sum = fLo + (1 << 15); |
| int32_t hi = fHi; |
| if (sum < fLo) { |
| hi += 1; |
| } |
| return (hi << 16) | (sum >> 16); |
| } |
| |
| /** Return the number >> 30. Asserts that this does not loose any |
| significant high bits. |
| */ |
| SkFract getFract() const; |
| |
| /** Returns the square-root of the number as a signed 32 bit value. */ |
| int32_t getSqrt() const; |
| |
| /** Returns the number of leading zeros of the absolute value of this. |
| Will return in the range [0..64] |
| */ |
| int getClzAbs() const; |
| |
| /** Returns non-zero if the number is zero */ |
| SkBool isZero() const { return (fHi | fLo) == 0; } |
| |
| /** Returns non-zero if the number is non-zero */ |
| SkBool nonZero() const { return fHi | fLo; } |
| |
| /** Returns non-zero if the number is negative (number < 0) */ |
| SkBool isNeg() const { return (uint32_t)fHi >> 31; } |
| |
| /** Returns non-zero if the number is positive (number > 0) */ |
| SkBool isPos() const { return ~(fHi >> 31) & (fHi | fLo); } |
| |
| /** Returns -1,0,+1 based on the sign of the number */ |
| int getSign() const { return (fHi >> 31) | Sk32ToBool(fHi | fLo); } |
| |
| /** Negate the number */ |
| void negate(); |
| |
| /** If the number < 0, negate the number |
| */ |
| void abs(); |
| |
| /** Returns the number of bits needed to shift the Sk64 to the right |
| in order to make it fit in a signed 32 bit integer. |
| */ |
| int shiftToMake32() const; |
| |
| /** Set the number to zero */ |
| void setZero() { fHi = fLo = 0; } |
| |
| /** Set the high and low 32 bit values of the number */ |
| void set(int32_t hi, uint32_t lo) { fHi = hi; fLo = lo; } |
| |
| /** Set the number to the specified 32 bit integer */ |
| void set(int32_t a) { fHi = a >> 31; fLo = a; } |
| |
| /** Set the number to the product of the two 32 bit integers */ |
| void setMul(int32_t a, int32_t b); |
| |
| /** extract 32bits after shifting right by bitCount. |
| Note: itCount must be [0..63]. |
| Asserts that no significant high bits were lost. |
| */ |
| int32_t getShiftRight(unsigned bitCount) const; |
| |
| /** Shift the number left by the specified number of bits. |
| @param bits How far to shift left, must be [0..63] |
| */ |
| void shiftLeft(unsigned bits); |
| |
| /** Shift the number right by the specified number of bits. |
| @param bits How far to shift right, must be [0..63]. This |
| performs an arithmetic right-shift (sign extending). |
| */ |
| void shiftRight(unsigned bits); |
| |
| /** Shift the number right by the specified number of bits, but |
| round the result. |
| @param bits How far to shift right, must be [0..63]. This |
| performs an arithmetic right-shift (sign extending). |
| */ |
| void roundRight(unsigned bits); |
| |
| /** Add the specified 32 bit integer to the number */ |
| void add(int32_t lo) { |
| int32_t hi = lo >> 31; // 0 or -1 |
| uint32_t sum = fLo + (uint32_t)lo; |
| |
| fHi = fHi + hi + (sum < fLo); |
| fLo = sum; |
| } |
| |
| /** Add the specified Sk64 to the number */ |
| void add(int32_t hi, uint32_t lo) { |
| uint32_t sum = fLo + lo; |
| |
| fHi = fHi + hi + (sum < fLo); |
| fLo = sum; |
| } |
| |
| /** Add the specified Sk64 to the number */ |
| void add(const Sk64& other) { this->add(other.fHi, other.fLo); } |
| |
| /** Subtract the specified Sk64 from the number. (*this) = (*this) - num |
| */ |
| void sub(const Sk64& num); |
| |
| /** Subtract the number from the specified Sk64. (*this) = num - (*this) |
| */ |
| void rsub(const Sk64& num); |
| |
| /** Multiply the number by the specified 32 bit integer |
| */ |
| void mul(int32_t); |
| |
| enum DivOptions { |
| kTrunc_DivOption, //!< truncate the result when calling div() |
| kRound_DivOption //!< round the result when calling div() |
| }; |
| |
| /** Divide the number by the specified 32 bit integer, using the specified |
| divide option (either truncate or round). |
| */ |
| void div(int32_t, DivOptions); |
| |
| /** return (this + other >> 16) as a 32bit result */ |
| SkFixed addGetFixed(const Sk64& other) const { |
| return this->addGetFixed(other.fHi, other.fLo); |
| } |
| |
| /** return (this + Sk64(hi, lo) >> 16) as a 32bit result */ |
| SkFixed addGetFixed(int32_t hi, uint32_t lo) const { |
| #ifdef SK_DEBUG |
| Sk64 tmp(*this); |
| tmp.add(hi, lo); |
| #endif |
| |
| uint32_t sum = fLo + lo; |
| hi += fHi + (sum < fLo); |
| lo = sum; |
| |
| sum = lo + (1 << 15); |
| if (sum < lo) |
| hi += 1; |
| |
| hi = (hi << 16) | (sum >> 16); |
| SkASSERT(hi == tmp.getFixed()); |
| return hi; |
| } |
| |
| /** Return the result of dividing the number by denom, treating the answer |
| as a SkFixed. (*this) << 16 / denom. It is an error for denom to be 0. |
| */ |
| SkFixed getFixedDiv(const Sk64& denom) const; |
| |
| friend bool operator==(const Sk64& a, const Sk64& b) { |
| return a.fHi == b.fHi && a.fLo == b.fLo; |
| } |
| |
| friend bool operator!=(const Sk64& a, const Sk64& b) { |
| return a.fHi != b.fHi || a.fLo != b.fLo; |
| } |
| |
| friend bool operator<(const Sk64& a, const Sk64& b) { |
| return a.fHi < b.fHi || (a.fHi == b.fHi && a.fLo < b.fLo); |
| } |
| |
| friend bool operator<=(const Sk64& a, const Sk64& b) { |
| return a.fHi < b.fHi || (a.fHi == b.fHi && a.fLo <= b.fLo); |
| } |
| |
| friend bool operator>(const Sk64& a, const Sk64& b) { |
| return a.fHi > b.fHi || (a.fHi == b.fHi && a.fLo > b.fLo); |
| } |
| |
| friend bool operator>=(const Sk64& a, const Sk64& b) { |
| return a.fHi > b.fHi || (a.fHi == b.fHi && a.fLo >= b.fLo); |
| } |
| |
| #ifdef SkLONGLONG |
| SkLONGLONG getLongLong() const; |
| #endif |
| }; |
| |
| #endif |