Home | History | Annotate | Download | only in core
      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 SK_API 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