9
9
#ifndef LLVM_LIBC_SRC___SUPPORT_HIGH_PRECISION_DECIMAL_H
10
10
#define LLVM_LIBC_SRC___SUPPORT_HIGH_PRECISION_DECIMAL_H
11
11
12
+ #include " src/__support/CPP/limits.h"
12
13
#include " src/__support/ctype_utils.h"
13
14
#include " src/__support/str_to_integer.h"
14
15
#include < stdint.h>
@@ -115,9 +116,10 @@ class HighPrecisionDecimal {
115
116
uint8_t digits[MAX_NUM_DIGITS];
116
117
117
118
private:
118
- bool should_round_up (int32_t roundToDigit, RoundDirection round) {
119
- if (roundToDigit < 0 ||
120
- static_cast <uint32_t >(roundToDigit) >= this ->num_digits ) {
119
+ LIBC_INLINE bool should_round_up (int32_t round_to_digit,
120
+ RoundDirection round) {
121
+ if (round_to_digit < 0 ||
122
+ static_cast <uint32_t >(round_to_digit) >= this ->num_digits ) {
121
123
return false ;
122
124
}
123
125
@@ -133,8 +135,8 @@ class HighPrecisionDecimal {
133
135
// Else round to nearest.
134
136
135
137
// If we're right in the middle and there are no extra digits
136
- if (this ->digits [roundToDigit ] == 5 &&
137
- static_cast <uint32_t >(roundToDigit + 1 ) == this ->num_digits ) {
138
+ if (this ->digits [round_to_digit ] == 5 &&
139
+ static_cast <uint32_t >(round_to_digit + 1 ) == this ->num_digits ) {
138
140
139
141
// Round up if we've truncated (since that means the result is slightly
140
142
// higher than what's represented.)
@@ -143,22 +145,22 @@ class HighPrecisionDecimal {
143
145
}
144
146
145
147
// If this exactly halfway, round to even.
146
- if (roundToDigit == 0 )
148
+ if (round_to_digit == 0 )
147
149
// When the input is ".5".
148
150
return false ;
149
- return this ->digits [roundToDigit - 1 ] % 2 != 0 ;
151
+ return this ->digits [round_to_digit - 1 ] % 2 != 0 ;
150
152
}
151
- // If there are digits after roundToDigit , they must be non-zero since we
153
+ // If there are digits after round_to_digit , they must be non-zero since we
152
154
// trim trailing zeroes after all operations that change digits.
153
- return this ->digits [roundToDigit ] >= 5 ;
155
+ return this ->digits [round_to_digit ] >= 5 ;
154
156
}
155
157
156
158
// Takes an amount to left shift and returns the number of new digits needed
157
159
// to store the result based on LEFT_SHIFT_DIGIT_TABLE.
158
- uint32_t get_num_new_digits (uint32_t lShiftAmount ) {
160
+ LIBC_INLINE uint32_t get_num_new_digits (uint32_t lshift_amount ) {
159
161
const char *power_of_five =
160
- LEFT_SHIFT_DIGIT_TABLE[lShiftAmount ].power_of_five ;
161
- uint32_t new_digits = LEFT_SHIFT_DIGIT_TABLE[lShiftAmount ].new_digits ;
162
+ LEFT_SHIFT_DIGIT_TABLE[lshift_amount ].power_of_five ;
163
+ uint32_t new_digits = LEFT_SHIFT_DIGIT_TABLE[lshift_amount ].new_digits ;
162
164
uint32_t digit_index = 0 ;
163
165
while (power_of_five[digit_index] != 0 ) {
164
166
if (digit_index >= this ->num_digits ) {
@@ -176,7 +178,7 @@ class HighPrecisionDecimal {
176
178
}
177
179
178
180
// Trim all trailing 0s
179
- void trim_trailing_zeroes () {
181
+ LIBC_INLINE void trim_trailing_zeroes () {
180
182
while (this ->num_digits > 0 && this ->digits [this ->num_digits - 1 ] == 0 ) {
181
183
--this ->num_digits ;
182
184
}
@@ -186,19 +188,19 @@ class HighPrecisionDecimal {
186
188
}
187
189
188
190
// Perform a digitwise binary non-rounding right shift on this value by
189
- // shiftAmount . The shiftAmount can't be more than MAX_SHIFT_AMOUNT to prevent
190
- // overflow.
191
- void right_shift (uint32_t shiftAmount ) {
191
+ // shift_amount . The shift_amount can't be more than MAX_SHIFT_AMOUNT to
192
+ // prevent overflow.
193
+ LIBC_INLINE void right_shift (uint32_t shift_amount ) {
192
194
uint32_t read_index = 0 ;
193
195
uint32_t write_index = 0 ;
194
196
195
197
uint64_t accumulator = 0 ;
196
198
197
- const uint64_t shift_mask = (uint64_t (1 ) << shiftAmount ) - 1 ;
199
+ const uint64_t shift_mask = (uint64_t (1 ) << shift_amount ) - 1 ;
198
200
199
201
// Warm Up phase: we don't have enough digits to start writing, so just
200
202
// read them into the accumulator.
201
- while (accumulator >> shiftAmount == 0 ) {
203
+ while (accumulator >> shift_amount == 0 ) {
202
204
uint64_t read_digit = 0 ;
203
205
// If there are still digits to read, read the next one, else the digit is
204
206
// assumed to be 0.
@@ -217,7 +219,7 @@ class HighPrecisionDecimal {
217
219
// read. Keep reading until we run out of digits.
218
220
while (read_index < this ->num_digits ) {
219
221
uint64_t read_digit = this ->digits [read_index];
220
- uint64_t write_digit = accumulator >> shiftAmount ;
222
+ uint64_t write_digit = accumulator >> shift_amount ;
221
223
accumulator &= shift_mask;
222
224
this ->digits [write_index] = static_cast <uint8_t >(write_digit);
223
225
accumulator = accumulator * 10 + read_digit;
@@ -228,7 +230,7 @@ class HighPrecisionDecimal {
228
230
// Cool Down phase: All of the readable digits have been read, so just write
229
231
// the remainder, while treating any more digits as 0.
230
232
while (accumulator > 0 ) {
231
- uint64_t write_digit = accumulator >> shiftAmount ;
233
+ uint64_t write_digit = accumulator >> shift_amount ;
232
234
accumulator &= shift_mask;
233
235
if (write_index < MAX_NUM_DIGITS) {
234
236
this ->digits [write_index] = static_cast <uint8_t >(write_digit);
@@ -243,10 +245,10 @@ class HighPrecisionDecimal {
243
245
}
244
246
245
247
// Perform a digitwise binary non-rounding left shift on this value by
246
- // shiftAmount . The shiftAmount can't be more than MAX_SHIFT_AMOUNT to prevent
247
- // overflow.
248
- void left_shift (uint32_t shiftAmount ) {
249
- uint32_t new_digits = this ->get_num_new_digits (shiftAmount );
248
+ // shift_amount . The shift_amount can't be more than MAX_SHIFT_AMOUNT to
249
+ // prevent overflow.
250
+ LIBC_INLINE void left_shift (uint32_t shift_amount ) {
251
+ uint32_t new_digits = this ->get_num_new_digits (shift_amount );
250
252
251
253
int32_t read_index = this ->num_digits - 1 ;
252
254
uint32_t write_index = this ->num_digits + new_digits;
@@ -260,7 +262,7 @@ class HighPrecisionDecimal {
260
262
// writing.
261
263
while (read_index >= 0 ) {
262
264
accumulator += static_cast <uint64_t >(this ->digits [read_index])
263
- << shiftAmount ;
265
+ << shift_amount ;
264
266
uint64_t next_accumulator = accumulator / 10 ;
265
267
uint64_t write_digit = accumulator - (10 * next_accumulator);
266
268
--write_index;
@@ -296,45 +298,52 @@ class HighPrecisionDecimal {
296
298
}
297
299
298
300
public:
299
- // numString is assumed to be a string of numeric characters. It doesn't
301
+ // num_string is assumed to be a string of numeric characters. It doesn't
300
302
// handle leading spaces.
301
- HighPrecisionDecimal (const char *__restrict numString) {
303
+ LIBC_INLINE
304
+ HighPrecisionDecimal (
305
+ const char *__restrict num_string,
306
+ const size_t num_len = cpp::numeric_limits<size_t >::max()) {
302
307
bool saw_dot = false ;
308
+ size_t num_cur = 0 ;
303
309
// This counts the digits in the number, even if there isn't space to store
304
310
// them all.
305
311
uint32_t total_digits = 0 ;
306
- while (isdigit (*numString) || *numString == ' .' ) {
307
- if (*numString == ' .' ) {
312
+ while (num_cur < num_len &&
313
+ (isdigit (num_string[num_cur]) || num_string[num_cur] == ' .' )) {
314
+ if (num_string[num_cur] == ' .' ) {
308
315
if (saw_dot) {
309
316
break ;
310
317
}
311
318
this ->decimal_point = total_digits;
312
319
saw_dot = true ;
313
320
} else {
314
- if (*numString == ' 0' && this ->num_digits == 0 ) {
321
+ if (num_string[num_cur] == ' 0' && this ->num_digits == 0 ) {
315
322
--this ->decimal_point ;
316
- ++numString ;
323
+ ++num_cur ;
317
324
continue ;
318
325
}
319
326
++total_digits;
320
327
if (this ->num_digits < MAX_NUM_DIGITS) {
321
328
this ->digits [this ->num_digits ] =
322
- static_cast <uint8_t >(*numString - ' 0' );
329
+ static_cast <uint8_t >(num_string[num_cur] - ' 0' );
323
330
++this ->num_digits ;
324
- } else if (*numString != ' 0' ) {
331
+ } else if (num_string[num_cur] != ' 0' ) {
325
332
this ->truncated = true ;
326
333
}
327
334
}
328
- ++numString ;
335
+ ++num_cur ;
329
336
}
330
337
331
338
if (!saw_dot)
332
339
this ->decimal_point = total_digits;
333
340
334
- if ((*numString | 32 ) == ' e' ) {
335
- ++numString;
336
- if (isdigit (*numString) || *numString == ' +' || *numString == ' -' ) {
337
- auto result = strtointeger<int32_t >(numString, 10 );
341
+ if (num_cur < num_len && ((num_string[num_cur] | 32 ) == ' e' )) {
342
+ ++num_cur;
343
+ if (isdigit (num_string[num_cur]) || num_string[num_cur] == ' +' ||
344
+ num_string[num_cur] == ' -' ) {
345
+ auto result =
346
+ strtointeger<int32_t >(num_string + num_cur, 10 , num_len - num_cur);
338
347
if (result.has_error ()) {
339
348
// TODO: handle error
340
349
}
@@ -358,33 +367,34 @@ class HighPrecisionDecimal {
358
367
this ->trim_trailing_zeroes ();
359
368
}
360
369
361
- // Binary shift left (shiftAmount > 0) or right (shiftAmount < 0)
362
- void shift (int shiftAmount ) {
363
- if (shiftAmount == 0 ) {
370
+ // Binary shift left (shift_amount > 0) or right (shift_amount < 0)
371
+ LIBC_INLINE void shift (int shift_amount ) {
372
+ if (shift_amount == 0 ) {
364
373
return ;
365
374
}
366
375
// Left
367
- else if (shiftAmount > 0 ) {
368
- while (static_cast <uint32_t >(shiftAmount ) > MAX_SHIFT_AMOUNT) {
376
+ else if (shift_amount > 0 ) {
377
+ while (static_cast <uint32_t >(shift_amount ) > MAX_SHIFT_AMOUNT) {
369
378
this ->left_shift (MAX_SHIFT_AMOUNT);
370
- shiftAmount -= MAX_SHIFT_AMOUNT;
379
+ shift_amount -= MAX_SHIFT_AMOUNT;
371
380
}
372
- this ->left_shift (shiftAmount );
381
+ this ->left_shift (shift_amount );
373
382
}
374
383
// Right
375
384
else {
376
- while (static_cast <uint32_t >(shiftAmount ) < -MAX_SHIFT_AMOUNT) {
385
+ while (static_cast <uint32_t >(shift_amount ) < -MAX_SHIFT_AMOUNT) {
377
386
this ->right_shift (MAX_SHIFT_AMOUNT);
378
- shiftAmount += MAX_SHIFT_AMOUNT;
387
+ shift_amount += MAX_SHIFT_AMOUNT;
379
388
}
380
- this ->right_shift (-shiftAmount );
389
+ this ->right_shift (-shift_amount );
381
390
}
382
391
}
383
392
384
393
// Round the number represented to the closest value of unsigned int type T.
385
394
// This is done ignoring overflow.
386
395
template <class T >
387
- T round_to_integer_type (RoundDirection round = RoundDirection::Nearest) {
396
+ LIBC_INLINE T
397
+ round_to_integer_type (RoundDirection round = RoundDirection::Nearest) {
388
398
T result = 0 ;
389
399
uint32_t cur_digit = 0 ;
390
400
@@ -404,10 +414,10 @@ class HighPrecisionDecimal {
404
414
405
415
// Extra functions for testing.
406
416
407
- uint8_t *get_digits () { return this ->digits ; }
408
- uint32_t get_num_digits () { return this ->num_digits ; }
409
- int32_t get_decimal_point () { return this ->decimal_point ; }
410
- void set_truncated (bool trunc) { this ->truncated = trunc; }
417
+ LIBC_INLINE uint8_t *get_digits () { return this ->digits ; }
418
+ LIBC_INLINE uint32_t get_num_digits () { return this ->num_digits ; }
419
+ LIBC_INLINE int32_t get_decimal_point () { return this ->decimal_point ; }
420
+ LIBC_INLINE void set_truncated (bool trunc) { this ->truncated = trunc; }
411
421
};
412
422
413
423
} // namespace internal
0 commit comments