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 0 : 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 0 : 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 0 : 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 0 : SkBool isNeg() const { return (uint32_t)fHi >> 31; }
74 :
75 : /** Returns non-zero if the number is positive (number > 0) */
76 0 : 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 0 : void setZero() { fHi = fLo = 0; }
95 :
96 : /** Set the high and low 32 bit values of the number */
97 0 : void set(int32_t hi, uint32_t lo) { fHi = hi; fLo = lo; }
98 :
99 : /** Set the number to the specified 32 bit integer */
100 0 : 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 0 : void add(int32_t lo) {
131 0 : int32_t hi = lo >> 31; // 0 or -1
132 0 : uint32_t sum = fLo + (uint32_t)lo;
133 :
134 0 : fHi = fHi + hi + (sum < fLo);
135 0 : fLo = sum;
136 0 : }
137 :
138 : /** Add the specified Sk64 to the number */
139 0 : void add(int32_t hi, uint32_t lo) {
140 0 : uint32_t sum = fLo + lo;
141 :
142 0 : fHi = fHi + hi + (sum < fLo);
143 0 : fLo = sum;
144 0 : }
145 :
146 : /** Add the specified Sk64 to the number */
147 0 : 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 :
|