1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
|
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef Sk64_DEFINED
#define Sk64_DEFINED
#include "SkFixed.h"
#include "SkMath.h"
/** \class Sk64
Sk64 is a 64-bit math package that does not require long long support from the compiler.
*/
struct Sk64 {
int32_t fHi; //!< the high 32 bits of the number (including sign)
uint32_t fLo; //!< the low 32 bits of the number
/** Returns non-zero if the Sk64 can be represented as a signed 32 bit integer
*/
SkBool is32() const { return fHi == ((int32_t)fLo >> 31); }
/** Returns non-zero if the Sk64 cannot be represented as a signed 32 bit integer
*/
SkBool is64() const { return fHi != ((int32_t)fLo >> 31); }
/** Returns non-zero if the Sk64 can be represented as a signed 48 bit integer. Used to know
if we can shift the value down by 16 to treat it as a SkFixed.
*/
SkBool isFixed() const;
/** Return the signed 32 bit integer equivalent. Asserts that is32() returns non-zero.
*/
int32_t get32() const { SkASSERT(this->is32()); return (int32_t)fLo; }
/** Return the number >> 16. Asserts that this does not loose any significant high bits.
*/
SkFixed getFixed() const {
SkASSERT(this->isFixed());
uint32_t sum = fLo + (1 << 15);
int32_t hi = fHi;
if (sum < fLo) {
hi += 1;
}
return (hi << 16) | (sum >> 16);
}
/** Return the number >> 30. Asserts that this does not loose any
significant high bits.
*/
SkFract getFract() const;
/** Returns the square-root of the number as a signed 32 bit value. */
int32_t getSqrt() const;
/** Returns the number of leading zeros of the absolute value of this.
Will return in the range [0..64]
*/
int getClzAbs() const;
/** Returns non-zero if the number is zero */
SkBool isZero() const { return (fHi | fLo) == 0; }
/** Returns non-zero if the number is non-zero */
SkBool nonZero() const { return fHi | fLo; }
/** Returns non-zero if the number is negative (number < 0) */
SkBool isNeg() const { return (uint32_t)fHi >> 31; }
/** Returns non-zero if the number is positive (number > 0) */
SkBool isPos() const { return ~(fHi >> 31) & (fHi | fLo); }
/** Returns -1,0,+1 based on the sign of the number */
int getSign() const { return (fHi >> 31) | Sk32ToBool(fHi | fLo); }
/** Negate the number */
void negate();
/** If the number < 0, negate the number
*/
void abs();
/** Returns the number of bits needed to shift the Sk64 to the right
in order to make it fit in a signed 32 bit integer.
*/
int shiftToMake32() const;
/** Set the number to zero */
void setZero() { fHi = fLo = 0; }
/** Set the high and low 32 bit values of the number */
void set(int32_t hi, uint32_t lo) { fHi = hi; fLo = lo; }
/** Set the number to the specified 32 bit integer */
void set(int32_t a) { fHi = a >> 31; fLo = a; }
/** Set the number to the product of the two 32 bit integers */
void setMul(int32_t a, int32_t b);
/** extract 32bits after shifting right by bitCount.
Note: itCount must be [0..63].
Asserts that no significant high bits were lost.
*/
int32_t getShiftRight(unsigned bitCount) const;
/** Shift the number left by the specified number of bits.
@param bits How far to shift left, must be [0..63]
*/
void shiftLeft(unsigned bits);
/** Shift the number right by the specified number of bits.
@param bits How far to shift right, must be [0..63]. This
performs an arithmetic right-shift (sign extending).
*/
void shiftRight(unsigned bits);
/** Shift the number right by the specified number of bits, but
round the result.
@param bits How far to shift right, must be [0..63]. This
performs an arithmetic right-shift (sign extending).
*/
void roundRight(unsigned bits);
/** Add the specified 32 bit integer to the number */
void add(int32_t lo) {
int32_t hi = lo >> 31; // 0 or -1
uint32_t sum = fLo + (uint32_t)lo;
fHi = fHi + hi + (sum < fLo);
fLo = sum;
}
/** Add the specified Sk64 to the number */
void add(int32_t hi, uint32_t lo) {
uint32_t sum = fLo + lo;
fHi = fHi + hi + (sum < fLo);
fLo = sum;
}
/** Add the specified Sk64 to the number */
void add(const Sk64& other) { this->add(other.fHi, other.fLo); }
/** Subtract the specified Sk64 from the number. (*this) = (*this) - num
*/
void sub(const Sk64& num);
/** Subtract the number from the specified Sk64. (*this) = num - (*this)
*/
void rsub(const Sk64& num);
/** Multiply the number by the specified 32 bit integer
*/
void mul(int32_t);
enum DivOptions {
kTrunc_DivOption, //!< truncate the result when calling div()
kRound_DivOption //!< round the result when calling div()
};
/** Divide the number by the specified 32 bit integer, using the specified
divide option (either truncate or round).
*/
void div(int32_t, DivOptions);
/** return (this + other >> 16) as a 32bit result */
SkFixed addGetFixed(const Sk64& other) const {
return this->addGetFixed(other.fHi, other.fLo);
}
/** return (this + Sk64(hi, lo) >> 16) as a 32bit result */
SkFixed addGetFixed(int32_t hi, uint32_t lo) const {
#ifdef SK_DEBUG
Sk64 tmp(*this);
tmp.add(hi, lo);
#endif
uint32_t sum = fLo + lo;
hi += fHi + (sum < fLo);
lo = sum;
sum = lo + (1 << 15);
if (sum < lo)
hi += 1;
hi = (hi << 16) | (sum >> 16);
SkASSERT(hi == tmp.getFixed());
return hi;
}
/** Return the result of dividing the number by denom, treating the answer
as a SkFixed. (*this) << 16 / denom. It is an error for denom to be 0.
*/
SkFixed getFixedDiv(const Sk64& denom) const;
friend bool operator==(const Sk64& a, const Sk64& b) {
return a.fHi == b.fHi && a.fLo == b.fLo;
}
friend bool operator!=(const Sk64& a, const Sk64& b) {
return a.fHi != b.fHi || a.fLo != b.fLo;
}
friend bool operator<(const Sk64& a, const Sk64& b) {
return a.fHi < b.fHi || (a.fHi == b.fHi && a.fLo < b.fLo);
}
friend bool operator<=(const Sk64& a, const Sk64& b) {
return a.fHi < b.fHi || (a.fHi == b.fHi && a.fLo <= b.fLo);
}
friend bool operator>(const Sk64& a, const Sk64& b) {
return a.fHi > b.fHi || (a.fHi == b.fHi && a.fLo > b.fLo);
}
friend bool operator>=(const Sk64& a, const Sk64& b) {
return a.fHi > b.fHi || (a.fHi == b.fHi && a.fLo >= b.fLo);
}
#ifdef SkLONGLONG
SkLONGLONG getLongLong() const;
#endif
};
#endif
|