diff options
Diffstat (limited to 'include/core/Sk64.h')
-rw-r--r-- | include/core/Sk64.h | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/include/core/Sk64.h b/include/core/Sk64.h new file mode 100644 index 0000000..538ae7e --- /dev/null +++ b/include/core/Sk64.h @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef Sk64_DEFINED +#define Sk64_DEFINED + +#include "SkFixed.h" +#include "SkMath.h" + +/** \class Sk64 + + Sk64 is a 64-bit math package that does not require long long support from the compiler. +*/ +struct 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 + +#ifdef SK_DEBUG + /** @cond UNIT_TEST */ + static void UnitTest(); + /** @endcond */ +#endif +}; + +#endif + |