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*/
19struct 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