@@ -76,6 +76,35 @@ static const char *bc_count_digits(const char *str, const char *end)
76
76
return str ;
77
77
}
78
78
79
+ static inline const char * bc_skip_zero_reverse (const char * scanner , const char * stop )
80
+ {
81
+ /* Check in bulk */
82
+ #ifdef __SSE2__
83
+ const __m128i c_zero_repeat = _mm_set1_epi8 ('0' );
84
+ while (scanner - sizeof (__m128i ) >= stop ) {
85
+ scanner -= sizeof (__m128i );
86
+ __m128i bytes = _mm_loadu_si128 ((const __m128i * ) scanner );
87
+ /* Checks if all numeric strings are equal to '0'. */
88
+ bytes = _mm_cmpeq_epi8 (bytes , c_zero_repeat );
89
+
90
+ int mask = _mm_movemask_epi8 (bytes );
91
+ /* The probability of having 16 trailing 0s in a row is very low, so we use EXPECTED. */
92
+ if (EXPECTED (mask != 0xffff )) {
93
+ /* Move the pointer back and check each character in loop. */
94
+ scanner += sizeof (__m128i );
95
+ break ;
96
+ }
97
+ }
98
+ #endif
99
+
100
+ /* Exclude trailing zeros. */
101
+ while (scanner - 1 >= stop && scanner [-1 ] == '0' ) {
102
+ scanner -- ;
103
+ }
104
+
105
+ return scanner ;
106
+ }
107
+
79
108
/* Assumes `num` points to NULL, i.e. does yet not hold a number. */
80
109
bool bc_str2num (bc_num * num , const char * str , const char * end , size_t scale , bool auto_scale )
81
110
{
@@ -104,32 +133,28 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, boo
104
133
const char * decimal_point = (* ptr == '.' ) ? ptr : NULL ;
105
134
106
135
/* If a non-digit and non-decimal-point indicator is in the string, i.e. an invalid character */
107
- if (!decimal_point && * ptr != '\0' ) {
136
+ if (UNEXPECTED ( !decimal_point && * ptr != '\0' ) ) {
108
137
goto fail ;
109
138
}
110
139
111
140
/* search and validate fractional end if exists */
112
141
if (decimal_point ) {
113
142
/* search */
114
143
fractional_ptr = fractional_end = decimal_point + 1 ;
115
- if (* fractional_ptr == '\0' ) {
144
+ /* For strings that end with a decimal point, such as "012." */
145
+ if (UNEXPECTED (* fractional_ptr == '\0' )) {
116
146
goto after_fractional ;
117
147
}
118
148
119
149
/* validate */
120
150
fractional_end = bc_count_digits (fractional_ptr , end );
121
- if (* fractional_end != '\0' ) {
151
+ if (UNEXPECTED ( * fractional_end != '\0' ) ) {
122
152
/* invalid num */
123
153
goto fail ;
124
154
}
125
155
126
156
/* Exclude trailing zeros. */
127
- while (fractional_end - 1 > decimal_point && fractional_end [-1 ] == '0' ) {
128
- fractional_end -- ;
129
- }
130
-
131
- /* Move the pointer to the beginning of the fraction. */
132
- fractional_ptr = decimal_point + 1 ;
157
+ fractional_end = bc_skip_zero_reverse (fractional_end , fractional_ptr );
133
158
134
159
/* Calculate the length of the fraction excluding trailing zero. */
135
160
str_scale = fractional_end - fractional_ptr ;
0 commit comments