be/src/util/string_parser.hpp
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // This file is copied from |
18 | | // https://github.com/apache/impala/blob/branch-2.9.0/be/src/util/string-parser.hpp |
19 | | // and modified by Doris |
20 | | |
21 | | #pragma once |
22 | | |
23 | | #include <fast_float/fast_float.h> |
24 | | #include <fast_float/parse_number.h> |
25 | | #include <glog/logging.h> |
26 | | #include <sys/types.h> |
27 | | |
28 | | #include <algorithm> |
29 | | #include <cstdlib> |
30 | | // IWYU pragma: no_include <bits/std_abs.h> |
31 | | #include <cmath> // IWYU pragma: keep |
32 | | #include <cstdint> |
33 | | #include <limits> |
34 | | #include <map> |
35 | | #include <string> |
36 | | #include <type_traits> |
37 | | #include <utility> |
38 | | |
39 | | #include "common/status.h" |
40 | | #include "core/data_type/number_traits.h" |
41 | | #include "core/data_type/primitive_type.h" |
42 | | #include "core/extended_types.h" |
43 | | #include "core/value/large_int_value.h" |
44 | | #include "exec/common/int_exp.h" |
45 | | #include "exec/common/string_utils/string_utils.h" |
46 | | |
47 | | namespace doris { |
48 | | #include "common/compile_check_avoid_begin.h" |
49 | | template <DecimalNativeTypeConcept T> |
50 | | struct Decimal; |
51 | | |
52 | | // they rely on the template parameter `IS_STRICT`. in strict mode, it will set error code and otherwise it will not. |
53 | | #ifndef SET_PARAMS_RET_FALSE_IFN |
54 | | #define SET_PARAMS_RET_FALSE_IFN(stmt, ...) \ |
55 | 5.74M | do { \ |
56 | 5.74M | if (!(stmt)) [[unlikely]] { \ |
57 | 206k | if constexpr (IsStrict) { \ |
58 | 304 | params.status = Status::InvalidArgument(__VA_ARGS__); \ |
59 | 304 | } \ |
60 | 206k | return false; \ |
61 | 206k | } \ |
62 | 5.74M | } while (false) |
63 | | #endif |
64 | | |
65 | | #ifndef SET_PARAMS_RET_FALSE_FROM_EXCEPTION |
66 | | #define SET_PARAMS_RET_FALSE_FROM_EXCEPTION(stmt) \ |
67 | 1.13k | do { \ |
68 | 1.13k | try { \ |
69 | 1.13k | { stmt; } \ |
70 | 1.13k | } catch (const doris::Exception& e) { \ |
71 | 74 | if constexpr (IsStrict) { \ |
72 | 2 | params.status = e.to_status(); \ |
73 | 2 | } \ |
74 | 74 | return false; \ |
75 | 74 | } \ |
76 | 1.13k | } while (false) |
77 | | #endif |
78 | | |
79 | | // skip leading and trailing ascii whitespaces, |
80 | | // return the pointer to the first non-whitespace char, |
81 | | // and update the len to the new length, which does not include |
82 | | // leading and trailing whitespaces |
83 | | template <typename T> |
84 | 21.9M | inline const char* skip_ascii_whitespaces(const char* s, T& len) { |
85 | 22.4M | while (len > 0 && is_whitespace_ascii(*s)) { |
86 | 472k | ++s; |
87 | 472k | --len; |
88 | 472k | } |
89 | | |
90 | 22.4M | while (len > 0 && is_whitespace_ascii(s[len - 1])) { |
91 | 467k | --len; |
92 | 467k | } |
93 | | |
94 | 21.9M | return s; |
95 | 21.9M | } _ZN5doris22skip_ascii_whitespacesImEEPKcS2_RT_ Line | Count | Source | 84 | 21.9M | inline const char* skip_ascii_whitespaces(const char* s, T& len) { | 85 | 22.3M | while (len > 0 && is_whitespace_ascii(*s)) { | 86 | 394k | ++s; | 87 | 394k | --len; | 88 | 394k | } | 89 | | | 90 | 22.2M | while (len > 0 && is_whitespace_ascii(s[len - 1])) { | 91 | 390k | --len; | 92 | 390k | } | 93 | | | 94 | 21.9M | return s; | 95 | 21.9M | } |
_ZN5doris22skip_ascii_whitespacesIlEEPKcS2_RT_ Line | Count | Source | 84 | 31.4k | inline const char* skip_ascii_whitespaces(const char* s, T& len) { | 85 | 105k | while (len > 0 && is_whitespace_ascii(*s)) { | 86 | 74.3k | ++s; | 87 | 74.3k | --len; | 88 | 74.3k | } | 89 | | | 90 | 105k | while (len > 0 && is_whitespace_ascii(s[len - 1])) { | 91 | 74.0k | --len; | 92 | 74.0k | } | 93 | | | 94 | 31.4k | return s; | 95 | 31.4k | } |
_ZN5doris22skip_ascii_whitespacesIiEEPKcS2_RT_ Line | Count | Source | 84 | 4.84k | inline const char* skip_ascii_whitespaces(const char* s, T& len) { | 85 | 8.37k | while (len > 0 && is_whitespace_ascii(*s)) { | 86 | 3.52k | ++s; | 87 | 3.52k | --len; | 88 | 3.52k | } | 89 | | | 90 | 8.37k | while (len > 0 && is_whitespace_ascii(s[len - 1])) { | 91 | 3.52k | --len; | 92 | 3.52k | } | 93 | | | 94 | 4.84k | return s; | 95 | 4.84k | } |
|
96 | | |
97 | | template <typename T> |
98 | 136k | inline const char* skip_leading_whitespace(const char* __restrict s, T& len) { |
99 | 254k | while (len > 0 && is_whitespace_ascii(*s)) { |
100 | 117k | ++s; |
101 | 117k | --len; |
102 | 117k | } |
103 | | |
104 | 136k | return s; |
105 | 136k | } |
106 | | |
107 | | // skip trailing ascii whitespaces, |
108 | | // return the pointer to the first char, |
109 | | // and update the len to the new length, which does not include |
110 | | // trailing whitespaces |
111 | | template <typename T> |
112 | 102k | inline const char* skip_trailing_whitespaces(const char* s, T& len) { |
113 | 226k | while (len > 0 && is_whitespace_ascii(s[len - 1])) { |
114 | 123k | --len; |
115 | 123k | } |
116 | | |
117 | 102k | return s; |
118 | 102k | } |
119 | | |
120 | | template <bool (*Pred)(char)> |
121 | 192k | bool range_suite(const char* s, const char* end) { |
122 | 192k | return std::ranges::all_of(s, end, Pred); |
123 | 192k | } _ZN5doris11range_suiteIXadL_Z16is_numeric_asciicEEEEbPKcS2_ Line | Count | Source | 121 | 189k | bool range_suite(const char* s, const char* end) { | 122 | 189k | return std::ranges::all_of(s, end, Pred); | 123 | 189k | } |
_ZN5doris11range_suiteIXadL_Z19is_whitespace_asciicEEEEbPKcS2_ Line | Count | Source | 121 | 2.64k | bool range_suite(const char* s, const char* end) { | 122 | 2.64k | return std::ranges::all_of(s, end, Pred); | 123 | 2.64k | } |
|
124 | | |
125 | | inline auto is_digit_range = range_suite<is_numeric_ascii>; |
126 | | inline auto is_space_range = range_suite<is_whitespace_ascii>; |
127 | | |
128 | | // combine in_bound and range_suite is ok. won't lead to duplicated calculation. |
129 | 199k | inline bool in_bound(const char* s, const char* end, size_t offset) { |
130 | 199k | if (s + offset >= end) [[unlikely]] { |
131 | 110k | return false; |
132 | 110k | } |
133 | 88.3k | return true; |
134 | 199k | } |
135 | | |
136 | | // LEN = 0 means any length(include zero). LEN = 1 means only one character. so on. LEN = -x means x or more. |
137 | | // if need result, use StringRef{origin_s, s} outside |
138 | | template <int LEN, bool (*Pred)(char)> |
139 | 2.36M | bool skip_qualified_char(const char*& s, const char* end) { |
140 | 2.36M | if constexpr (LEN == 0) { |
141 | | // Consume any length of characters that match the predicate. |
142 | 4.32M | while (s != end && Pred(*s)) { |
143 | 2.19M | ++s; |
144 | 2.19M | } |
145 | 2.13M | } else if constexpr (LEN > 0) { |
146 | | // Consume exactly LEN characters that match the predicate. |
147 | 360k | for (int i = 0; i < LEN; ++i, ++s) { |
148 | 217k | if (s == end || !Pred(*s)) [[unlikely]] { |
149 | 75.4k | return false; |
150 | 75.4k | } |
151 | 217k | } |
152 | 217k | } else { // LEN < 0 |
153 | | // Consume at least -LEN characters that match the predicate. |
154 | 16.3k | int count = 0; |
155 | 33.8k | while (s != end && Pred(*s)) { |
156 | 17.4k | ++s; |
157 | 17.4k | ++count; |
158 | 17.4k | } |
159 | 16.3k | if (count < -LEN) [[unlikely]] { |
160 | 0 | return false; |
161 | 0 | } |
162 | 16.3k | } |
163 | 158k | return true; |
164 | 2.36M | } _ZN5doris19skip_qualified_charILi0EXadL_Z19is_whitespace_asciicEEEEbRPKcS2_ Line | Count | Source | 139 | 917k | bool skip_qualified_char(const char*& s, const char* end) { | 140 | 917k | if constexpr (LEN == 0) { | 141 | | // Consume any length of characters that match the predicate. | 142 | 921k | while (s != end && Pred(*s)) { | 143 | 4.33k | ++s; | 144 | 4.33k | } | 145 | | } else if constexpr (LEN > 0) { | 146 | | // Consume exactly LEN characters that match the predicate. | 147 | | for (int i = 0; i < LEN; ++i, ++s) { | 148 | | if (s == end || !Pred(*s)) [[unlikely]] { | 149 | | return false; | 150 | | } | 151 | | } | 152 | | } else { // LEN < 0 | 153 | | // Consume at least -LEN characters that match the predicate. | 154 | | int count = 0; | 155 | | while (s != end && Pred(*s)) { | 156 | | ++s; | 157 | | ++count; | 158 | | } | 159 | | if (count < -LEN) [[unlikely]] { | 160 | | return false; | 161 | | } | 162 | | } | 163 | 917k | return true; | 164 | 917k | } |
_ZN5doris19skip_qualified_charILi0EXadL_Z16is_numeric_asciicEEEEbRPKcS2_ Line | Count | Source | 139 | 1.21M | bool skip_qualified_char(const char*& s, const char* end) { | 140 | 1.21M | if constexpr (LEN == 0) { | 141 | | // Consume any length of characters that match the predicate. | 142 | 3.40M | while (s != end && Pred(*s)) { | 143 | 2.18M | ++s; | 144 | 2.18M | } | 145 | | } else if constexpr (LEN > 0) { | 146 | | // Consume exactly LEN characters that match the predicate. | 147 | | for (int i = 0; i < LEN; ++i, ++s) { | 148 | | if (s == end || !Pred(*s)) [[unlikely]] { | 149 | | return false; | 150 | | } | 151 | | } | 152 | | } else { // LEN < 0 | 153 | | // Consume at least -LEN characters that match the predicate. | 154 | | int count = 0; | 155 | | while (s != end && Pred(*s)) { | 156 | | ++s; | 157 | | ++count; | 158 | | } | 159 | | if (count < -LEN) [[unlikely]] { | 160 | | return false; | 161 | | } | 162 | | } | 163 | 1.21M | return true; | 164 | 1.21M | } |
_ZN5doris19skip_qualified_charILin1EXadL_Z23is_not_whitespace_asciicEEEEbRPKcS2_ Line | Count | Source | 139 | 16.3k | bool skip_qualified_char(const char*& s, const char* end) { | 140 | | if constexpr (LEN == 0) { | 141 | | // Consume any length of characters that match the predicate. | 142 | | while (s != end && Pred(*s)) { | 143 | | ++s; | 144 | | } | 145 | | } else if constexpr (LEN > 0) { | 146 | | // Consume exactly LEN characters that match the predicate. | 147 | | for (int i = 0; i < LEN; ++i, ++s) { | 148 | | if (s == end || !Pred(*s)) [[unlikely]] { | 149 | | return false; | 150 | | } | 151 | | } | 152 | 16.3k | } else { // LEN < 0 | 153 | | // Consume at least -LEN characters that match the predicate. | 154 | 16.3k | int count = 0; | 155 | 33.8k | while (s != end && Pred(*s)) { | 156 | 17.4k | ++s; | 157 | 17.4k | ++count; | 158 | 17.4k | } | 159 | 16.3k | if (count < -LEN) [[unlikely]] { | 160 | 0 | return false; | 161 | 0 | } | 162 | 16.3k | } | 163 | 16.3k | return true; | 164 | 16.3k | } |
Unexecuted instantiation: _ZN5doris19skip_qualified_charILi1EXadL_Z14is_slash_asciicEEEEbRPKcS2_ _ZN5doris19skip_qualified_charILi1EXadL_Z12is_non_alnumcEEEEbRPKcS2_ Line | Count | Source | 139 | 101k | bool skip_qualified_char(const char*& s, const char* end) { | 140 | | if constexpr (LEN == 0) { | 141 | | // Consume any length of characters that match the predicate. | 142 | | while (s != end && Pred(*s)) { | 143 | | ++s; | 144 | | } | 145 | 101k | } else if constexpr (LEN > 0) { | 146 | | // Consume exactly LEN characters that match the predicate. | 147 | 127k | for (int i = 0; i < LEN; ++i, ++s) { | 148 | 101k | if (s == end || !Pred(*s)) [[unlikely]] { | 149 | 75.2k | return false; | 150 | 75.2k | } | 151 | 101k | } | 152 | | } else { // LEN < 0 | 153 | | // Consume at least -LEN characters that match the predicate. | 154 | | int count = 0; | 155 | | while (s != end && Pred(*s)) { | 156 | | ++s; | 157 | | ++count; | 158 | | } | 159 | | if (count < -LEN) [[unlikely]] { | 160 | | return false; | 161 | | } | 162 | | } | 163 | 26.2k | return true; | 164 | 101k | } |
_ZN5doris19skip_qualified_charILi1EXadL_ZNS_12is_delimiterEcEEEEbRPKcS2_ Line | Count | Source | 139 | 18.6k | bool skip_qualified_char(const char*& s, const char* end) { | 140 | | if constexpr (LEN == 0) { | 141 | | // Consume any length of characters that match the predicate. | 142 | | while (s != end && Pred(*s)) { | 143 | | ++s; | 144 | | } | 145 | 18.6k | } else if constexpr (LEN > 0) { | 146 | | // Consume exactly LEN characters that match the predicate. | 147 | 37.2k | for (int i = 0; i < LEN; ++i, ++s) { | 148 | 18.6k | if (s == end || !Pred(*s)) [[unlikely]] { | 149 | 89 | return false; | 150 | 89 | } | 151 | 18.6k | } | 152 | | } else { // LEN < 0 | 153 | | // Consume at least -LEN characters that match the predicate. | 154 | | int count = 0; | 155 | | while (s != end && Pred(*s)) { | 156 | | ++s; | 157 | | ++count; | 158 | | } | 159 | | if (count < -LEN) [[unlikely]] { | 160 | | return false; | 161 | | } | 162 | | } | 163 | 18.5k | return true; | 164 | 18.6k | } |
_ZN5doris19skip_qualified_charILi1EXadL_ZNS_11is_date_sepEcEEEEbRPKcS2_ Line | Count | Source | 139 | 66.0k | bool skip_qualified_char(const char*& s, const char* end) { | 140 | | if constexpr (LEN == 0) { | 141 | | // Consume any length of characters that match the predicate. | 142 | | while (s != end && Pred(*s)) { | 143 | | ++s; | 144 | | } | 145 | 66.0k | } else if constexpr (LEN > 0) { | 146 | | // Consume exactly LEN characters that match the predicate. | 147 | 131k | for (int i = 0; i < LEN; ++i, ++s) { | 148 | 66.0k | if (s == end || !Pred(*s)) [[unlikely]] { | 149 | 70 | return false; | 150 | 70 | } | 151 | 66.0k | } | 152 | | } else { // LEN < 0 | 153 | | // Consume at least -LEN characters that match the predicate. | 154 | | int count = 0; | 155 | | while (s != end && Pred(*s)) { | 156 | | ++s; | 157 | | ++count; | 158 | | } | 159 | | if (count < -LEN) [[unlikely]] { | 160 | | return false; | 161 | | } | 162 | | } | 163 | 65.9k | return true; | 164 | 66.0k | } |
_ZN5doris19skip_qualified_charILi1EXadL_ZNS_8is_colonEcEEEEbRPKcS2_ Line | Count | Source | 139 | 31.8k | bool skip_qualified_char(const char*& s, const char* end) { | 140 | | if constexpr (LEN == 0) { | 141 | | // Consume any length of characters that match the predicate. | 142 | | while (s != end && Pred(*s)) { | 143 | | ++s; | 144 | | } | 145 | 31.8k | } else if constexpr (LEN > 0) { | 146 | | // Consume exactly LEN characters that match the predicate. | 147 | 63.5k | for (int i = 0; i < LEN; ++i, ++s) { | 148 | 31.8k | if (s == end || !Pred(*s)) [[unlikely]] { | 149 | 60 | return false; | 150 | 60 | } | 151 | 31.8k | } | 152 | | } else { // LEN < 0 | 153 | | // Consume at least -LEN characters that match the predicate. | 154 | | int count = 0; | 155 | | while (s != end && Pred(*s)) { | 156 | | ++s; | 157 | | ++count; | 158 | | } | 159 | | if (count < -LEN) [[unlikely]] { | 160 | | return false; | 161 | | } | 162 | | } | 163 | 31.7k | return true; | 164 | 31.8k | } |
|
165 | | |
166 | | inline auto skip_any_whitespace = skip_qualified_char<0, is_whitespace_ascii>; |
167 | | inline auto skip_any_digit = skip_qualified_char<0, is_numeric_ascii>; |
168 | | inline auto skip_tz_name_part = skip_qualified_char<-1, is_not_whitespace_ascii>; |
169 | | inline auto skip_one_slash = skip_qualified_char<1, is_slash_ascii>; |
170 | | inline auto skip_one_non_alnum = skip_qualified_char<1, is_non_alnum>; |
171 | | |
172 | 18.6k | inline bool is_delimiter(char c) { |
173 | 18.6k | return c == ' ' || c == 'T' || c == ':'; |
174 | 18.6k | } |
175 | | inline auto consume_one_delimiter = skip_qualified_char<1, is_delimiter>; |
176 | | |
177 | 104k | inline bool is_date_sep(char c) { |
178 | 104k | return c == '-' || c == '/'; |
179 | 104k | } |
180 | | inline auto consume_one_date_sep = skip_qualified_char<1, is_date_sep>; |
181 | | |
182 | 31.8k | inline bool is_colon(char c) { |
183 | 31.8k | return c == ':'; |
184 | 31.8k | } |
185 | | inline auto consume_one_colon = skip_qualified_char<1, is_colon>; |
186 | | |
187 | | // only consume a string of digit, not include sign. |
188 | | // when has MAX_LEN > 0, do greedy match but at most MAX_LEN. |
189 | | // LEN = 0 means any length, otherwise(must > 0) it means exactly LEN digits. |
190 | | template <typename T, int LEN = 0, int MAX_LEN = -1> |
191 | 32.7k | bool consume_digit(const char*& s, const char* end, T& out) { |
192 | 32.7k | static_assert(LEN >= 0); |
193 | | if constexpr (MAX_LEN > 0) { |
194 | | out = 0; |
195 | | for (int i = 0; i < MAX_LEN; ++i, ++s) { |
196 | | if (s == end || !is_numeric_ascii(*s)) { |
197 | | if (i < LEN) [[unlikely]] { |
198 | | return false; |
199 | | } |
200 | | break; // stop consuming if we have consumed enough digits. |
201 | | } |
202 | | out = out * 10 + (*s - '0'); |
203 | | } |
204 | | } else if constexpr (LEN == 0) { |
205 | | // Consume any length of digits. |
206 | | out = 0; |
207 | | while (s != end && is_numeric_ascii(*s)) { |
208 | | out = out * 10 + (*s - '0'); |
209 | | ++s; |
210 | | } |
211 | 32.7k | } else if constexpr (LEN > 0) { |
212 | | // Consume exactly LEN digits. |
213 | 32.7k | out = 0; |
214 | 163k | for (int i = 0; i < LEN; ++i, ++s) { |
215 | 131k | if (s == end || !is_numeric_ascii(*s)) [[unlikely]] { |
216 | 0 | return false; |
217 | 0 | } |
218 | 131k | out = out * 10 + (*s - '0'); |
219 | 131k | } |
220 | 32.7k | } |
221 | 32.7k | return true; |
222 | 32.7k | } _ZN5doris13consume_digitIjLi4ELin1EEEbRPKcS2_RT_ Line | Count | Source | 191 | 32.7k | bool consume_digit(const char*& s, const char* end, T& out) { | 192 | 32.7k | static_assert(LEN >= 0); | 193 | | if constexpr (MAX_LEN > 0) { | 194 | | out = 0; | 195 | | for (int i = 0; i < MAX_LEN; ++i, ++s) { | 196 | | if (s == end || !is_numeric_ascii(*s)) { | 197 | | if (i < LEN) [[unlikely]] { | 198 | | return false; | 199 | | } | 200 | | break; // stop consuming if we have consumed enough digits. | 201 | | } | 202 | | out = out * 10 + (*s - '0'); | 203 | | } | 204 | | } else if constexpr (LEN == 0) { | 205 | | // Consume any length of digits. | 206 | | out = 0; | 207 | | while (s != end && is_numeric_ascii(*s)) { | 208 | | out = out * 10 + (*s - '0'); | 209 | | ++s; | 210 | | } | 211 | 32.7k | } else if constexpr (LEN > 0) { | 212 | | // Consume exactly LEN digits. | 213 | 32.7k | out = 0; | 214 | 163k | for (int i = 0; i < LEN; ++i, ++s) { | 215 | 131k | if (s == end || !is_numeric_ascii(*s)) [[unlikely]] { | 216 | 0 | return false; | 217 | 0 | } | 218 | 131k | out = out * 10 + (*s - '0'); | 219 | 131k | } | 220 | 32.7k | } | 221 | 32.7k | return true; | 222 | 32.7k | } |
_ZN5doris13consume_digitIjLi1ELin1EEEbRPKcS2_RT_ Line | Count | Source | 191 | 15 | bool consume_digit(const char*& s, const char* end, T& out) { | 192 | 15 | static_assert(LEN >= 0); | 193 | | if constexpr (MAX_LEN > 0) { | 194 | | out = 0; | 195 | | for (int i = 0; i < MAX_LEN; ++i, ++s) { | 196 | | if (s == end || !is_numeric_ascii(*s)) { | 197 | | if (i < LEN) [[unlikely]] { | 198 | | return false; | 199 | | } | 200 | | break; // stop consuming if we have consumed enough digits. | 201 | | } | 202 | | out = out * 10 + (*s - '0'); | 203 | | } | 204 | | } else if constexpr (LEN == 0) { | 205 | | // Consume any length of digits. | 206 | | out = 0; | 207 | | while (s != end && is_numeric_ascii(*s)) { | 208 | | out = out * 10 + (*s - '0'); | 209 | | ++s; | 210 | | } | 211 | 15 | } else if constexpr (LEN > 0) { | 212 | | // Consume exactly LEN digits. | 213 | 15 | out = 0; | 214 | 30 | for (int i = 0; i < LEN; ++i, ++s) { | 215 | 15 | if (s == end || !is_numeric_ascii(*s)) [[unlikely]] { | 216 | 0 | return false; | 217 | 0 | } | 218 | 15 | out = out * 10 + (*s - '0'); | 219 | 15 | } | 220 | 15 | } | 221 | 15 | return true; | 222 | 15 | } |
|
223 | | |
224 | | // specialized version for 2 digits, which is used very often in date/time parsing. |
225 | | template <> |
226 | 643k | inline bool consume_digit<uint32_t, 2, -1>(const char*& s, const char* end, uint32_t& out) { |
227 | 643k | out = 0; |
228 | 643k | if (s == end || s + 1 == end || !is_numeric_ascii(*s) || !is_numeric_ascii(*(s + 1))) |
229 | 64.7k | [[unlikely]] { |
230 | 64.7k | return false; |
231 | 64.7k | } |
232 | 578k | out = (s[0] - '0') * 10 + (s[1] - '0'); |
233 | 578k | s += 2; // consume 2 digits |
234 | 578k | return true; |
235 | 643k | } |
236 | | |
237 | | // specialized version for 1 or 2 digits, which is used very often in date/time parsing. |
238 | | template <> |
239 | 144k | inline bool consume_digit<uint32_t, 1, 2>(const char*& s, const char* end, uint32_t& out) { |
240 | 144k | out = 0; |
241 | 144k | if (s == end || !is_numeric_ascii(*s)) [[unlikely]] { |
242 | 521 | return false; |
243 | 143k | } else if (s + 1 != end && is_numeric_ascii(*(s + 1))) { |
244 | | // consume 2 digits |
245 | 96.0k | out = (*s - '0') * 10 + (*(s + 1) - '0'); |
246 | 96.0k | s += 2; |
247 | 96.0k | } else { |
248 | | // consume 1 digit |
249 | 47.8k | out = *s - '0'; |
250 | 47.8k | ++s; |
251 | 47.8k | } |
252 | 143k | return true; |
253 | 144k | } |
254 | | |
255 | | template <bool (*Pred)(char)> |
256 | 109k | uint32_t count_valid_length(const char* s, const char* end) { |
257 | 18.4E | DCHECK(s <= end) << "s: " << s << ", end: " << end; |
258 | 109k | uint32_t count = 0; |
259 | 329k | while (s != end && Pred(*s)) { |
260 | 219k | ++count; |
261 | 219k | ++s; |
262 | 219k | } |
263 | 109k | return count; |
264 | 109k | } |
265 | | |
266 | | inline auto count_digits = count_valid_length<is_numeric_ascii>; |
267 | | |
268 | 81.2k | inline std::string combine_tz_offset(char sign, uint32_t hour_offset, uint32_t minute_offset) { |
269 | 81.2k | std::string result(6, '0'); |
270 | 81.2k | result[0] = sign; |
271 | 81.2k | result[1] = '0' + (hour_offset / 10); |
272 | 81.2k | result[2] = '0' + (hour_offset % 10); |
273 | 81.2k | result[3] = ':'; |
274 | 81.2k | result[4] = '0' + (minute_offset / 10); |
275 | 81.2k | result[5] = '0' + (minute_offset % 10); |
276 | 81.2k | DCHECK_EQ(result.size(), 6); |
277 | 81.2k | return result; |
278 | 81.2k | } |
279 | | |
280 | | // Utility functions for doing atoi/atof on non-null terminated strings. On micro benchmarks, |
281 | | // this is significantly faster than libc (atoi/strtol and atof/strtod). |
282 | | // |
283 | | // Strings with leading and trailing whitespaces are accepted. |
284 | | // Branching is heavily optimized for the non-whitespace successful case. |
285 | | // All the StringTo* functions first parse the input string assuming it has no leading whitespace. |
286 | | // If that first attempt was unsuccessful, these functions retry the parsing after removing |
287 | | // whitespace. Therefore, strings with whitespace take a perf hit on branch mis-prediction. |
288 | | // |
289 | | // For overflows, we are following the mysql behavior, to cap values at the max/min value for that |
290 | | // data type. This is different from hive, which returns NULL for overflow slots for int types |
291 | | // and inf/-inf for float types. |
292 | | // |
293 | | // Things we tried that did not work: |
294 | | // - lookup table for converting character to digit |
295 | | // Improvements (TODO): |
296 | | // - Validate input using _simd_compare_ranges |
297 | | // - Since we know the length, we can parallelize this: i.e. result = 100*s[0] + 10*s[1] + s[2] |
298 | | class StringParser { |
299 | | public: |
300 | | enum ParseResult { PARSE_SUCCESS = 0, PARSE_FAILURE, PARSE_OVERFLOW, PARSE_UNDERFLOW }; |
301 | | |
302 | | template <typename T> |
303 | 132M | static T numeric_limits(bool negative) { |
304 | 132M | if constexpr (std::is_same_v<T, __int128>) { |
305 | 1.02M | return negative ? MIN_INT128 : MAX_INT128; |
306 | 131M | } else { |
307 | 131M | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); |
308 | 131M | } |
309 | 132M | } _ZN5doris12StringParser14numeric_limitsInEET_b Line | Count | Source | 303 | 1.02M | static T numeric_limits(bool negative) { | 304 | 1.02M | if constexpr (std::is_same_v<T, __int128>) { | 305 | 1.02M | return negative ? MIN_INT128 : MAX_INT128; | 306 | | } else { | 307 | | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 308 | | } | 309 | 1.02M | } |
_ZN5doris12StringParser14numeric_limitsIjEET_b Line | Count | Source | 303 | 2.79k | static T numeric_limits(bool negative) { | 304 | | if constexpr (std::is_same_v<T, __int128>) { | 305 | | return negative ? MIN_INT128 : MAX_INT128; | 306 | 2.79k | } else { | 307 | 2.79k | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 308 | 2.79k | } | 309 | 2.79k | } |
_ZN5doris12StringParser14numeric_limitsIaEET_b Line | Count | Source | 303 | 5.99M | static T numeric_limits(bool negative) { | 304 | | if constexpr (std::is_same_v<T, __int128>) { | 305 | | return negative ? MIN_INT128 : MAX_INT128; | 306 | 5.99M | } else { | 307 | 5.99M | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 308 | 5.99M | } | 309 | 5.99M | } |
_ZN5doris12StringParser14numeric_limitsIsEET_b Line | Count | Source | 303 | 1.10M | static T numeric_limits(bool negative) { | 304 | | if constexpr (std::is_same_v<T, __int128>) { | 305 | | return negative ? MIN_INT128 : MAX_INT128; | 306 | 1.10M | } else { | 307 | 1.10M | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 308 | 1.10M | } | 309 | 1.10M | } |
_ZN5doris12StringParser14numeric_limitsIiEET_b Line | Count | Source | 303 | 52.2M | static T numeric_limits(bool negative) { | 304 | | if constexpr (std::is_same_v<T, __int128>) { | 305 | | return negative ? MIN_INT128 : MAX_INT128; | 306 | 52.2M | } else { | 307 | 52.2M | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 308 | 52.2M | } | 309 | 52.2M | } |
_ZN5doris12StringParser14numeric_limitsIlEET_b Line | Count | Source | 303 | 71.6M | static T numeric_limits(bool negative) { | 304 | | if constexpr (std::is_same_v<T, __int128>) { | 305 | | return negative ? MIN_INT128 : MAX_INT128; | 306 | 71.6M | } else { | 307 | 71.6M | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 308 | 71.6M | } | 309 | 71.6M | } |
_ZN5doris12StringParser14numeric_limitsImEET_b Line | Count | Source | 303 | 9.96k | static T numeric_limits(bool negative) { | 304 | | if constexpr (std::is_same_v<T, __int128>) { | 305 | | return negative ? MIN_INT128 : MAX_INT128; | 306 | 9.96k | } else { | 307 | 9.96k | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 308 | 9.96k | } | 309 | 9.96k | } |
_ZN5doris12StringParser14numeric_limitsIN4wide7integerILm256EiEEEET_b Line | Count | Source | 303 | 4 | static T numeric_limits(bool negative) { | 304 | | if constexpr (std::is_same_v<T, __int128>) { | 305 | | return negative ? MIN_INT128 : MAX_INT128; | 306 | 4 | } else { | 307 | 4 | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 308 | 4 | } | 309 | 4 | } |
_ZN5doris12StringParser14numeric_limitsIoEET_b Line | Count | Source | 303 | 2.66k | static T numeric_limits(bool negative) { | 304 | | if constexpr (std::is_same_v<T, __int128>) { | 305 | | return negative ? MIN_INT128 : MAX_INT128; | 306 | 2.66k | } else { | 307 | 2.66k | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 308 | 2.66k | } | 309 | 2.66k | } |
|
310 | | |
311 | | template <typename T> |
312 | 38.7M | static T get_scale_multiplier(int scale) { |
313 | 38.7M | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || |
314 | 38.7M | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, |
315 | 38.7M | "You can only instantiate as int32_t, int64_t, __int128."); |
316 | 38.7M | if constexpr (std::is_same_v<T, int32_t>) { |
317 | 685k | return common::exp10_i32(scale); |
318 | 33.6M | } else if constexpr (std::is_same_v<T, int64_t>) { |
319 | 33.6M | return common::exp10_i64(scale); |
320 | 33.6M | } else if constexpr (std::is_same_v<T, __int128>) { |
321 | 3.95M | return common::exp10_i128(scale); |
322 | 3.95M | } else if constexpr (std::is_same_v<T, wide::Int256>) { |
323 | 434k | return common::exp10_i256(scale); |
324 | 434k | } |
325 | 38.7M | } _ZN5doris12StringParser20get_scale_multiplierIiEET_i Line | Count | Source | 312 | 685k | static T get_scale_multiplier(int scale) { | 313 | 685k | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || | 314 | 685k | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, | 315 | 685k | "You can only instantiate as int32_t, int64_t, __int128."); | 316 | 685k | if constexpr (std::is_same_v<T, int32_t>) { | 317 | 685k | return common::exp10_i32(scale); | 318 | | } else if constexpr (std::is_same_v<T, int64_t>) { | 319 | | return common::exp10_i64(scale); | 320 | | } else if constexpr (std::is_same_v<T, __int128>) { | 321 | | return common::exp10_i128(scale); | 322 | | } else if constexpr (std::is_same_v<T, wide::Int256>) { | 323 | | return common::exp10_i256(scale); | 324 | | } | 325 | 685k | } |
_ZN5doris12StringParser20get_scale_multiplierIlEET_i Line | Count | Source | 312 | 33.6M | static T get_scale_multiplier(int scale) { | 313 | 33.6M | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || | 314 | 33.6M | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, | 315 | 33.6M | "You can only instantiate as int32_t, int64_t, __int128."); | 316 | | if constexpr (std::is_same_v<T, int32_t>) { | 317 | | return common::exp10_i32(scale); | 318 | 33.6M | } else if constexpr (std::is_same_v<T, int64_t>) { | 319 | 33.6M | return common::exp10_i64(scale); | 320 | | } else if constexpr (std::is_same_v<T, __int128>) { | 321 | | return common::exp10_i128(scale); | 322 | | } else if constexpr (std::is_same_v<T, wide::Int256>) { | 323 | | return common::exp10_i256(scale); | 324 | | } | 325 | 33.6M | } |
_ZN5doris12StringParser20get_scale_multiplierInEET_i Line | Count | Source | 312 | 3.95M | static T get_scale_multiplier(int scale) { | 313 | 3.95M | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || | 314 | 3.95M | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, | 315 | 3.95M | "You can only instantiate as int32_t, int64_t, __int128."); | 316 | | if constexpr (std::is_same_v<T, int32_t>) { | 317 | | return common::exp10_i32(scale); | 318 | | } else if constexpr (std::is_same_v<T, int64_t>) { | 319 | | return common::exp10_i64(scale); | 320 | 3.95M | } else if constexpr (std::is_same_v<T, __int128>) { | 321 | 3.95M | return common::exp10_i128(scale); | 322 | | } else if constexpr (std::is_same_v<T, wide::Int256>) { | 323 | | return common::exp10_i256(scale); | 324 | | } | 325 | 3.95M | } |
_ZN5doris12StringParser20get_scale_multiplierIN4wide7integerILm256EiEEEET_i Line | Count | Source | 312 | 434k | static T get_scale_multiplier(int scale) { | 313 | 434k | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || | 314 | 434k | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, | 315 | 434k | "You can only instantiate as int32_t, int64_t, __int128."); | 316 | | if constexpr (std::is_same_v<T, int32_t>) { | 317 | | return common::exp10_i32(scale); | 318 | | } else if constexpr (std::is_same_v<T, int64_t>) { | 319 | | return common::exp10_i64(scale); | 320 | | } else if constexpr (std::is_same_v<T, __int128>) { | 321 | | return common::exp10_i128(scale); | 322 | 434k | } else if constexpr (std::is_same_v<T, wide::Int256>) { | 323 | 434k | return common::exp10_i256(scale); | 324 | 434k | } | 325 | 434k | } |
|
326 | | |
327 | | // This is considerably faster than glibc's implementation (25x). |
328 | | // Assumes s represents a decimal number. |
329 | | template <typename T, bool enable_strict_mode = false> |
330 | 131M | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { |
331 | 131M | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); |
332 | 131M | if (LIKELY(*result == PARSE_SUCCESS)) { |
333 | 131M | return ans; |
334 | 131M | } |
335 | 248k | s = skip_leading_whitespace(s, len); |
336 | 248k | return string_to_int_internal<T, enable_strict_mode>(s, len, result); |
337 | 131M | } _ZN5doris12StringParser13string_to_intInLb0EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 1.02M | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 1.02M | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 1.02M | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 1.01M | return ans; | 334 | 1.01M | } | 335 | 12.0k | s = skip_leading_whitespace(s, len); | 336 | 12.0k | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 1.02M | } |
_ZN5doris12StringParser13string_to_intIaLb1EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 1.92k | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 1.92k | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 1.92k | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 876 | return ans; | 334 | 876 | } | 335 | 1.04k | s = skip_leading_whitespace(s, len); | 336 | 1.04k | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 1.92k | } |
_ZN5doris12StringParser13string_to_intIsLb1EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 1.75k | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 1.75k | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 1.75k | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 860 | return ans; | 334 | 860 | } | 335 | 896 | s = skip_leading_whitespace(s, len); | 336 | 896 | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 1.75k | } |
_ZN5doris12StringParser13string_to_intIiLb1EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 2.30k | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 2.30k | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 2.30k | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 1.38k | return ans; | 334 | 1.38k | } | 335 | 916 | s = skip_leading_whitespace(s, len); | 336 | 916 | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 2.30k | } |
_ZN5doris12StringParser13string_to_intIlLb1EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 2.42k | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 2.42k | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 2.42k | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 1.13k | return ans; | 334 | 1.13k | } | 335 | 1.28k | s = skip_leading_whitespace(s, len); | 336 | 1.28k | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 2.42k | } |
_ZN5doris12StringParser13string_to_intInLb1EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 1.88k | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 1.88k | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 1.88k | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 999 | return ans; | 334 | 999 | } | 335 | 890 | s = skip_leading_whitespace(s, len); | 336 | 890 | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 1.88k | } |
_ZN5doris12StringParser13string_to_intIaLb0EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 5.93M | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 5.93M | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 5.93M | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 5.89M | return ans; | 334 | 5.89M | } | 335 | 38.3k | s = skip_leading_whitespace(s, len); | 336 | 38.3k | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 5.93M | } |
_ZN5doris12StringParser13string_to_intIsLb0EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 1.09M | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 1.09M | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 1.09M | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 1.07M | return ans; | 334 | 1.07M | } | 335 | 19.8k | s = skip_leading_whitespace(s, len); | 336 | 19.8k | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 1.09M | } |
_ZN5doris12StringParser13string_to_intIiLb0EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 52.2M | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 52.2M | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 52.2M | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 52.2M | return ans; | 334 | 52.2M | } | 335 | 35.8k | s = skip_leading_whitespace(s, len); | 336 | 35.8k | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 52.2M | } |
_ZN5doris12StringParser13string_to_intIlLb0EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 71.6M | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 71.6M | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 71.6M | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 71.5M | return ans; | 334 | 71.5M | } | 335 | 136k | s = skip_leading_whitespace(s, len); | 336 | 136k | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 71.6M | } |
_ZN5doris12StringParser13string_to_intIjLb0EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 442 | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 442 | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 442 | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 43 | return ans; | 334 | 43 | } | 335 | 399 | s = skip_leading_whitespace(s, len); | 336 | 399 | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 442 | } |
_ZN5doris12StringParser13string_to_intImLb0EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 5.22k | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 5.22k | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 5.22k | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 4.82k | return ans; | 334 | 4.82k | } | 335 | 396 | s = skip_leading_whitespace(s, len); | 336 | 396 | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 5.22k | } |
_ZN5doris12StringParser13string_to_intIN4wide7integerILm256EiEELb0EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 4 | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 4 | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 4 | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 4 | return ans; | 334 | 4 | } | 335 | 0 | s = skip_leading_whitespace(s, len); | 336 | 0 | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 4 | } |
_ZN5doris12StringParser13string_to_intIoLb0EEET_PKcmPNS0_11ParseResultE Line | Count | Source | 330 | 1.41k | static inline T string_to_int(const char* __restrict s, size_t len, ParseResult* result) { | 331 | 1.41k | T ans = string_to_int_internal<T, enable_strict_mode>(s, len, result); | 332 | 1.41k | if (LIKELY(*result == PARSE_SUCCESS)) { | 333 | 1.01k | return ans; | 334 | 1.01k | } | 335 | 399 | s = skip_leading_whitespace(s, len); | 336 | 399 | return string_to_int_internal<T, enable_strict_mode>(s, len, result); | 337 | 1.41k | } |
|
338 | | |
339 | | // This is considerably faster than glibc's implementation. |
340 | | // In the case of overflow, the max/min value for the data type will be returned. |
341 | | // Assumes s represents a decimal number. |
342 | | template <typename T> |
343 | 3.81k | static inline T string_to_unsigned_int(const char* __restrict s, int len, ParseResult* result) { |
344 | 3.81k | s = skip_ascii_whitespaces(s, len); |
345 | 3.81k | return string_to_unsigned_int_internal<T>(s, len, result); |
346 | 3.81k | } |
347 | | |
348 | | // Convert a string s representing a number in given base into a decimal number. |
349 | | template <typename T> |
350 | | static inline T string_to_int(const char* __restrict s, int64_t len, int base, |
351 | 3.49k | ParseResult* result) { |
352 | 3.49k | s = skip_ascii_whitespaces(s, len); |
353 | 3.49k | return string_to_int_internal<T>(s, len, base, result); |
354 | 3.49k | } |
355 | | |
356 | | template <typename T> |
357 | 3.85M | static inline T string_to_float(const char* __restrict s, size_t len, ParseResult* result) { |
358 | 3.85M | s = skip_ascii_whitespaces(s, len); |
359 | 3.85M | return string_to_float_internal<T>(s, len, result); |
360 | 3.85M | } _ZN5doris12StringParser15string_to_floatIdEET_PKcmPNS0_11ParseResultE Line | Count | Source | 357 | 2.84M | static inline T string_to_float(const char* __restrict s, size_t len, ParseResult* result) { | 358 | 2.84M | s = skip_ascii_whitespaces(s, len); | 359 | 2.84M | return string_to_float_internal<T>(s, len, result); | 360 | 2.84M | } |
_ZN5doris12StringParser15string_to_floatIfEET_PKcmPNS0_11ParseResultE Line | Count | Source | 357 | 1.00M | static inline T string_to_float(const char* __restrict s, size_t len, ParseResult* result) { | 358 | 1.00M | s = skip_ascii_whitespaces(s, len); | 359 | 1.00M | return string_to_float_internal<T>(s, len, result); | 360 | 1.00M | } |
|
361 | | |
362 | | // Parses a string for 'true' or 'false', case insensitive. |
363 | 676k | static inline bool string_to_bool(const char* __restrict s, size_t len, ParseResult* result) { |
364 | 676k | s = skip_ascii_whitespaces(s, len); |
365 | 676k | return string_to_bool_internal(s, len, result); |
366 | 676k | } |
367 | | |
368 | | template <PrimitiveType P> |
369 | | static typename PrimitiveTypeTraits<P>::CppType::NativeType string_to_decimal( |
370 | | const char* __restrict s, size_t len, int type_precision, int type_scale, |
371 | | ParseResult* result); |
372 | | |
373 | | template <typename T> |
374 | | static Status split_string_to_map(const std::string& base, const T element_separator, |
375 | | const T key_value_separator, |
376 | | std::map<std::string, std::string>* result) { |
377 | | int key_pos = 0; |
378 | | int key_end; |
379 | | int val_pos; |
380 | | int val_end; |
381 | | |
382 | | while ((key_end = base.find(key_value_separator, key_pos)) != std::string::npos) { |
383 | | if ((val_pos = base.find_first_not_of(key_value_separator, key_end)) == |
384 | | std::string::npos) { |
385 | | break; |
386 | | } |
387 | | if ((val_end = base.find(element_separator, val_pos)) == std::string::npos) { |
388 | | val_end = base.size(); |
389 | | } |
390 | | result->insert(std::make_pair(base.substr(key_pos, key_end - key_pos), |
391 | | base.substr(val_pos, val_end - val_pos))); |
392 | | key_pos = val_end; |
393 | | if (key_pos != std::string::npos) { |
394 | | ++key_pos; |
395 | | } |
396 | | } |
397 | | |
398 | | return Status::OK(); |
399 | | } |
400 | | |
401 | | // This is considerably faster than glibc's implementation. |
402 | | // In the case of overflow, the max/min value for the data type will be returned. |
403 | | // Assumes s represents a decimal number. |
404 | | // Return PARSE_FAILURE on leading whitespace. Trailing whitespace is allowed. |
405 | | template <typename T, bool enable_strict_mode = false> |
406 | | static inline T string_to_int_internal(const char* __restrict s, int len, ParseResult* result); |
407 | | |
408 | | // This is considerably faster than glibc's implementation. |
409 | | // In the case of overflow, the max/min value for the data type will be returned. |
410 | | // Assumes s represents a decimal number. |
411 | | // Return PARSE_FAILURE on leading whitespace. Trailing whitespace is allowed. |
412 | | template <typename T> |
413 | | static inline T string_to_unsigned_int_internal(const char* __restrict s, int len, |
414 | | ParseResult* result); |
415 | | |
416 | | // Convert a string s representing a number in given base into a decimal number. |
417 | | // Return PARSE_FAILURE on leading whitespace. Trailing whitespace is allowed. |
418 | | template <typename T> |
419 | | static inline T string_to_int_internal(const char* __restrict s, int64_t len, int base, |
420 | | ParseResult* result); |
421 | | |
422 | | // Converts an ascii string to an integer of type T assuming it cannot overflow |
423 | | // and the number is positive. |
424 | | // Leading whitespace is not allowed. Trailing whitespace will be skipped. |
425 | | template <typename T, bool enable_strict_mode = false> |
426 | | static inline T string_to_int_no_overflow(const char* __restrict s, int len, |
427 | | ParseResult* result); |
428 | | |
429 | | // zero length, or at least one legal digit. at most consume MAX_LEN digits and stop. or stop when next |
430 | | // char is not a digit. |
431 | | template <typename T> |
432 | | static inline T string_to_uint_greedy_no_overflow(const char* __restrict s, int max_len, |
433 | | ParseResult* result); |
434 | | |
435 | | // This is considerably faster than glibc's implementation (>100x why???) |
436 | | // No special case handling needs to be done for overflows, the floating point spec |
437 | | // already does it and will cap the values to -inf/inf |
438 | | // To avoid inaccurate conversions this function falls back to strtod for |
439 | | // scientific notation. |
440 | | // Return PARSE_FAILURE on leading whitespace. Trailing whitespace is allowed. |
441 | | // TODO: Investigate using intrinsics to speed up the slow strtod path. |
442 | | template <typename T> |
443 | | static inline T string_to_float_internal(const char* __restrict s, int len, |
444 | | ParseResult* result); |
445 | | |
446 | | // parses a string for 'true' or 'false', case insensitive |
447 | | // Return PARSE_FAILURE on leading whitespace. Trailing whitespace is allowed. |
448 | | static inline bool string_to_bool_internal(const char* __restrict s, int len, |
449 | | ParseResult* result); |
450 | | |
451 | | // Returns true if s only contains whitespace. |
452 | 5.35k | static inline bool is_all_whitespace(const char* __restrict s, int len) { |
453 | 12.0k | for (int i = 0; i < len; ++i) { |
454 | 10.3k | if (!LIKELY(is_whitespace_ascii(s[i]))) { |
455 | 3.65k | return false; |
456 | 3.65k | } |
457 | 10.3k | } |
458 | 1.70k | return true; |
459 | 5.35k | } |
460 | | |
461 | | // For strings like "3.0", "3.123", and "3.", can parse them as 3. |
462 | 57.4k | static inline bool is_float_suffix(const char* __restrict s, int len) { |
463 | 57.4k | return (s[0] == '.' && is_all_digit(s + 1, len - 1)); |
464 | 57.4k | } |
465 | | |
466 | 45.9k | static inline bool is_all_digit(const char* __restrict s, int len) { |
467 | 92.1k | for (int i = 0; i < len; ++i) { |
468 | 46.4k | if (!LIKELY(s[i] >= '0' && s[i] <= '9')) { |
469 | 193 | return false; |
470 | 193 | } |
471 | 46.4k | } |
472 | 45.7k | return true; |
473 | 45.9k | } |
474 | | }; // end of class StringParser |
475 | | |
476 | | template <typename T, bool enable_strict_mode> |
477 | 132M | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { |
478 | 132M | if (UNLIKELY(len <= 0)) { |
479 | 102k | *result = PARSE_FAILURE; |
480 | 102k | return 0; |
481 | 102k | } |
482 | | |
483 | 132M | using UnsignedT = MakeUnsignedT<T>; |
484 | 132M | UnsignedT val = 0; |
485 | 132M | UnsignedT max_val = StringParser::numeric_limits<T>(false); |
486 | 132M | bool negative = false; |
487 | 132M | int i = 0; |
488 | 132M | switch (*s) { |
489 | 3.11M | case '-': |
490 | 3.11M | negative = true; |
491 | | // Only signed types have an extra value in their negative range. |
492 | 3.11M | max_val += std::numeric_limits<T>::is_signed; |
493 | 3.11M | [[fallthrough]]; |
494 | 3.12M | case '+': |
495 | 3.12M | ++i; |
496 | | // only one '+'/'-' char, so could return failure directly |
497 | 3.12M | if (UNLIKELY(len == 1)) { |
498 | 6 | *result = PARSE_FAILURE; |
499 | 6 | return 0; |
500 | 6 | } |
501 | 132M | } |
502 | | |
503 | | // This is the fast path where the string cannot overflow. |
504 | 131M | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { |
505 | 130M | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); |
506 | 130M | return static_cast<T>(negative ? -val : val); |
507 | 130M | } |
508 | | |
509 | 1.38M | const T max_div_10 = max_val / 10; |
510 | 1.38M | const T max_mod_10 = max_val % 10; |
511 | | |
512 | 1.38M | int first = i; |
513 | 13.1M | for (; i < len; ++i) { |
514 | 11.8M | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { |
515 | 11.8M | T digit = s[i] - '0'; |
516 | | // This is a tricky check to see if adding this digit will cause an overflow. |
517 | 11.8M | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { |
518 | 82.9k | *result = PARSE_OVERFLOW; |
519 | 82.9k | return negative ? -max_val : max_val; |
520 | 82.9k | } |
521 | 11.7M | val = val * 10 + digit; |
522 | 11.7M | } else { |
523 | 50.0k | if constexpr (enable_strict_mode) { |
524 | 5.07k | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { |
525 | | // Reject the string because the remaining chars are not all whitespace |
526 | 4.43k | *result = PARSE_FAILURE; |
527 | 4.43k | return 0; |
528 | 4.43k | } |
529 | 44.9k | } else { |
530 | | // Save original position where non-digit was found |
531 | 44.9k | int remaining_len = len - i; |
532 | 44.9k | const char* remaining_s = s + i; |
533 | | // Skip trailing whitespaces from the remaining portion |
534 | 44.9k | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); |
535 | 44.9k | if ((UNLIKELY(i == first || (remaining_len != 0 && |
536 | 44.9k | !is_float_suffix(remaining_s, remaining_len))))) { |
537 | | // Reject the string because either the first char was not a digit, |
538 | | // or the remaining chars are not all whitespace |
539 | 31.4k | *result = PARSE_FAILURE; |
540 | 31.4k | return 0; |
541 | 31.4k | } |
542 | 44.9k | } |
543 | | // Returning here is slightly faster than breaking the loop. |
544 | 14.0k | *result = PARSE_SUCCESS; |
545 | 50.0k | return static_cast<T>(negative ? -val : val); |
546 | 50.0k | } |
547 | 11.8M | } |
548 | 1.25M | *result = PARSE_SUCCESS; |
549 | 1.25M | return static_cast<T>(negative ? -val : val); |
550 | 1.38M | } _ZN5doris12StringParser22string_to_int_internalInLb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 1.03M | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 1.03M | if (UNLIKELY(len <= 0)) { | 479 | 10.7k | *result = PARSE_FAILURE; | 480 | 10.7k | return 0; | 481 | 10.7k | } | 482 | | | 483 | 1.02M | using UnsignedT = MakeUnsignedT<T>; | 484 | 1.02M | UnsignedT val = 0; | 485 | 1.02M | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 1.02M | bool negative = false; | 487 | 1.02M | int i = 0; | 488 | 1.02M | switch (*s) { | 489 | 382k | case '-': | 490 | 382k | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 382k | max_val += std::numeric_limits<T>::is_signed; | 493 | 382k | [[fallthrough]]; | 494 | 382k | case '+': | 495 | 382k | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 382k | if (UNLIKELY(len == 1)) { | 498 | 0 | *result = PARSE_FAILURE; | 499 | 0 | return 0; | 500 | 0 | } | 501 | 1.02M | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 1.02M | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 1.02M | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 1.02M | return static_cast<T>(negative ? -val : val); | 507 | 1.02M | } | 508 | | | 509 | 5.24k | const T max_div_10 = max_val / 10; | 510 | 5.24k | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 5.24k | int first = i; | 513 | 196k | for (; i < len; ++i) { | 514 | 192k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 191k | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 191k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 520 | *result = PARSE_OVERFLOW; | 519 | 520 | return negative ? -max_val : max_val; | 520 | 520 | } | 521 | 191k | val = val * 10 + digit; | 522 | 191k | } else { | 523 | | if constexpr (enable_strict_mode) { | 524 | | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | | *result = PARSE_FAILURE; | 527 | | return 0; | 528 | | } | 529 | 490 | } else { | 530 | | // Save original position where non-digit was found | 531 | 490 | int remaining_len = len - i; | 532 | 490 | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | 490 | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | 490 | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | 490 | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | 376 | *result = PARSE_FAILURE; | 540 | 376 | return 0; | 541 | 376 | } | 542 | 490 | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 114 | *result = PARSE_SUCCESS; | 545 | 490 | return static_cast<T>(negative ? -val : val); | 546 | 490 | } | 547 | 192k | } | 548 | 4.23k | *result = PARSE_SUCCESS; | 549 | 4.23k | return static_cast<T>(negative ? -val : val); | 550 | 5.24k | } |
_ZN5doris12StringParser22string_to_int_internalIjLb1EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 1.96k | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 1.96k | if (UNLIKELY(len <= 0)) { | 479 | 7 | *result = PARSE_FAILURE; | 480 | 7 | return 0; | 481 | 7 | } | 482 | | | 483 | 1.95k | using UnsignedT = MakeUnsignedT<T>; | 484 | 1.95k | UnsignedT val = 0; | 485 | 1.95k | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 1.95k | bool negative = false; | 487 | 1.95k | int i = 0; | 488 | 1.95k | switch (*s) { | 489 | 364 | case '-': | 490 | 364 | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 364 | max_val += std::numeric_limits<T>::is_signed; | 493 | 364 | [[fallthrough]]; | 494 | 364 | case '+': | 495 | 364 | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 364 | if (UNLIKELY(len == 1)) { | 498 | 0 | *result = PARSE_FAILURE; | 499 | 0 | return 0; | 500 | 0 | } | 501 | 1.95k | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 1.95k | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 1.35k | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 1.35k | return static_cast<T>(negative ? -val : val); | 507 | 1.35k | } | 508 | | | 509 | 603 | const T max_div_10 = max_val / 10; | 510 | 603 | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 603 | int first = i; | 513 | 4.07k | for (; i < len; ++i) { | 514 | 4.05k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 3.64k | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 3.64k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 168 | *result = PARSE_OVERFLOW; | 519 | 168 | return negative ? -max_val : max_val; | 520 | 168 | } | 521 | 3.47k | val = val * 10 + digit; | 522 | 3.47k | } else { | 523 | 414 | if constexpr (enable_strict_mode) { | 524 | 414 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | 288 | *result = PARSE_FAILURE; | 527 | 288 | return 0; | 528 | 288 | } | 529 | | } else { | 530 | | // Save original position where non-digit was found | 531 | | int remaining_len = len - i; | 532 | | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | | *result = PARSE_FAILURE; | 540 | | return 0; | 541 | | } | 542 | | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 126 | *result = PARSE_SUCCESS; | 545 | 414 | return static_cast<T>(negative ? -val : val); | 546 | 414 | } | 547 | 4.05k | } | 548 | 21 | *result = PARSE_SUCCESS; | 549 | 21 | return static_cast<T>(negative ? -val : val); | 550 | 603 | } |
_ZN5doris12StringParser22string_to_int_internalIaLb1EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 2.96k | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 2.96k | if (UNLIKELY(len <= 0)) { | 479 | 8 | *result = PARSE_FAILURE; | 480 | 8 | return 0; | 481 | 8 | } | 482 | | | 483 | 2.96k | using UnsignedT = MakeUnsignedT<T>; | 484 | 2.96k | UnsignedT val = 0; | 485 | 2.96k | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 2.96k | bool negative = false; | 487 | 2.96k | int i = 0; | 488 | 2.96k | switch (*s) { | 489 | 1.14k | case '-': | 490 | 1.14k | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 1.14k | max_val += std::numeric_limits<T>::is_signed; | 493 | 1.14k | [[fallthrough]]; | 494 | 1.49k | case '+': | 495 | 1.49k | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 1.49k | if (UNLIKELY(len == 1)) { | 498 | 0 | *result = PARSE_FAILURE; | 499 | 0 | return 0; | 500 | 0 | } | 501 | 2.96k | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 2.96k | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 670 | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 670 | return static_cast<T>(negative ? -val : val); | 507 | 670 | } | 508 | | | 509 | 2.29k | const T max_div_10 = max_val / 10; | 510 | 2.29k | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 2.29k | int first = i; | 513 | 7.88k | for (; i < len; ++i) { | 514 | 7.64k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 6.24k | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 6.24k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 656 | *result = PARSE_OVERFLOW; | 519 | 656 | return negative ? -max_val : max_val; | 520 | 656 | } | 521 | 5.59k | val = val * 10 + digit; | 522 | 5.59k | } else { | 523 | 1.40k | if constexpr (enable_strict_mode) { | 524 | 1.40k | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | 1.22k | *result = PARSE_FAILURE; | 527 | 1.22k | return 0; | 528 | 1.22k | } | 529 | | } else { | 530 | | // Save original position where non-digit was found | 531 | | int remaining_len = len - i; | 532 | | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | | *result = PARSE_FAILURE; | 540 | | return 0; | 541 | | } | 542 | | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 172 | *result = PARSE_SUCCESS; | 545 | 1.40k | return static_cast<T>(negative ? -val : val); | 546 | 1.40k | } | 547 | 7.64k | } | 548 | 234 | *result = PARSE_SUCCESS; | 549 | 234 | return static_cast<T>(negative ? -val : val); | 550 | 2.29k | } |
_ZN5doris12StringParser22string_to_int_internalIsLb1EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 2.65k | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 2.65k | if (UNLIKELY(len <= 0)) { | 479 | 8 | *result = PARSE_FAILURE; | 480 | 8 | return 0; | 481 | 8 | } | 482 | | | 483 | 2.64k | using UnsignedT = MakeUnsignedT<T>; | 484 | 2.64k | UnsignedT val = 0; | 485 | 2.64k | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 2.64k | bool negative = false; | 487 | 2.64k | int i = 0; | 488 | 2.64k | switch (*s) { | 489 | 752 | case '-': | 490 | 752 | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 752 | max_val += std::numeric_limits<T>::is_signed; | 493 | 752 | [[fallthrough]]; | 494 | 1.10k | case '+': | 495 | 1.10k | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 1.10k | if (UNLIKELY(len == 1)) { | 498 | 0 | *result = PARSE_FAILURE; | 499 | 0 | return 0; | 500 | 0 | } | 501 | 2.64k | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 2.64k | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 854 | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 854 | return static_cast<T>(negative ? -val : val); | 507 | 854 | } | 508 | | | 509 | 1.79k | const T max_div_10 = max_val / 10; | 510 | 1.79k | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 1.79k | int first = i; | 513 | 8.39k | for (; i < len; ++i) { | 514 | 8.26k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 7.17k | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 7.17k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 576 | *result = PARSE_OVERFLOW; | 519 | 576 | return negative ? -max_val : max_val; | 520 | 576 | } | 521 | 6.60k | val = val * 10 + digit; | 522 | 6.60k | } else { | 523 | 1.08k | if constexpr (enable_strict_mode) { | 524 | 1.08k | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | 1.00k | *result = PARSE_FAILURE; | 527 | 1.00k | return 0; | 528 | 1.00k | } | 529 | | } else { | 530 | | // Save original position where non-digit was found | 531 | | int remaining_len = len - i; | 532 | | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | | *result = PARSE_FAILURE; | 540 | | return 0; | 541 | | } | 542 | | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 88 | *result = PARSE_SUCCESS; | 545 | 1.08k | return static_cast<T>(negative ? -val : val); | 546 | 1.08k | } | 547 | 8.26k | } | 548 | 126 | *result = PARSE_SUCCESS; | 549 | 126 | return static_cast<T>(negative ? -val : val); | 550 | 1.79k | } |
_ZN5doris12StringParser22string_to_int_internalIiLb1EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 3.22k | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 3.22k | if (UNLIKELY(len <= 0)) { | 479 | 14 | *result = PARSE_FAILURE; | 480 | 14 | return 0; | 481 | 14 | } | 482 | | | 483 | 3.20k | using UnsignedT = MakeUnsignedT<T>; | 484 | 3.20k | UnsignedT val = 0; | 485 | 3.20k | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 3.20k | bool negative = false; | 487 | 3.20k | int i = 0; | 488 | 3.20k | switch (*s) { | 489 | 765 | case '-': | 490 | 765 | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 765 | max_val += std::numeric_limits<T>::is_signed; | 493 | 765 | [[fallthrough]]; | 494 | 1.10k | case '+': | 495 | 1.10k | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 1.10k | if (UNLIKELY(len == 1)) { | 498 | 0 | *result = PARSE_FAILURE; | 499 | 0 | return 0; | 500 | 0 | } | 501 | 3.20k | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 3.20k | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 1.74k | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 1.74k | return static_cast<T>(negative ? -val : val); | 507 | 1.74k | } | 508 | | | 509 | 1.46k | const T max_div_10 = max_val / 10; | 510 | 1.46k | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 1.46k | int first = i; | 513 | 11.6k | for (; i < len; ++i) { | 514 | 11.5k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 10.7k | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 10.7k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 552 | *result = PARSE_OVERFLOW; | 519 | 552 | return negative ? -max_val : max_val; | 520 | 552 | } | 521 | 10.2k | val = val * 10 + digit; | 522 | 10.2k | } else { | 523 | 795 | if constexpr (enable_strict_mode) { | 524 | 795 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | 735 | *result = PARSE_FAILURE; | 527 | 735 | return 0; | 528 | 735 | } | 529 | | } else { | 530 | | // Save original position where non-digit was found | 531 | | int remaining_len = len - i; | 532 | | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | | *result = PARSE_FAILURE; | 540 | | return 0; | 541 | | } | 542 | | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 60 | *result = PARSE_SUCCESS; | 545 | 795 | return static_cast<T>(negative ? -val : val); | 546 | 795 | } | 547 | 11.5k | } | 548 | 120 | *result = PARSE_SUCCESS; | 549 | 120 | return static_cast<T>(negative ? -val : val); | 550 | 1.46k | } |
_ZN5doris12StringParser22string_to_int_internalIlLb1EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 3.70k | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 3.70k | if (UNLIKELY(len <= 0)) { | 479 | 18 | *result = PARSE_FAILURE; | 480 | 18 | return 0; | 481 | 18 | } | 482 | | | 483 | 3.68k | using UnsignedT = MakeUnsignedT<T>; | 484 | 3.68k | UnsignedT val = 0; | 485 | 3.68k | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 3.68k | bool negative = false; | 487 | 3.68k | int i = 0; | 488 | 3.68k | switch (*s) { | 489 | 1.14k | case '-': | 490 | 1.14k | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 1.14k | max_val += std::numeric_limits<T>::is_signed; | 493 | 1.14k | [[fallthrough]]; | 494 | 1.60k | case '+': | 495 | 1.60k | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 1.60k | if (UNLIKELY(len == 1)) { | 498 | 4 | *result = PARSE_FAILURE; | 499 | 4 | return 0; | 500 | 4 | } | 501 | 3.68k | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 3.68k | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 1.93k | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 1.93k | return static_cast<T>(negative ? -val : val); | 507 | 1.93k | } | 508 | | | 509 | 1.75k | const T max_div_10 = max_val / 10; | 510 | 1.75k | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 1.75k | int first = i; | 513 | 27.8k | for (; i < len; ++i) { | 514 | 27.6k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 26.8k | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 26.8k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 760 | *result = PARSE_OVERFLOW; | 519 | 760 | return negative ? -max_val : max_val; | 520 | 760 | } | 521 | 26.1k | val = val * 10 + digit; | 522 | 26.1k | } else { | 523 | 801 | if constexpr (enable_strict_mode) { | 524 | 801 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | 685 | *result = PARSE_FAILURE; | 527 | 685 | return 0; | 528 | 685 | } | 529 | | } else { | 530 | | // Save original position where non-digit was found | 531 | | int remaining_len = len - i; | 532 | | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | | *result = PARSE_FAILURE; | 540 | | return 0; | 541 | | } | 542 | | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 116 | *result = PARSE_SUCCESS; | 545 | 801 | return static_cast<T>(negative ? -val : val); | 546 | 801 | } | 547 | 27.6k | } | 548 | 190 | *result = PARSE_SUCCESS; | 549 | 190 | return static_cast<T>(negative ? -val : val); | 550 | 1.75k | } |
_ZN5doris12StringParser22string_to_int_internalInLb1EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 2.77k | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 2.77k | if (UNLIKELY(len <= 0)) { | 479 | 8 | *result = PARSE_FAILURE; | 480 | 8 | return 0; | 481 | 8 | } | 482 | | | 483 | 2.77k | using UnsignedT = MakeUnsignedT<T>; | 484 | 2.77k | UnsignedT val = 0; | 485 | 2.77k | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 2.77k | bool negative = false; | 487 | 2.77k | int i = 0; | 488 | 2.77k | switch (*s) { | 489 | 829 | case '-': | 490 | 829 | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 829 | max_val += std::numeric_limits<T>::is_signed; | 493 | 829 | [[fallthrough]]; | 494 | 1.16k | case '+': | 495 | 1.16k | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 1.16k | if (UNLIKELY(len == 1)) { | 498 | 0 | *result = PARSE_FAILURE; | 499 | 0 | return 0; | 500 | 0 | } | 501 | 2.77k | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 2.77k | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 1.58k | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 1.58k | return static_cast<T>(negative ? -val : val); | 507 | 1.58k | } | 508 | | | 509 | 1.18k | const T max_div_10 = max_val / 10; | 510 | 1.18k | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 1.18k | int first = i; | 513 | 36.0k | for (; i < len; ++i) { | 514 | 35.9k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 35.3k | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 35.3k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 504 | *result = PARSE_OVERFLOW; | 519 | 504 | return negative ? -max_val : max_val; | 520 | 504 | } | 521 | 34.8k | val = val * 10 + digit; | 522 | 34.8k | } else { | 523 | 572 | if constexpr (enable_strict_mode) { | 524 | 572 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | 498 | *result = PARSE_FAILURE; | 527 | 498 | return 0; | 528 | 498 | } | 529 | | } else { | 530 | | // Save original position where non-digit was found | 531 | | int remaining_len = len - i; | 532 | | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | | *result = PARSE_FAILURE; | 540 | | return 0; | 541 | | } | 542 | | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 74 | *result = PARSE_SUCCESS; | 545 | 572 | return static_cast<T>(negative ? -val : val); | 546 | 572 | } | 547 | 35.9k | } | 548 | 107 | *result = PARSE_SUCCESS; | 549 | 107 | return static_cast<T>(negative ? -val : val); | 550 | 1.18k | } |
_ZN5doris12StringParser22string_to_int_internalIaLb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 5.99M | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 5.99M | if (UNLIKELY(len <= 0)) { | 479 | 28.0k | *result = PARSE_FAILURE; | 480 | 28.0k | return 0; | 481 | 28.0k | } | 482 | | | 483 | 5.96M | using UnsignedT = MakeUnsignedT<T>; | 484 | 5.96M | UnsignedT val = 0; | 485 | 5.96M | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 5.96M | bool negative = false; | 487 | 5.96M | int i = 0; | 488 | 5.96M | switch (*s) { | 489 | 402k | case '-': | 490 | 402k | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 402k | max_val += std::numeric_limits<T>::is_signed; | 493 | 402k | [[fallthrough]]; | 494 | 403k | case '+': | 495 | 403k | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 403k | if (UNLIKELY(len == 1)) { | 498 | 0 | *result = PARSE_FAILURE; | 499 | 0 | return 0; | 500 | 0 | } | 501 | 5.96M | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 5.96M | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 5.71M | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 5.71M | return static_cast<T>(negative ? -val : val); | 507 | 5.71M | } | 508 | | | 509 | 256k | const T max_div_10 = max_val / 10; | 510 | 256k | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 256k | int first = i; | 513 | 895k | for (; i < len; ++i) { | 514 | 722k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 685k | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 685k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 46.5k | *result = PARSE_OVERFLOW; | 519 | 46.5k | return negative ? -max_val : max_val; | 520 | 46.5k | } | 521 | 639k | val = val * 10 + digit; | 522 | 639k | } else { | 523 | | if constexpr (enable_strict_mode) { | 524 | | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | | *result = PARSE_FAILURE; | 527 | | return 0; | 528 | | } | 529 | 36.9k | } else { | 530 | | // Save original position where non-digit was found | 531 | 36.9k | int remaining_len = len - i; | 532 | 36.9k | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | 36.9k | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | 36.9k | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | 36.9k | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | 25.4k | *result = PARSE_FAILURE; | 540 | 25.4k | return 0; | 541 | 25.4k | } | 542 | 36.9k | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 11.4k | *result = PARSE_SUCCESS; | 545 | 36.9k | return static_cast<T>(negative ? -val : val); | 546 | 36.9k | } | 547 | 722k | } | 548 | 172k | *result = PARSE_SUCCESS; | 549 | 172k | return static_cast<T>(negative ? -val : val); | 550 | 256k | } |
_ZN5doris12StringParser22string_to_int_internalIsLb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 1.11M | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 1.11M | if (UNLIKELY(len <= 0)) { | 479 | 14.6k | *result = PARSE_FAILURE; | 480 | 14.6k | return 0; | 481 | 14.6k | } | 482 | | | 483 | 1.10M | using UnsignedT = MakeUnsignedT<T>; | 484 | 1.10M | UnsignedT val = 0; | 485 | 1.10M | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 1.10M | bool negative = false; | 487 | 1.10M | int i = 0; | 488 | 1.10M | switch (*s) { | 489 | 409k | case '-': | 490 | 409k | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 409k | max_val += std::numeric_limits<T>::is_signed; | 493 | 409k | [[fallthrough]]; | 494 | 410k | case '+': | 495 | 410k | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 410k | if (UNLIKELY(len == 1)) { | 498 | 0 | *result = PARSE_FAILURE; | 499 | 0 | return 0; | 500 | 0 | } | 501 | 1.10M | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 1.10M | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 517k | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 517k | return static_cast<T>(negative ? -val : val); | 507 | 517k | } | 508 | | | 509 | 584k | const T max_div_10 = max_val / 10; | 510 | 584k | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 584k | int first = i; | 513 | 3.48M | for (; i < len; ++i) { | 514 | 2.92M | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 2.91M | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 2.91M | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 20.6k | *result = PARSE_OVERFLOW; | 519 | 20.6k | return negative ? -max_val : max_val; | 520 | 20.6k | } | 521 | 2.89M | val = val * 10 + digit; | 522 | 2.89M | } else { | 523 | | if constexpr (enable_strict_mode) { | 524 | | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | | *result = PARSE_FAILURE; | 527 | | return 0; | 528 | | } | 529 | 2.41k | } else { | 530 | | // Save original position where non-digit was found | 531 | 2.41k | int remaining_len = len - i; | 532 | 2.41k | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | 2.41k | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | 2.41k | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | 2.41k | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | 1.80k | *result = PARSE_FAILURE; | 540 | 1.80k | return 0; | 541 | 1.80k | } | 542 | 2.41k | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 612 | *result = PARSE_SUCCESS; | 545 | 2.41k | return static_cast<T>(negative ? -val : val); | 546 | 2.41k | } | 547 | 2.92M | } | 548 | 561k | *result = PARSE_SUCCESS; | 549 | 561k | return static_cast<T>(negative ? -val : val); | 550 | 584k | } |
_ZN5doris12StringParser22string_to_int_internalIiLb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 52.3M | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 52.3M | if (UNLIKELY(len <= 0)) { | 479 | 22.8k | *result = PARSE_FAILURE; | 480 | 22.8k | return 0; | 481 | 22.8k | } | 482 | | | 483 | 52.2M | using UnsignedT = MakeUnsignedT<T>; | 484 | 52.2M | UnsignedT val = 0; | 485 | 52.2M | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 52.2M | bool negative = false; | 487 | 52.2M | int i = 0; | 488 | 52.2M | switch (*s) { | 489 | 852k | case '-': | 490 | 852k | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 852k | max_val += std::numeric_limits<T>::is_signed; | 493 | 852k | [[fallthrough]]; | 494 | 853k | case '+': | 495 | 853k | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 853k | if (UNLIKELY(len == 1)) { | 498 | 2 | *result = PARSE_FAILURE; | 499 | 2 | return 0; | 500 | 2 | } | 501 | 52.2M | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 52.2M | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 52.0M | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 52.0M | return static_cast<T>(negative ? -val : val); | 507 | 52.0M | } | 508 | | | 509 | 191k | const T max_div_10 = max_val / 10; | 510 | 191k | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 191k | int first = i; | 513 | 2.00M | for (; i < len; ++i) { | 514 | 1.81M | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 1.81M | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 1.81M | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 5.88k | *result = PARSE_OVERFLOW; | 519 | 5.88k | return negative ? -max_val : max_val; | 520 | 5.88k | } | 521 | 1.81M | val = val * 10 + digit; | 522 | 1.81M | } else { | 523 | | if constexpr (enable_strict_mode) { | 524 | | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | | *result = PARSE_FAILURE; | 527 | | return 0; | 528 | | } | 529 | 2.02k | } else { | 530 | | // Save original position where non-digit was found | 531 | 2.02k | int remaining_len = len - i; | 532 | 2.02k | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | 2.02k | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | 2.02k | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | 2.02k | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | 1.64k | *result = PARSE_FAILURE; | 540 | 1.64k | return 0; | 541 | 1.64k | } | 542 | 2.02k | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 388 | *result = PARSE_SUCCESS; | 545 | 2.02k | return static_cast<T>(negative ? -val : val); | 546 | 2.02k | } | 547 | 1.81M | } | 548 | 183k | *result = PARSE_SUCCESS; | 549 | 183k | return static_cast<T>(negative ? -val : val); | 550 | 191k | } |
_ZN5doris12StringParser22string_to_int_internalIlLb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 71.7M | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 71.7M | if (UNLIKELY(len <= 0)) { | 479 | 26.4k | *result = PARSE_FAILURE; | 480 | 26.4k | return 0; | 481 | 26.4k | } | 482 | | | 483 | 71.6M | using UnsignedT = MakeUnsignedT<T>; | 484 | 71.6M | UnsignedT val = 0; | 485 | 71.6M | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 71.6M | bool negative = false; | 487 | 71.6M | int i = 0; | 488 | 71.6M | switch (*s) { | 489 | 1.06M | case '-': | 490 | 1.06M | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 1.06M | max_val += std::numeric_limits<T>::is_signed; | 493 | 1.06M | [[fallthrough]]; | 494 | 1.06M | case '+': | 495 | 1.06M | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 1.06M | if (UNLIKELY(len == 1)) { | 498 | 0 | *result = PARSE_FAILURE; | 499 | 0 | return 0; | 500 | 0 | } | 501 | 71.6M | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 71.6M | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 71.2M | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 71.2M | return static_cast<T>(negative ? -val : val); | 507 | 71.2M | } | 508 | | | 509 | 339k | const T max_div_10 = max_val / 10; | 510 | 339k | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 339k | int first = i; | 513 | 6.39M | for (; i < len; ++i) { | 514 | 6.06M | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 6.06M | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 6.06M | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 5.56k | *result = PARSE_OVERFLOW; | 519 | 5.56k | return negative ? -max_val : max_val; | 520 | 5.56k | } | 521 | 6.05M | val = val * 10 + digit; | 522 | 6.05M | } else { | 523 | | if constexpr (enable_strict_mode) { | 524 | | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | | *result = PARSE_FAILURE; | 527 | | return 0; | 528 | | } | 529 | 1.59k | } else { | 530 | | // Save original position where non-digit was found | 531 | 1.59k | int remaining_len = len - i; | 532 | 1.59k | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | 1.59k | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | 1.59k | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | 1.59k | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | 1.25k | *result = PARSE_FAILURE; | 540 | 1.25k | return 0; | 541 | 1.25k | } | 542 | 1.59k | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 340 | *result = PARSE_SUCCESS; | 545 | 1.59k | return static_cast<T>(negative ? -val : val); | 546 | 1.59k | } | 547 | 6.06M | } | 548 | 332k | *result = PARSE_SUCCESS; | 549 | 332k | return static_cast<T>(negative ? -val : val); | 550 | 339k | } |
_ZN5doris12StringParser22string_to_int_internalIjLb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 841 | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 841 | if (UNLIKELY(len <= 0)) { | 479 | 0 | *result = PARSE_FAILURE; | 480 | 0 | return 0; | 481 | 0 | } | 482 | | | 483 | 841 | using UnsignedT = MakeUnsignedT<T>; | 484 | 841 | UnsignedT val = 0; | 485 | 841 | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 841 | bool negative = false; | 487 | 841 | int i = 0; | 488 | 841 | switch (*s) { | 489 | 357 | case '-': | 490 | 357 | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 357 | max_val += std::numeric_limits<T>::is_signed; | 493 | 357 | [[fallthrough]]; | 494 | 357 | case '+': | 495 | 357 | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 357 | if (UNLIKELY(len == 1)) { | 498 | 0 | *result = PARSE_FAILURE; | 499 | 0 | return 0; | 500 | 0 | } | 501 | 841 | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 841 | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 238 | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 238 | return static_cast<T>(negative ? -val : val); | 507 | 238 | } | 508 | | | 509 | 603 | const T max_div_10 = max_val / 10; | 510 | 603 | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 603 | int first = i; | 513 | 4.07k | for (; i < len; ++i) { | 514 | 4.05k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 3.64k | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 3.64k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 168 | *result = PARSE_OVERFLOW; | 519 | 168 | return negative ? -max_val : max_val; | 520 | 168 | } | 521 | 3.47k | val = val * 10 + digit; | 522 | 3.47k | } else { | 523 | | if constexpr (enable_strict_mode) { | 524 | | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | | *result = PARSE_FAILURE; | 527 | | return 0; | 528 | | } | 529 | 414 | } else { | 530 | | // Save original position where non-digit was found | 531 | 414 | int remaining_len = len - i; | 532 | 414 | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | 414 | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | 414 | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | 414 | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | 288 | *result = PARSE_FAILURE; | 540 | 288 | return 0; | 541 | 288 | } | 542 | 414 | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 126 | *result = PARSE_SUCCESS; | 545 | 414 | return static_cast<T>(negative ? -val : val); | 546 | 414 | } | 547 | 4.05k | } | 548 | 21 | *result = PARSE_SUCCESS; | 549 | 21 | return static_cast<T>(negative ? -val : val); | 550 | 603 | } |
_ZN5doris12StringParser22string_to_int_internalImLb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 5.62k | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 5.62k | if (UNLIKELY(len <= 0)) { | 479 | 0 | *result = PARSE_FAILURE; | 480 | 0 | return 0; | 481 | 0 | } | 482 | | | 483 | 5.62k | using UnsignedT = MakeUnsignedT<T>; | 484 | 5.62k | UnsignedT val = 0; | 485 | 5.62k | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 5.62k | bool negative = false; | 487 | 5.62k | int i = 0; | 488 | 5.62k | switch (*s) { | 489 | 357 | case '-': | 490 | 357 | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 357 | max_val += std::numeric_limits<T>::is_signed; | 493 | 357 | [[fallthrough]]; | 494 | 357 | case '+': | 495 | 357 | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 357 | if (UNLIKELY(len == 1)) { | 498 | 0 | *result = PARSE_FAILURE; | 499 | 0 | return 0; | 500 | 0 | } | 501 | 5.62k | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 5.62k | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 5.05k | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 5.05k | return static_cast<T>(negative ? -val : val); | 507 | 5.05k | } | 508 | | | 509 | 567 | const T max_div_10 = max_val / 10; | 510 | 567 | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 567 | int first = i; | 513 | 6.69k | for (; i < len; ++i) { | 514 | 6.67k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 6.30k | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 6.30k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 168 | *result = PARSE_OVERFLOW; | 519 | 168 | return negative ? -max_val : max_val; | 520 | 168 | } | 521 | 6.13k | val = val * 10 + digit; | 522 | 6.13k | } else { | 523 | | if constexpr (enable_strict_mode) { | 524 | | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | | *result = PARSE_FAILURE; | 527 | | return 0; | 528 | | } | 529 | 378 | } else { | 530 | | // Save original position where non-digit was found | 531 | 378 | int remaining_len = len - i; | 532 | 378 | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | 378 | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | 378 | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | 378 | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | 252 | *result = PARSE_FAILURE; | 540 | 252 | return 0; | 541 | 252 | } | 542 | 378 | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 126 | *result = PARSE_SUCCESS; | 545 | 378 | return static_cast<T>(negative ? -val : val); | 546 | 378 | } | 547 | 6.67k | } | 548 | 21 | *result = PARSE_SUCCESS; | 549 | 21 | return static_cast<T>(negative ? -val : val); | 550 | 567 | } |
_ZN5doris12StringParser22string_to_int_internalIN4wide7integerILm256EiEELb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 4 | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 4 | if (UNLIKELY(len <= 0)) { | 479 | 0 | *result = PARSE_FAILURE; | 480 | 0 | return 0; | 481 | 0 | } | 482 | | | 483 | 4 | using UnsignedT = MakeUnsignedT<T>; | 484 | 4 | UnsignedT val = 0; | 485 | 4 | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 4 | bool negative = false; | 487 | 4 | int i = 0; | 488 | 4 | switch (*s) { | 489 | 0 | case '-': | 490 | 0 | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 0 | max_val += std::numeric_limits<T>::is_signed; | 493 | 0 | [[fallthrough]]; | 494 | 0 | case '+': | 495 | 0 | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 0 | if (UNLIKELY(len == 1)) { | 498 | 0 | *result = PARSE_FAILURE; | 499 | 0 | return 0; | 500 | 0 | } | 501 | 4 | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 4 | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 4 | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 4 | return static_cast<T>(negative ? -val : val); | 507 | 4 | } | 508 | | | 509 | 0 | const T max_div_10 = max_val / 10; | 510 | 0 | const T max_mod_10 = max_val % 10; | 511 | |
| 512 | 0 | int first = i; | 513 | 0 | for (; i < len; ++i) { | 514 | 0 | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 0 | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 0 | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 0 | *result = PARSE_OVERFLOW; | 519 | 0 | return negative ? -max_val : max_val; | 520 | 0 | } | 521 | 0 | val = val * 10 + digit; | 522 | 0 | } else { | 523 | | if constexpr (enable_strict_mode) { | 524 | | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | | *result = PARSE_FAILURE; | 527 | | return 0; | 528 | | } | 529 | 0 | } else { | 530 | | // Save original position where non-digit was found | 531 | 0 | int remaining_len = len - i; | 532 | 0 | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | 0 | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | 0 | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | 0 | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | 0 | *result = PARSE_FAILURE; | 540 | 0 | return 0; | 541 | 0 | } | 542 | 0 | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 0 | *result = PARSE_SUCCESS; | 545 | 0 | return static_cast<T>(negative ? -val : val); | 546 | 0 | } | 547 | 0 | } | 548 | 0 | *result = PARSE_SUCCESS; | 549 | 0 | return static_cast<T>(negative ? -val : val); | 550 | 0 | } |
_ZN5doris12StringParser22string_to_int_internalIoLb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 477 | 1.81k | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 478 | 1.81k | if (UNLIKELY(len <= 0)) { | 479 | 0 | *result = PARSE_FAILURE; | 480 | 0 | return 0; | 481 | 0 | } | 482 | | | 483 | 1.81k | using UnsignedT = MakeUnsignedT<T>; | 484 | 1.81k | UnsignedT val = 0; | 485 | 1.81k | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 486 | 1.81k | bool negative = false; | 487 | 1.81k | int i = 0; | 488 | 1.81k | switch (*s) { | 489 | 357 | case '-': | 490 | 357 | negative = true; | 491 | | // Only signed types have an extra value in their negative range. | 492 | 357 | max_val += std::numeric_limits<T>::is_signed; | 493 | 357 | [[fallthrough]]; | 494 | 357 | case '+': | 495 | 357 | ++i; | 496 | | // only one '+'/'-' char, so could return failure directly | 497 | 357 | if (UNLIKELY(len == 1)) { | 498 | 0 | *result = PARSE_FAILURE; | 499 | 0 | return 0; | 500 | 0 | } | 501 | 1.81k | } | 502 | | | 503 | | // This is the fast path where the string cannot overflow. | 504 | 1.81k | if (LIKELY(len - i < NumberTraits::max_ascii_len<T>())) { | 505 | 0 | val = string_to_int_no_overflow<UnsignedT, enable_strict_mode>(s + i, len - i, result); | 506 | 0 | return static_cast<T>(negative ? -val : val); | 507 | 0 | } | 508 | | | 509 | 1.81k | const T max_div_10 = max_val / 10; | 510 | 1.81k | const T max_mod_10 = max_val % 10; | 511 | | | 512 | 1.81k | int first = i; | 513 | 51.0k | for (; i < len; ++i) { | 514 | 50.0k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 515 | 49.4k | T digit = s[i] - '0'; | 516 | | // This is a tricky check to see if adding this digit will cause an overflow. | 517 | 49.4k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { | 518 | 168 | *result = PARSE_OVERFLOW; | 519 | 168 | return negative ? -max_val : max_val; | 520 | 168 | } | 521 | 49.2k | val = val * 10 + digit; | 522 | 49.2k | } else { | 523 | | if constexpr (enable_strict_mode) { | 524 | | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { | 525 | | // Reject the string because the remaining chars are not all whitespace | 526 | | *result = PARSE_FAILURE; | 527 | | return 0; | 528 | | } | 529 | 637 | } else { | 530 | | // Save original position where non-digit was found | 531 | 637 | int remaining_len = len - i; | 532 | 637 | const char* remaining_s = s + i; | 533 | | // Skip trailing whitespaces from the remaining portion | 534 | 637 | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 535 | 637 | if ((UNLIKELY(i == first || (remaining_len != 0 && | 536 | 637 | !is_float_suffix(remaining_s, remaining_len))))) { | 537 | | // Reject the string because either the first char was not a digit, | 538 | | // or the remaining chars are not all whitespace | 539 | 378 | *result = PARSE_FAILURE; | 540 | 378 | return 0; | 541 | 378 | } | 542 | 637 | } | 543 | | // Returning here is slightly faster than breaking the loop. | 544 | 259 | *result = PARSE_SUCCESS; | 545 | 637 | return static_cast<T>(negative ? -val : val); | 546 | 637 | } | 547 | 50.0k | } | 548 | 1.01k | *result = PARSE_SUCCESS; | 549 | 1.01k | return static_cast<T>(negative ? -val : val); | 550 | 1.81k | } |
|
551 | | |
552 | | template <typename T> |
553 | | T StringParser::string_to_unsigned_int_internal(const char* __restrict s, int len, |
554 | 3.81k | ParseResult* result) { |
555 | 3.81k | if (UNLIKELY(len <= 0)) { |
556 | 0 | *result = PARSE_FAILURE; |
557 | 0 | return 0; |
558 | 0 | } |
559 | | |
560 | 3.81k | T val = 0; |
561 | 3.81k | T max_val = std::numeric_limits<T>::max(); |
562 | 3.81k | int i = 0; |
563 | | |
564 | 3.81k | using signedT = MakeSignedT<T>; |
565 | | // This is the fast path where the string cannot overflow. |
566 | 3.81k | if (LIKELY(len - i < NumberTraits::max_ascii_len<signedT>())) { |
567 | 3.71k | val = string_to_int_no_overflow<T>(s + i, len - i, result); |
568 | 3.71k | return val; |
569 | 3.71k | } |
570 | | |
571 | 98 | const T max_div_10 = max_val / 10; |
572 | 98 | const T max_mod_10 = max_val % 10; |
573 | | |
574 | 98 | int first = i; |
575 | 2.00k | for (; i < len; ++i) { |
576 | 1.96k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { |
577 | 1.96k | T digit = s[i] - '0'; |
578 | | // This is a tricky check to see if adding this digit will cause an overflow. |
579 | 1.96k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) { |
580 | 49 | *result = PARSE_OVERFLOW; |
581 | 49 | return max_val; |
582 | 49 | } |
583 | 1.91k | val = val * 10 + digit; |
584 | 1.91k | } else { |
585 | 0 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { |
586 | | // Reject the string because either the first char was not a digit, |
587 | | // or the remaining chars are not all whitespace |
588 | 0 | *result = PARSE_FAILURE; |
589 | 0 | return 0; |
590 | 0 | } |
591 | | // Returning here is slightly faster than breaking the loop. |
592 | 0 | *result = PARSE_SUCCESS; |
593 | 0 | return val; |
594 | 0 | } |
595 | 1.96k | } |
596 | 49 | *result = PARSE_SUCCESS; |
597 | 49 | return val; |
598 | 98 | } |
599 | | |
600 | | template <typename T> |
601 | | T StringParser::string_to_int_internal(const char* __restrict s, int64_t len, int base, |
602 | 3.49k | ParseResult* result) { |
603 | 3.49k | using UnsignedT = MakeUnsignedT<T>; |
604 | 3.49k | UnsignedT val = 0; |
605 | 3.49k | UnsignedT max_val = StringParser::numeric_limits<T>(false); |
606 | 3.49k | bool negative = false; |
607 | 3.49k | if (UNLIKELY(len <= 0)) { |
608 | 19 | *result = PARSE_FAILURE; |
609 | 19 | return 0; |
610 | 19 | } |
611 | 3.47k | int i = 0; |
612 | 3.47k | switch (*s) { |
613 | 1.53k | case '-': |
614 | 1.53k | negative = true; |
615 | | // Only signed types have an extra value in their negative range. |
616 | | // Keep the unsigned magnitude limit unchanged to avoid wrapping it to zero. |
617 | 1.53k | max_val += std::numeric_limits<T>::is_signed; |
618 | 1.53k | [[fallthrough]]; |
619 | 1.53k | case '+': |
620 | 1.53k | i = 1; |
621 | 3.47k | } |
622 | | |
623 | 3.47k | const T max_div_base = max_val / base; |
624 | 3.47k | const T max_mod_base = max_val % base; |
625 | | |
626 | 3.47k | int first = i; |
627 | 16.0k | for (; i < len; ++i) { |
628 | 12.9k | T digit; |
629 | 12.9k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { |
630 | 12.5k | digit = s[i] - '0'; |
631 | 12.5k | } else if (s[i] >= 'a' && s[i] <= 'z') { |
632 | 314 | digit = (s[i] - 'a' + 10); |
633 | 314 | } else if (s[i] >= 'A' && s[i] <= 'Z') { |
634 | 24 | digit = (s[i] - 'A' + 10); |
635 | 24 | } else { |
636 | 8 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) { |
637 | | // Reject the string because either the first char was not an alpha/digit, |
638 | | // or the remaining chars are not all whitespace |
639 | 8 | *result = PARSE_FAILURE; |
640 | 8 | return 0; |
641 | 8 | } |
642 | | // skip trailing whitespace. |
643 | 0 | break; |
644 | 8 | } |
645 | | |
646 | | // Bail, if we encounter a digit that is not available in base. |
647 | 12.9k | if (digit >= base) { |
648 | 257 | break; |
649 | 257 | } |
650 | | |
651 | | // This is a tricky check to see if adding this digit will cause an overflow. |
652 | 12.6k | if (UNLIKELY(val > (max_div_base - (digit > max_mod_base)))) { |
653 | 100 | *result = PARSE_OVERFLOW; |
654 | 100 | return static_cast<T>(negative ? -max_val : max_val); |
655 | 100 | } |
656 | 12.5k | val = val * base + digit; |
657 | 12.5k | } |
658 | 3.36k | *result = PARSE_SUCCESS; |
659 | 3.36k | return static_cast<T>(negative ? -val : val); |
660 | 3.47k | } |
661 | | |
662 | | template <typename T, bool enable_strict_mode> |
663 | 130M | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { |
664 | 130M | T val = 0; |
665 | 130M | if (UNLIKELY(len == 0)) { |
666 | 0 | *result = PARSE_SUCCESS; |
667 | 0 | return val; |
668 | 0 | } |
669 | | // Factor out the first char for error handling speeds up the loop. |
670 | 130M | if (LIKELY(s[0] >= '0' && s[0] <= '9')) { |
671 | 130M | val = s[0] - '0'; |
672 | 18.4E | } else { |
673 | 18.4E | *result = PARSE_FAILURE; |
674 | 18.4E | return 0; |
675 | 18.4E | } |
676 | 541M | for (int i = 1; i < len; ++i) { |
677 | 411M | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { |
678 | 411M | T digit = s[i] - '0'; |
679 | 411M | val = val * 10 + digit; |
680 | 411M | } else { |
681 | 53.9k | if constexpr (enable_strict_mode) { |
682 | 1.84k | if (UNLIKELY(!is_all_whitespace(s + i, len - i))) { |
683 | 1.49k | *result = PARSE_FAILURE; |
684 | 1.49k | return 0; |
685 | 1.49k | } |
686 | 52.0k | } else { |
687 | | // Save original position where non-digit was found |
688 | 52.0k | int remaining_len = len - i; |
689 | 52.0k | const char* remaining_s = s + i; |
690 | | // Skip trailing whitespaces from the remaining portion |
691 | 52.0k | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); |
692 | 52.0k | if ((UNLIKELY(remaining_len != 0 && |
693 | 52.0k | !is_float_suffix(remaining_s, remaining_len)))) { |
694 | 11.0k | *result = PARSE_FAILURE; |
695 | 11.0k | return 0; |
696 | 11.0k | } |
697 | 52.0k | } |
698 | 41.3k | *result = PARSE_SUCCESS; |
699 | 53.9k | return val; |
700 | 53.9k | } |
701 | 411M | } |
702 | 130M | *result = PARSE_SUCCESS; |
703 | 130M | return val; |
704 | 130M | } _ZN5doris12StringParser25string_to_int_no_overflowIoLb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 663 | 1.02M | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 664 | 1.02M | T val = 0; | 665 | 1.02M | if (UNLIKELY(len == 0)) { | 666 | 0 | *result = PARSE_SUCCESS; | 667 | 0 | return val; | 668 | 0 | } | 669 | | // Factor out the first char for error handling speeds up the loop. | 670 | 1.02M | if (LIKELY(s[0] >= '0' && s[0] <= '9')) { | 671 | 1.02M | val = s[0] - '0'; | 672 | 1.02M | } else { | 673 | 1.47k | *result = PARSE_FAILURE; | 674 | 1.47k | return 0; | 675 | 1.47k | } | 676 | 9.61M | for (int i = 1; i < len; ++i) { | 677 | 8.60M | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 678 | 8.59M | T digit = s[i] - '0'; | 679 | 8.59M | val = val * 10 + digit; | 680 | 8.59M | } else { | 681 | | if constexpr (enable_strict_mode) { | 682 | | if (UNLIKELY(!is_all_whitespace(s + i, len - i))) { | 683 | | *result = PARSE_FAILURE; | 684 | | return 0; | 685 | | } | 686 | 10.6k | } else { | 687 | | // Save original position where non-digit was found | 688 | 10.6k | int remaining_len = len - i; | 689 | 10.6k | const char* remaining_s = s + i; | 690 | | // Skip trailing whitespaces from the remaining portion | 691 | 10.6k | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 692 | 10.6k | if ((UNLIKELY(remaining_len != 0 && | 693 | 10.6k | !is_float_suffix(remaining_s, remaining_len)))) { | 694 | 10.3k | *result = PARSE_FAILURE; | 695 | 10.3k | return 0; | 696 | 10.3k | } | 697 | 10.6k | } | 698 | 274 | *result = PARSE_SUCCESS; | 699 | 10.6k | return val; | 700 | 10.6k | } | 701 | 8.60M | } | 702 | 1.00M | *result = PARSE_SUCCESS; | 703 | 1.00M | return val; | 704 | 1.02M | } |
_ZN5doris12StringParser25string_to_int_no_overflowIjLb1EEET_PKciPNS0_11ParseResultE Line | Count | Source | 663 | 3.09k | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 664 | 3.09k | T val = 0; | 665 | 3.09k | if (UNLIKELY(len == 0)) { | 666 | 0 | *result = PARSE_SUCCESS; | 667 | 0 | return val; | 668 | 0 | } | 669 | | // Factor out the first char for error handling speeds up the loop. | 670 | 3.09k | if (LIKELY(s[0] >= '0' && s[0] <= '9')) { | 671 | 2.85k | val = s[0] - '0'; | 672 | 2.85k | } else { | 673 | 241 | *result = PARSE_FAILURE; | 674 | 241 | return 0; | 675 | 241 | } | 676 | 7.41k | for (int i = 1; i < len; ++i) { | 677 | 5.02k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 678 | 4.56k | T digit = s[i] - '0'; | 679 | 4.56k | val = val * 10 + digit; | 680 | 4.56k | } else { | 681 | 460 | if constexpr (enable_strict_mode) { | 682 | 460 | if (UNLIKELY(!is_all_whitespace(s + i, len - i))) { | 683 | 348 | *result = PARSE_FAILURE; | 684 | 348 | return 0; | 685 | 348 | } | 686 | | } else { | 687 | | // Save original position where non-digit was found | 688 | | int remaining_len = len - i; | 689 | | const char* remaining_s = s + i; | 690 | | // Skip trailing whitespaces from the remaining portion | 691 | | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 692 | | if ((UNLIKELY(remaining_len != 0 && | 693 | | !is_float_suffix(remaining_s, remaining_len)))) { | 694 | | *result = PARSE_FAILURE; | 695 | | return 0; | 696 | | } | 697 | | } | 698 | 112 | *result = PARSE_SUCCESS; | 699 | 460 | return val; | 700 | 460 | } | 701 | 5.02k | } | 702 | 2.39k | *result = PARSE_SUCCESS; | 703 | 2.39k | return val; | 704 | 2.85k | } |
_ZN5doris12StringParser25string_to_int_no_overflowIhLb1EEET_PKciPNS0_11ParseResultE Line | Count | Source | 663 | 670 | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 664 | 670 | T val = 0; | 665 | 670 | if (UNLIKELY(len == 0)) { | 666 | 0 | *result = PARSE_SUCCESS; | 667 | 0 | return val; | 668 | 0 | } | 669 | | // Factor out the first char for error handling speeds up the loop. | 670 | 670 | if (LIKELY(s[0] >= '0' && s[0] <= '9')) { | 671 | 644 | val = s[0] - '0'; | 672 | 644 | } else { | 673 | 26 | *result = PARSE_FAILURE; | 674 | 26 | return 0; | 675 | 26 | } | 676 | 1.00k | for (int i = 1; i < len; ++i) { | 677 | 364 | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 678 | 362 | T digit = s[i] - '0'; | 679 | 362 | val = val * 10 + digit; | 680 | 362 | } else { | 681 | 2 | if constexpr (enable_strict_mode) { | 682 | 2 | if (UNLIKELY(!is_all_whitespace(s + i, len - i))) { | 683 | 2 | *result = PARSE_FAILURE; | 684 | 2 | return 0; | 685 | 2 | } | 686 | | } else { | 687 | | // Save original position where non-digit was found | 688 | | int remaining_len = len - i; | 689 | | const char* remaining_s = s + i; | 690 | | // Skip trailing whitespaces from the remaining portion | 691 | | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 692 | | if ((UNLIKELY(remaining_len != 0 && | 693 | | !is_float_suffix(remaining_s, remaining_len)))) { | 694 | | *result = PARSE_FAILURE; | 695 | | return 0; | 696 | | } | 697 | | } | 698 | 0 | *result = PARSE_SUCCESS; | 699 | 2 | return val; | 700 | 2 | } | 701 | 364 | } | 702 | 642 | *result = PARSE_SUCCESS; | 703 | 642 | return val; | 704 | 644 | } |
_ZN5doris12StringParser25string_to_int_no_overflowItLb1EEET_PKciPNS0_11ParseResultE Line | Count | Source | 663 | 918 | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 664 | 918 | T val = 0; | 665 | 918 | if (UNLIKELY(len == 0)) { | 666 | 0 | *result = PARSE_SUCCESS; | 667 | 0 | return val; | 668 | 0 | } | 669 | | // Factor out the first char for error handling speeds up the loop. | 670 | 918 | if (LIKELY(s[0] >= '0' && s[0] <= '9')) { | 671 | 880 | val = s[0] - '0'; | 672 | 880 | } else { | 673 | 38 | *result = PARSE_FAILURE; | 674 | 38 | return 0; | 675 | 38 | } | 676 | 2.00k | for (int i = 1; i < len; ++i) { | 677 | 1.25k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 678 | 1.12k | T digit = s[i] - '0'; | 679 | 1.12k | val = val * 10 + digit; | 680 | 1.12k | } else { | 681 | 132 | if constexpr (enable_strict_mode) { | 682 | 132 | if (UNLIKELY(!is_all_whitespace(s + i, len - i))) { | 683 | 90 | *result = PARSE_FAILURE; | 684 | 90 | return 0; | 685 | 90 | } | 686 | | } else { | 687 | | // Save original position where non-digit was found | 688 | | int remaining_len = len - i; | 689 | | const char* remaining_s = s + i; | 690 | | // Skip trailing whitespaces from the remaining portion | 691 | | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 692 | | if ((UNLIKELY(remaining_len != 0 && | 693 | | !is_float_suffix(remaining_s, remaining_len)))) { | 694 | | *result = PARSE_FAILURE; | 695 | | return 0; | 696 | | } | 697 | | } | 698 | 42 | *result = PARSE_SUCCESS; | 699 | 132 | return val; | 700 | 132 | } | 701 | 1.25k | } | 702 | 748 | *result = PARSE_SUCCESS; | 703 | 748 | return val; | 704 | 880 | } |
_ZN5doris12StringParser25string_to_int_no_overflowImLb1EEET_PKciPNS0_11ParseResultE Line | Count | Source | 663 | 2.21k | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 664 | 2.21k | T val = 0; | 665 | 2.21k | if (UNLIKELY(len == 0)) { | 666 | 0 | *result = PARSE_SUCCESS; | 667 | 0 | return val; | 668 | 0 | } | 669 | | // Factor out the first char for error handling speeds up the loop. | 670 | 2.21k | if (LIKELY(s[0] >= '0' && s[0] <= '9')) { | 671 | 1.75k | val = s[0] - '0'; | 672 | 1.75k | } else { | 673 | 459 | *result = PARSE_FAILURE; | 674 | 459 | return 0; | 675 | 459 | } | 676 | 5.63k | for (int i = 1; i < len; ++i) { | 677 | 4.67k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 678 | 3.88k | T digit = s[i] - '0'; | 679 | 3.88k | val = val * 10 + digit; | 680 | 3.88k | } else { | 681 | 796 | if constexpr (enable_strict_mode) { | 682 | 796 | if (UNLIKELY(!is_all_whitespace(s + i, len - i))) { | 683 | 656 | *result = PARSE_FAILURE; | 684 | 656 | return 0; | 685 | 656 | } | 686 | | } else { | 687 | | // Save original position where non-digit was found | 688 | | int remaining_len = len - i; | 689 | | const char* remaining_s = s + i; | 690 | | // Skip trailing whitespaces from the remaining portion | 691 | | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 692 | | if ((UNLIKELY(remaining_len != 0 && | 693 | | !is_float_suffix(remaining_s, remaining_len)))) { | 694 | | *result = PARSE_FAILURE; | 695 | | return 0; | 696 | | } | 697 | | } | 698 | 140 | *result = PARSE_SUCCESS; | 699 | 796 | return val; | 700 | 796 | } | 701 | 4.67k | } | 702 | 959 | *result = PARSE_SUCCESS; | 703 | 959 | return val; | 704 | 1.75k | } |
_ZN5doris12StringParser25string_to_int_no_overflowIoLb1EEET_PKciPNS0_11ParseResultE Line | Count | Source | 663 | 1.58k | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 664 | 1.58k | T val = 0; | 665 | 1.58k | if (UNLIKELY(len == 0)) { | 666 | 0 | *result = PARSE_SUCCESS; | 667 | 0 | return val; | 668 | 0 | } | 669 | | // Factor out the first char for error handling speeds up the loop. | 670 | 1.58k | if (LIKELY(s[0] >= '0' && s[0] <= '9')) { | 671 | 1.34k | val = s[0] - '0'; | 672 | 1.34k | } else { | 673 | 240 | *result = PARSE_FAILURE; | 674 | 240 | return 0; | 675 | 240 | } | 676 | 6.66k | for (int i = 1; i < len; ++i) { | 677 | 5.77k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 678 | 5.32k | T digit = s[i] - '0'; | 679 | 5.32k | val = val * 10 + digit; | 680 | 5.32k | } else { | 681 | 456 | if constexpr (enable_strict_mode) { | 682 | 456 | if (UNLIKELY(!is_all_whitespace(s + i, len - i))) { | 683 | 400 | *result = PARSE_FAILURE; | 684 | 400 | return 0; | 685 | 400 | } | 686 | | } else { | 687 | | // Save original position where non-digit was found | 688 | | int remaining_len = len - i; | 689 | | const char* remaining_s = s + i; | 690 | | // Skip trailing whitespaces from the remaining portion | 691 | | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 692 | | if ((UNLIKELY(remaining_len != 0 && | 693 | | !is_float_suffix(remaining_s, remaining_len)))) { | 694 | | *result = PARSE_FAILURE; | 695 | | return 0; | 696 | | } | 697 | | } | 698 | 56 | *result = PARSE_SUCCESS; | 699 | 456 | return val; | 700 | 456 | } | 701 | 5.77k | } | 702 | 892 | *result = PARSE_SUCCESS; | 703 | 892 | return val; | 704 | 1.34k | } |
_ZN5doris12StringParser25string_to_int_no_overflowIhLb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 663 | 5.70M | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 664 | 5.70M | T val = 0; | 665 | 5.70M | if (UNLIKELY(len == 0)) { | 666 | 0 | *result = PARSE_SUCCESS; | 667 | 0 | return val; | 668 | 0 | } | 669 | | // Factor out the first char for error handling speeds up the loop. | 670 | 5.72M | if (LIKELY(s[0] >= '0' && s[0] <= '9')) { | 671 | 5.72M | val = s[0] - '0'; | 672 | 18.4E | } else { | 673 | 18.4E | *result = PARSE_FAILURE; | 674 | 18.4E | return 0; | 675 | 18.4E | } | 676 | 6.28M | for (int i = 1; i < len; ++i) { | 677 | 563k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 678 | 563k | T digit = s[i] - '0'; | 679 | 563k | val = val * 10 + digit; | 680 | 563k | } else { | 681 | | if constexpr (enable_strict_mode) { | 682 | | if (UNLIKELY(!is_all_whitespace(s + i, len - i))) { | 683 | | *result = PARSE_FAILURE; | 684 | | return 0; | 685 | | } | 686 | 1 | } else { | 687 | | // Save original position where non-digit was found | 688 | 1 | int remaining_len = len - i; | 689 | 1 | const char* remaining_s = s + i; | 690 | | // Skip trailing whitespaces from the remaining portion | 691 | 1 | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 692 | 1 | if ((UNLIKELY(remaining_len != 0 && | 693 | 2 | !is_float_suffix(remaining_s, remaining_len)))) { | 694 | 2 | *result = PARSE_FAILURE; | 695 | 2 | return 0; | 696 | 2 | } | 697 | 1 | } | 698 | 18.4E | *result = PARSE_SUCCESS; | 699 | 1 | return val; | 700 | 1 | } | 701 | 563k | } | 702 | 5.72M | *result = PARSE_SUCCESS; | 703 | 5.72M | return val; | 704 | 5.72M | } |
_ZN5doris12StringParser25string_to_int_no_overflowItLb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 663 | 517k | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 664 | 517k | T val = 0; | 665 | 517k | if (UNLIKELY(len == 0)) { | 666 | 0 | *result = PARSE_SUCCESS; | 667 | 0 | return val; | 668 | 0 | } | 669 | | // Factor out the first char for error handling speeds up the loop. | 670 | 517k | if (LIKELY(s[0] >= '0' && s[0] <= '9')) { | 671 | 516k | val = s[0] - '0'; | 672 | 516k | } else { | 673 | 1.39k | *result = PARSE_FAILURE; | 674 | 1.39k | return 0; | 675 | 1.39k | } | 676 | 1.24M | for (int i = 1; i < len; ++i) { | 677 | 734k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 678 | 733k | T digit = s[i] - '0'; | 679 | 733k | val = val * 10 + digit; | 680 | 733k | } else { | 681 | | if constexpr (enable_strict_mode) { | 682 | | if (UNLIKELY(!is_all_whitespace(s + i, len - i))) { | 683 | | *result = PARSE_FAILURE; | 684 | | return 0; | 685 | | } | 686 | 1.02k | } else { | 687 | | // Save original position where non-digit was found | 688 | 1.02k | int remaining_len = len - i; | 689 | 1.02k | const char* remaining_s = s + i; | 690 | | // Skip trailing whitespaces from the remaining portion | 691 | 1.02k | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 692 | 1.02k | if ((UNLIKELY(remaining_len != 0 && | 693 | 1.02k | !is_float_suffix(remaining_s, remaining_len)))) { | 694 | 74 | *result = PARSE_FAILURE; | 695 | 74 | return 0; | 696 | 74 | } | 697 | 1.02k | } | 698 | 951 | *result = PARSE_SUCCESS; | 699 | 1.02k | return val; | 700 | 1.02k | } | 701 | 734k | } | 702 | 515k | *result = PARSE_SUCCESS; | 703 | 515k | return val; | 704 | 516k | } |
_ZN5doris12StringParser25string_to_int_no_overflowIjLb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 663 | 52.0M | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 664 | 52.0M | T val = 0; | 665 | 52.0M | if (UNLIKELY(len == 0)) { | 666 | 0 | *result = PARSE_SUCCESS; | 667 | 0 | return val; | 668 | 0 | } | 669 | | // Factor out the first char for error handling speeds up the loop. | 670 | 52.0M | if (LIKELY(s[0] >= '0' && s[0] <= '9')) { | 671 | 52.0M | val = s[0] - '0'; | 672 | 52.0M | } else { | 673 | 7.71k | *result = PARSE_FAILURE; | 674 | 7.71k | return 0; | 675 | 7.71k | } | 676 | 194M | for (int i = 1; i < len; ++i) { | 677 | 142M | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 678 | 142M | T digit = s[i] - '0'; | 679 | 142M | val = val * 10 + digit; | 680 | 142M | } else { | 681 | | if constexpr (enable_strict_mode) { | 682 | | if (UNLIKELY(!is_all_whitespace(s + i, len - i))) { | 683 | | *result = PARSE_FAILURE; | 684 | | return 0; | 685 | | } | 686 | 50.6k | } else { | 687 | | // Save original position where non-digit was found | 688 | 50.6k | int remaining_len = len - i; | 689 | 50.6k | const char* remaining_s = s + i; | 690 | | // Skip trailing whitespaces from the remaining portion | 691 | 50.6k | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 692 | 50.6k | if ((UNLIKELY(remaining_len != 0 && | 693 | 50.6k | !is_float_suffix(remaining_s, remaining_len)))) { | 694 | 286 | *result = PARSE_FAILURE; | 695 | 286 | return 0; | 696 | 286 | } | 697 | 50.6k | } | 698 | 50.3k | *result = PARSE_SUCCESS; | 699 | 50.6k | return val; | 700 | 50.6k | } | 701 | 142M | } | 702 | 51.9M | *result = PARSE_SUCCESS; | 703 | 51.9M | return val; | 704 | 52.0M | } |
_ZN5doris12StringParser25string_to_int_no_overflowImLb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 663 | 71.2M | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 664 | 71.2M | T val = 0; | 665 | 71.2M | if (UNLIKELY(len == 0)) { | 666 | 0 | *result = PARSE_SUCCESS; | 667 | 0 | return val; | 668 | 0 | } | 669 | | // Factor out the first char for error handling speeds up the loop. | 670 | 71.2M | if (LIKELY(s[0] >= '0' && s[0] <= '9')) { | 671 | 71.2M | val = s[0] - '0'; | 672 | 18.4E | } else { | 673 | 18.4E | *result = PARSE_FAILURE; | 674 | 18.4E | return 0; | 675 | 18.4E | } | 676 | 330M | for (int i = 1; i < len; ++i) { | 677 | 259M | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 678 | 259M | T digit = s[i] - '0'; | 679 | 259M | val = val * 10 + digit; | 680 | 18.4E | } else { | 681 | | if constexpr (enable_strict_mode) { | 682 | | if (UNLIKELY(!is_all_whitespace(s + i, len - i))) { | 683 | | *result = PARSE_FAILURE; | 684 | | return 0; | 685 | | } | 686 | 18.4E | } else { | 687 | | // Save original position where non-digit was found | 688 | 18.4E | int remaining_len = len - i; | 689 | 18.4E | const char* remaining_s = s + i; | 690 | | // Skip trailing whitespaces from the remaining portion | 691 | 18.4E | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 692 | 18.4E | if ((UNLIKELY(remaining_len != 0 && | 693 | 18.4E | !is_float_suffix(remaining_s, remaining_len)))) { | 694 | 291 | *result = PARSE_FAILURE; | 695 | 291 | return 0; | 696 | 291 | } | 697 | 18.4E | } | 698 | 18.4E | *result = PARSE_SUCCESS; | 699 | 18.4E | return val; | 700 | 18.4E | } | 701 | 259M | } | 702 | 71.2M | *result = PARSE_SUCCESS; | 703 | 71.2M | return val; | 704 | 71.2M | } |
_ZN5doris12StringParser25string_to_int_no_overflowIN4wide7integerILm256EjEELb0EEET_PKciPNS0_11ParseResultE Line | Count | Source | 663 | 4 | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 664 | 4 | T val = 0; | 665 | 4 | if (UNLIKELY(len == 0)) { | 666 | 0 | *result = PARSE_SUCCESS; | 667 | 0 | return val; | 668 | 0 | } | 669 | | // Factor out the first char for error handling speeds up the loop. | 670 | 4 | if (LIKELY(s[0] >= '0' && s[0] <= '9')) { | 671 | 4 | val = s[0] - '0'; | 672 | 4 | } else { | 673 | 0 | *result = PARSE_FAILURE; | 674 | 0 | return 0; | 675 | 0 | } | 676 | 4 | for (int i = 1; i < len; ++i) { | 677 | 0 | if (LIKELY(s[i] >= '0' && s[i] <= '9')) { | 678 | 0 | T digit = s[i] - '0'; | 679 | 0 | val = val * 10 + digit; | 680 | 0 | } else { | 681 | | if constexpr (enable_strict_mode) { | 682 | | if (UNLIKELY(!is_all_whitespace(s + i, len - i))) { | 683 | | *result = PARSE_FAILURE; | 684 | | return 0; | 685 | | } | 686 | 0 | } else { | 687 | | // Save original position where non-digit was found | 688 | 0 | int remaining_len = len - i; | 689 | 0 | const char* remaining_s = s + i; | 690 | | // Skip trailing whitespaces from the remaining portion | 691 | 0 | remaining_s = skip_trailing_whitespaces(remaining_s, remaining_len); | 692 | 0 | if ((UNLIKELY(remaining_len != 0 && | 693 | 0 | !is_float_suffix(remaining_s, remaining_len)))) { | 694 | 0 | *result = PARSE_FAILURE; | 695 | 0 | return 0; | 696 | 0 | } | 697 | 0 | } | 698 | 0 | *result = PARSE_SUCCESS; | 699 | 0 | return val; | 700 | 0 | } | 701 | 0 | } | 702 | 4 | *result = PARSE_SUCCESS; | 703 | 4 | return val; | 704 | 4 | } |
|
705 | | |
706 | | // at least the first char(if any) must be a digit. |
707 | | template <typename T> |
708 | | T StringParser::string_to_uint_greedy_no_overflow(const char* __restrict s, int max_len, |
709 | 590k | ParseResult* result) { |
710 | 590k | T val = 0; |
711 | 590k | if (max_len == 0) [[unlikely]] { |
712 | 461k | *result = PARSE_SUCCESS; |
713 | 461k | return val; |
714 | 461k | } |
715 | | // Factor out the first char for error handling speeds up the loop. |
716 | 128k | if (is_numeric_ascii(s[0])) [[likely]] { |
717 | 128k | val = s[0] - '0'; |
718 | 18.4E | } else { |
719 | 18.4E | *result = PARSE_FAILURE; |
720 | 18.4E | return 0; |
721 | 18.4E | } |
722 | 500k | for (int i = 1; i < max_len; ++i) { |
723 | 371k | if (is_numeric_ascii(s[i])) [[likely]] { |
724 | 371k | T digit = s[i] - '0'; |
725 | 371k | val = val * 10 + digit; |
726 | 371k | } else { |
727 | | // 123abc, return 123 |
728 | 28 | *result = PARSE_SUCCESS; |
729 | 28 | return val; |
730 | 28 | } |
731 | 371k | } |
732 | 128k | *result = PARSE_SUCCESS; |
733 | 128k | return val; |
734 | 128k | } |
735 | | |
736 | | template <typename T> |
737 | 3.85M | T StringParser::string_to_float_internal(const char* __restrict s, int len, ParseResult* result) { |
738 | 3.85M | int i = 0; |
739 | | // skip leading spaces |
740 | 3.85M | for (; i < len; ++i) { |
741 | 3.81M | if (!is_whitespace_ascii(s[i])) { |
742 | 3.81M | break; |
743 | 3.81M | } |
744 | 3.81M | } |
745 | | |
746 | | // skip back spaces |
747 | 3.85M | int j = len - 1; |
748 | 3.85M | for (; j >= i; j--) { |
749 | 3.81M | if (!is_whitespace_ascii(s[j])) { |
750 | 3.81M | break; |
751 | 3.81M | } |
752 | 3.81M | } |
753 | | |
754 | | // skip leading '+', from_chars can handle '-' |
755 | 3.85M | if (i < len && s[i] == '+') { |
756 | 7.16k | i++; |
757 | | // ++ or +- are not valid, but the first + is already skipped, |
758 | | // if don't check here, from_chars will succeed. |
759 | | // |
760 | | // New version of fast_float supports a new flag called 'chars_format::allow_leading_plus' |
761 | | // which may avoid this extra check here. |
762 | | // e.g.: |
763 | | // fast_float::chars_format format = |
764 | | // fast_float::chars_format::general | fast_float::chars_format::allow_leading_plus; |
765 | | // auto res = fast_float::from_chars(s + i, s + j + 1, val, format); |
766 | 7.16k | if (i < len && (s[i] == '+' || s[i] == '-')) { |
767 | 70 | *result = PARSE_FAILURE; |
768 | 70 | return 0; |
769 | 70 | } |
770 | 7.16k | } |
771 | 3.85M | if (UNLIKELY(i > j)) { |
772 | 38.7k | *result = PARSE_FAILURE; |
773 | 38.7k | return 0; |
774 | 38.7k | } |
775 | | |
776 | | // Use double here to not lose precision while accumulating the result |
777 | 3.81M | double val = 0; |
778 | 3.81M | auto res = fast_float::from_chars(s + i, s + j + 1, val); |
779 | | |
780 | 3.81M | if (res.ptr == s + j + 1) { |
781 | 3.80M | *result = PARSE_SUCCESS; |
782 | 3.80M | return val; |
783 | 3.80M | } else { |
784 | 11.0k | *result = PARSE_FAILURE; |
785 | 11.0k | } |
786 | 11.0k | return 0; |
787 | 3.81M | } _ZN5doris12StringParser24string_to_float_internalIdEET_PKciPNS0_11ParseResultE Line | Count | Source | 737 | 2.84M | T StringParser::string_to_float_internal(const char* __restrict s, int len, ParseResult* result) { | 738 | 2.84M | int i = 0; | 739 | | // skip leading spaces | 740 | 2.84M | for (; i < len; ++i) { | 741 | 2.81M | if (!is_whitespace_ascii(s[i])) { | 742 | 2.81M | break; | 743 | 2.81M | } | 744 | 2.81M | } | 745 | | | 746 | | // skip back spaces | 747 | 2.84M | int j = len - 1; | 748 | 2.84M | for (; j >= i; j--) { | 749 | 2.81M | if (!is_whitespace_ascii(s[j])) { | 750 | 2.81M | break; | 751 | 2.81M | } | 752 | 2.81M | } | 753 | | | 754 | | // skip leading '+', from_chars can handle '-' | 755 | 2.84M | if (i < len && s[i] == '+') { | 756 | 3.58k | i++; | 757 | | // ++ or +- are not valid, but the first + is already skipped, | 758 | | // if don't check here, from_chars will succeed. | 759 | | // | 760 | | // New version of fast_float supports a new flag called 'chars_format::allow_leading_plus' | 761 | | // which may avoid this extra check here. | 762 | | // e.g.: | 763 | | // fast_float::chars_format format = | 764 | | // fast_float::chars_format::general | fast_float::chars_format::allow_leading_plus; | 765 | | // auto res = fast_float::from_chars(s + i, s + j + 1, val, format); | 766 | 3.58k | if (i < len && (s[i] == '+' || s[i] == '-')) { | 767 | 35 | *result = PARSE_FAILURE; | 768 | 35 | return 0; | 769 | 35 | } | 770 | 3.58k | } | 771 | 2.84M | if (UNLIKELY(i > j)) { | 772 | 33.5k | *result = PARSE_FAILURE; | 773 | 33.5k | return 0; | 774 | 33.5k | } | 775 | | | 776 | | // Use double here to not lose precision while accumulating the result | 777 | 2.81M | double val = 0; | 778 | 2.81M | auto res = fast_float::from_chars(s + i, s + j + 1, val); | 779 | | | 780 | 2.81M | if (res.ptr == s + j + 1) { | 781 | 2.80M | *result = PARSE_SUCCESS; | 782 | 2.80M | return val; | 783 | 2.80M | } else { | 784 | 8.38k | *result = PARSE_FAILURE; | 785 | 8.38k | } | 786 | 8.38k | return 0; | 787 | 2.81M | } |
_ZN5doris12StringParser24string_to_float_internalIfEET_PKciPNS0_11ParseResultE Line | Count | Source | 737 | 1.00M | T StringParser::string_to_float_internal(const char* __restrict s, int len, ParseResult* result) { | 738 | 1.00M | int i = 0; | 739 | | // skip leading spaces | 740 | 1.00M | for (; i < len; ++i) { | 741 | 1.00M | if (!is_whitespace_ascii(s[i])) { | 742 | 1.00M | break; | 743 | 1.00M | } | 744 | 1.00M | } | 745 | | | 746 | | // skip back spaces | 747 | 1.00M | int j = len - 1; | 748 | 1.00M | for (; j >= i; j--) { | 749 | 1.00M | if (!is_whitespace_ascii(s[j])) { | 750 | 1.00M | break; | 751 | 1.00M | } | 752 | 1.00M | } | 753 | | | 754 | | // skip leading '+', from_chars can handle '-' | 755 | 1.00M | if (i < len && s[i] == '+') { | 756 | 3.57k | i++; | 757 | | // ++ or +- are not valid, but the first + is already skipped, | 758 | | // if don't check here, from_chars will succeed. | 759 | | // | 760 | | // New version of fast_float supports a new flag called 'chars_format::allow_leading_plus' | 761 | | // which may avoid this extra check here. | 762 | | // e.g.: | 763 | | // fast_float::chars_format format = | 764 | | // fast_float::chars_format::general | fast_float::chars_format::allow_leading_plus; | 765 | | // auto res = fast_float::from_chars(s + i, s + j + 1, val, format); | 766 | 3.57k | if (i < len && (s[i] == '+' || s[i] == '-')) { | 767 | 35 | *result = PARSE_FAILURE; | 768 | 35 | return 0; | 769 | 35 | } | 770 | 3.57k | } | 771 | 1.00M | if (UNLIKELY(i > j)) { | 772 | 5.20k | *result = PARSE_FAILURE; | 773 | 5.20k | return 0; | 774 | 5.20k | } | 775 | | | 776 | | // Use double here to not lose precision while accumulating the result | 777 | 1.00M | double val = 0; | 778 | 1.00M | auto res = fast_float::from_chars(s + i, s + j + 1, val); | 779 | | | 780 | 1.00M | if (res.ptr == s + j + 1) { | 781 | 998k | *result = PARSE_SUCCESS; | 782 | 998k | return val; | 783 | 998k | } else { | 784 | 2.69k | *result = PARSE_FAILURE; | 785 | 2.69k | } | 786 | 2.69k | return 0; | 787 | 1.00M | } |
|
788 | | |
789 | | inline bool StringParser::string_to_bool_internal(const char* __restrict s, int len, |
790 | 676k | ParseResult* result) { |
791 | 676k | *result = PARSE_SUCCESS; |
792 | | |
793 | 676k | if (len == 1) { |
794 | 541k | if (s[0] == '1' || s[0] == 't' || s[0] == 'T') { |
795 | 277k | return true; |
796 | 277k | } |
797 | 264k | if (s[0] == '0' || s[0] == 'f' || s[0] == 'F') { |
798 | 262k | return false; |
799 | 262k | } |
800 | 1.41k | *result = PARSE_FAILURE; |
801 | 1.41k | return false; |
802 | 264k | } |
803 | | |
804 | 134k | if (len == 2) { |
805 | 1.04k | if ((s[0] == 'o' || s[0] == 'O') && (s[1] == 'n' || s[1] == 'N')) { |
806 | 20 | return true; |
807 | 20 | } |
808 | 1.02k | if ((s[0] == 'n' || s[0] == 'N') && (s[1] == 'o' || s[1] == 'O')) { |
809 | 19 | return false; |
810 | 19 | } |
811 | 1.02k | } |
812 | | |
813 | 134k | if (len == 3) { |
814 | 99 | if ((s[0] == 'y' || s[0] == 'Y') && (s[1] == 'e' || s[1] == 'E') && |
815 | 99 | (s[2] == 's' || s[2] == 'S')) { |
816 | 20 | return true; |
817 | 20 | } |
818 | 79 | if ((s[0] == 'o' || s[0] == 'O') && (s[1] == 'f' || s[1] == 'F') && |
819 | 79 | (s[2] == 'f' || s[2] == 'F')) { |
820 | 19 | return false; |
821 | 19 | } |
822 | 79 | } |
823 | | |
824 | 134k | if (len == 4 && (s[0] == 't' || s[0] == 'T') && (s[1] == 'r' || s[1] == 'R') && |
825 | 134k | (s[2] == 'u' || s[2] == 'U') && (s[3] == 'e' || s[3] == 'E')) { |
826 | 65.0k | return true; |
827 | 65.0k | } |
828 | | |
829 | 69.4k | if (len == 5 && (s[0] == 'f' || s[0] == 'F') && (s[1] == 'a' || s[1] == 'A') && |
830 | 69.4k | (s[2] == 'l' || s[2] == 'L') && (s[3] == 's' || s[3] == 'S') && |
831 | 69.4k | (s[4] == 'e' || s[4] == 'E')) { |
832 | 63.2k | return false; |
833 | 63.2k | } |
834 | | |
835 | | // No valid boolean value found |
836 | 6.27k | *result = PARSE_FAILURE; |
837 | 6.27k | return false; |
838 | 69.4k | } |
839 | | #include "common/compile_check_avoid_end.h" |
840 | | } // end namespace doris |