blob: c4ae41eb68f56ef157ea9d8d8365ccdf2de98a7f [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
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*/
27struct 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 sign() 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#ifdef SK_DEBUG
238 /** @cond UNIT_TEST */
239 static void UnitTest();
240 /** @endcond */
241#endif
242};
243
244#endif
245