• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     */
is32Sk6425     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     */
is64Sk6429     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     */
get32Sk6438     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     */
getFixedSk6442     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 */
isZeroSk6467     SkBool  isZero() const { return (fHi | fLo) == 0; }
68 
69     /** Returns non-zero if the number is non-zero */
nonZeroSk6470     SkBool  nonZero() const { return fHi | fLo; }
71 
72     /** Returns non-zero if the number is negative (number < 0) */
isNegSk6473     SkBool  isNeg() const { return (uint32_t)fHi >> 31; }
74 
75     /** Returns non-zero if the number is positive (number > 0) */
isPosSk6476     SkBool  isPos() const { return ~(fHi >> 31) & (fHi | fLo); }
77 
78     /** Returns -1,0,+1 based on the sign of the number */
getSignSk6479     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 */
setZeroSk6494     void    setZero() { fHi = fLo = 0; }
95 
96     /** Set the high and low 32 bit values of the number */
setSk6497     void    set(int32_t hi, uint32_t lo) { fHi = hi; fLo = lo; }
98 
99     /** Set the number to the specified 32 bit integer */
setSk64100     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 */
addSk64130     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 */
addSk64139     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 */
addSk64147     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 */
addGetFixedSk64172     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 */
addGetFixedSk64177     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