Home | History | Annotate | Download | only in core
      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     */
     25     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     */
     29     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     */
     38     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     */
     42     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 */
     67     SkBool  isZero() const { return (fHi | fLo) == 0; }
     68 
     69     /** Returns non-zero if the number is non-zero */
     70     SkBool  nonZero() const { return fHi | fLo; }
     71 
     72     /** Returns non-zero if the number is negative (number < 0) */
     73     SkBool  isNeg() const { return (uint32_t)fHi >> 31; }
     74 
     75     /** Returns non-zero if the number is positive (number > 0) */
     76     SkBool  isPos() const { return ~(fHi >> 31) & (fHi | fLo); }
     77 
     78     /** Returns -1,0,+1 based on the sign of the number */
     79     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 */
     94     void    setZero() { fHi = fLo = 0; }
     95 
     96     /** Set the high and low 32 bit values of the number */
     97     void    set(int32_t hi, uint32_t lo) { fHi = hi; fLo = lo; }
     98 
     99     /** Set the number to the specified 32 bit integer */
    100     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 */
    130     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 */
    139     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 */
    147     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 */
    172     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 */
    177     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