34
34
#include <assert.h>
35
35
#include <stdbool.h>
36
36
#include "private.h"
37
+ #include "convert.h"
37
38
#include "zend_alloc.h"
38
39
39
40
40
- #if SIZEOF_SIZE_T >= 8
41
- # define BC_VECTOR_SIZE 8
42
- /* The boundary number is computed from BASE ** BC_VECTOR_SIZE */
43
- # define BC_VECTOR_BOUNDARY_NUM (BC_VECTOR) 100000000
44
- #else
45
- # define BC_VECTOR_SIZE 4
46
- /* The boundary number is computed from BASE ** BC_VECTOR_SIZE */
47
- # define BC_VECTOR_BOUNDARY_NUM (BC_VECTOR) 10000
48
- #endif
49
-
50
- /*
51
- * Adding more than this many times may cause uint32_t/uint64_t to overflow.
52
- * Typically this is 1844 for 64bit and 42 for 32bit.
53
- */
54
- #define BC_VECTOR_NO_OVERFLOW_ADD_COUNT (~((BC_VECTOR) 0) / (BC_VECTOR_BOUNDARY_NUM * BC_VECTOR_BOUNDARY_NUM))
55
-
56
-
57
41
/* Multiply utility routines */
58
42
59
43
static inline void bc_mul_carry_calc (BC_VECTOR * prod_vector , size_t prod_arr_size )
@@ -64,92 +48,6 @@ static inline void bc_mul_carry_calc(BC_VECTOR *prod_vector, size_t prod_arr_siz
64
48
}
65
49
}
66
50
67
- /* This is based on the technique described in https://kholdstare.github.io/technical/2020/05/26/faster-integer-parsing.html.
68
- * This function transforms AABBCCDD into 1000 * AA + 100 * BB + 10 * CC + DD,
69
- * with the caveat that all components must be in the interval [0, 25] to prevent overflow
70
- * due to the multiplication by power of 10 (10 * 25 = 250 is the largest number that fits in a byte).
71
- * The advantage of this method instead of using shifts + 3 multiplications is that this is cheaper
72
- * due to its divide-and-conquer nature.
73
- */
74
- #if SIZEOF_SIZE_T == 4
75
- static BC_VECTOR bc_parse_chunk_chars (const char * str )
76
- {
77
- BC_VECTOR tmp ;
78
- memcpy (& tmp , str , sizeof (tmp ));
79
- #if !BC_LITTLE_ENDIAN
80
- tmp = BC_BSWAP (tmp );
81
- #endif
82
-
83
- BC_VECTOR lower_digits = (tmp & 0x0f000f00 ) >> 8 ;
84
- BC_VECTOR upper_digits = (tmp & 0x000f000f ) * 10 ;
85
-
86
- tmp = lower_digits + upper_digits ;
87
-
88
- lower_digits = (tmp & 0x00ff0000 ) >> 16 ;
89
- upper_digits = (tmp & 0x000000ff ) * 100 ;
90
-
91
- return lower_digits + upper_digits ;
92
- }
93
- #elif SIZEOF_SIZE_T == 8
94
- static BC_VECTOR bc_parse_chunk_chars (const char * str )
95
- {
96
- BC_VECTOR tmp ;
97
- memcpy (& tmp , str , sizeof (tmp ));
98
- #if !BC_LITTLE_ENDIAN
99
- tmp = BC_BSWAP (tmp );
100
- #endif
101
-
102
- BC_VECTOR lower_digits = (tmp & 0x0f000f000f000f00 ) >> 8 ;
103
- BC_VECTOR upper_digits = (tmp & 0x000f000f000f000f ) * 10 ;
104
-
105
- tmp = lower_digits + upper_digits ;
106
-
107
- lower_digits = (tmp & 0x00ff000000ff0000 ) >> 16 ;
108
- upper_digits = (tmp & 0x000000ff000000ff ) * 100 ;
109
-
110
- tmp = lower_digits + upper_digits ;
111
-
112
- lower_digits = (tmp & 0x0000ffff00000000 ) >> 32 ;
113
- upper_digits = (tmp & 0x000000000000ffff ) * 10000 ;
114
-
115
- return lower_digits + upper_digits ;
116
- }
117
- #endif
118
-
119
- /*
120
- * Converts bc_num to BC_VECTOR, going backwards from pointer n by the number of
121
- * characters specified by len.
122
- */
123
- static inline BC_VECTOR bc_partial_convert_to_vector (const char * n , size_t len )
124
- {
125
- if (len == BC_VECTOR_SIZE ) {
126
- return bc_parse_chunk_chars (n - BC_VECTOR_SIZE + 1 );
127
- }
128
-
129
- BC_VECTOR num = 0 ;
130
- BC_VECTOR base = 1 ;
131
-
132
- for (size_t i = 0 ; i < len ; i ++ ) {
133
- num += * n * base ;
134
- base *= BASE ;
135
- n -- ;
136
- }
137
-
138
- return num ;
139
- }
140
-
141
- static inline void bc_convert_to_vector (BC_VECTOR * n_vector , const char * nend , size_t nlen )
142
- {
143
- size_t i = 0 ;
144
- while (nlen > 0 ) {
145
- size_t len = MIN (BC_VECTOR_SIZE , nlen );
146
- n_vector [i ] = bc_partial_convert_to_vector (nend , len );
147
- nend -= len ;
148
- nlen -= len ;
149
- i ++ ;
150
- }
151
- }
152
-
153
51
/*
154
52
* If the n_values of n1 and n2 are both 4 (32-bit) or 8 (64-bit) digits or less,
155
53
* the calculation will be performed at high speed without using an array.
@@ -174,52 +72,6 @@ static inline void bc_fast_mul(bc_num n1, size_t n1len, bc_num n2, size_t n2len,
174
72
}
175
73
}
176
74
177
- #if BC_LITTLE_ENDIAN
178
- # define BC_ENCODE_LUT (A , B ) ((A) | (B) << 4)
179
- #else
180
- # define BC_ENCODE_LUT (A , B ) ((B) | (A) << 4)
181
- #endif
182
-
183
- #define LUT_ITERATE (_ , A ) \
184
- _(A, 0), _(A, 1), _(A, 2), _(A, 3), _(A, 4), _(A, 5), _(A, 6), _(A, 7), _(A, 8), _(A, 9)
185
-
186
- /* This LUT encodes the decimal representation of numbers 0-100
187
- * such that we can avoid taking modulos and divisions which would be slow. */
188
- static const unsigned char LUT [100 ] = {
189
- LUT_ITERATE (BC_ENCODE_LUT , 0 ),
190
- LUT_ITERATE (BC_ENCODE_LUT , 1 ),
191
- LUT_ITERATE (BC_ENCODE_LUT , 2 ),
192
- LUT_ITERATE (BC_ENCODE_LUT , 3 ),
193
- LUT_ITERATE (BC_ENCODE_LUT , 4 ),
194
- LUT_ITERATE (BC_ENCODE_LUT , 5 ),
195
- LUT_ITERATE (BC_ENCODE_LUT , 6 ),
196
- LUT_ITERATE (BC_ENCODE_LUT , 7 ),
197
- LUT_ITERATE (BC_ENCODE_LUT , 8 ),
198
- LUT_ITERATE (BC_ENCODE_LUT , 9 ),
199
- };
200
-
201
- static inline unsigned short bc_expand_lut (unsigned char c )
202
- {
203
- return (c & 0x0f ) | (c & 0xf0 ) << 4 ;
204
- }
205
-
206
- /* Writes the character representation of the number encoded in value.
207
- * E.g. if value = 1234, then the string "1234" will be written to str. */
208
- static void bc_write_bcd_representation (uint32_t value , char * str )
209
- {
210
- uint32_t upper = value / 100 ; /* e.g. 12 */
211
- uint32_t lower = value % 100 ; /* e.g. 34 */
212
-
213
- #if BC_LITTLE_ENDIAN
214
- /* Note: little endian, so `lower` comes before `upper`! */
215
- uint32_t digits = bc_expand_lut (LUT [lower ]) << 16 | bc_expand_lut (LUT [upper ]);
216
- #else
217
- /* Note: big endian, so `upper` comes before `lower`! */
218
- uint32_t digits = bc_expand_lut (LUT [upper ]) << 16 | bc_expand_lut (LUT [lower ]);
219
- #endif
220
- memcpy (str , & digits , sizeof (digits ));
221
- }
222
-
223
75
/*
224
76
* Converts the BCD of bc_num by 4 (32 bits) or 8 (64 bits) digits to an array of BC_VECTOR.
225
77
* The array is generated starting with the smaller digits.
0 commit comments