/root/doris/be/src/util/string_parser.hpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
27 | | #include <cstdlib> |
28 | | // IWYU pragma: no_include <bits/std_abs.h> |
29 | | #include <cmath> // IWYU pragma: keep |
30 | | #include <cstdint> |
31 | | #include <limits> |
32 | | #include <map> |
33 | | #include <string> |
34 | | #include <system_error> |
35 | | #include <type_traits> |
36 | | #include <utility> |
37 | | |
38 | | #include "common/compiler_util.h" // IWYU pragma: keep |
39 | | #include "common/status.h" |
40 | | #include "runtime/large_int_value.h" |
41 | | #include "runtime/primitive_type.h" |
42 | | #include "vec/common/int_exp.h" |
43 | | #include "vec/common/string_utils/string_utils.h" |
44 | | #include "vec/core/extended_types.h" |
45 | | #include "vec/core/wide_integer.h" |
46 | | #include "vec/data_types/data_type_decimal.h" |
47 | | #include "vec/data_types/number_traits.h" |
48 | | |
49 | | namespace doris { |
50 | | namespace vectorized { |
51 | | template <DecimalNativeTypeConcept T> |
52 | | struct Decimal; |
53 | | } // namespace vectorized |
54 | | |
55 | | // Utility functions for doing atoi/atof on non-null terminated strings. On micro benchmarks, |
56 | | // this is significantly faster than libc (atoi/strtol and atof/strtod). |
57 | | // |
58 | | // Strings with leading and trailing whitespaces are accepted. |
59 | | // Branching is heavily optimized for the non-whitespace successful case. |
60 | | // All the StringTo* functions first parse the input string assuming it has no leading whitespace. |
61 | | // If that first attempt was unsuccessful, these functions retry the parsing after removing |
62 | | // whitespace. Therefore, strings with whitespace take a perf hit on branch mis-prediction. |
63 | | // |
64 | | // For overflows, we are following the mysql behavior, to cap values at the max/min value for that |
65 | | // data type. This is different from hive, which returns NULL for overflow slots for int types |
66 | | // and inf/-inf for float types. |
67 | | // |
68 | | // Things we tried that did not work: |
69 | | // - lookup table for converting character to digit |
70 | | // Improvements (TODO): |
71 | | // - Validate input using _sidd_compare_ranges |
72 | | // - Since we know the length, we can parallelize this: i.e. result = 100*s[0] + 10*s[1] + s[2] |
73 | | class StringParser { |
74 | | public: |
75 | | enum ParseResult { PARSE_SUCCESS = 0, PARSE_FAILURE, PARSE_OVERFLOW, PARSE_UNDERFLOW }; |
76 | | |
77 | | template <typename T> |
78 | 243k | static T numeric_limits(bool negative) { |
79 | 243k | if constexpr (std::is_same_v<T, __int128>) { Branch (79:23): [Folded - Ignored]
Branch (79:23): [Folded - Ignored]
Branch (79:23): [Folded - Ignored]
Branch (79:23): [Folded - Ignored]
Branch (79:23): [Folded - Ignored]
Branch (79:23): [Folded - Ignored]
Branch (79:23): [Folded - Ignored]
Branch (79:23): [Folded - Ignored]
Branch (79:23): [Folded - Ignored]
Branch (79:23): [Folded - Ignored]
Branch (79:23): [Folded - Ignored]
|
80 | 123k | return negative ? MIN_INT128 : MAX_INT128; Branch (80:20): [True: 0, False: 119k]
|
81 | 123k | } else { |
82 | 123k | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); Branch (82:20): [True: 0, False: 115k]
Branch (82:20): [True: 0, False: 1.97k]
Branch (82:20): [True: 0, False: 3.82k]
Branch (82:20): [True: 0, False: 2.10k]
Branch (82:20): [True: 0, False: 0]
Branch (82:20): [True: 0, False: 0]
Branch (82:20): [True: 0, False: 21]
Branch (82:20): [True: 0, False: 0]
Branch (82:20): [True: 0, False: 93]
Branch (82:20): [True: 0, False: 0]
|
83 | 123k | } |
84 | 243k | } _ZN5doris12StringParser14numeric_limitsIaEET_b Line | Count | Source | 78 | 115k | static T numeric_limits(bool negative) { | 79 | 115k | if constexpr (std::is_same_v<T, __int128>) { Branch (79:23): [Folded - Ignored]
| 80 | 115k | return negative ? MIN_INT128 : MAX_INT128; | 81 | 115k | } else { | 82 | 115k | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); Branch (82:20): [True: 0, False: 115k]
| 83 | 115k | } | 84 | 115k | } |
_ZN5doris12StringParser14numeric_limitsInEET_b Line | Count | Source | 78 | 119k | static T numeric_limits(bool negative) { | 79 | 119k | if constexpr (std::is_same_v<T, __int128>) { Branch (79:23): [Folded - Ignored]
| 80 | 119k | return negative ? MIN_INT128 : MAX_INT128; Branch (80:20): [True: 0, False: 119k]
| 81 | 119k | } else { | 82 | 119k | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 83 | 119k | } | 84 | 119k | } |
_ZN5doris12StringParser14numeric_limitsIsEET_b Line | Count | Source | 78 | 1.97k | static T numeric_limits(bool negative) { | 79 | 1.97k | if constexpr (std::is_same_v<T, __int128>) { Branch (79:23): [Folded - Ignored]
| 80 | 1.97k | return negative ? MIN_INT128 : MAX_INT128; | 81 | 1.97k | } else { | 82 | 1.97k | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); Branch (82:20): [True: 0, False: 1.97k]
| 83 | 1.97k | } | 84 | 1.97k | } |
_ZN5doris12StringParser14numeric_limitsIiEET_b Line | Count | Source | 78 | 3.82k | static T numeric_limits(bool negative) { | 79 | 3.82k | if constexpr (std::is_same_v<T, __int128>) { Branch (79:23): [Folded - Ignored]
| 80 | 3.82k | return negative ? MIN_INT128 : MAX_INT128; | 81 | 3.82k | } else { | 82 | 3.82k | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); Branch (82:20): [True: 0, False: 3.82k]
| 83 | 3.82k | } | 84 | 3.82k | } |
_ZN5doris12StringParser14numeric_limitsIlEET_b Line | Count | Source | 78 | 2.10k | static T numeric_limits(bool negative) { | 79 | 2.10k | if constexpr (std::is_same_v<T, __int128>) { Branch (79:23): [Folded - Ignored]
| 80 | 2.10k | return negative ? MIN_INT128 : MAX_INT128; | 81 | 2.10k | } else { | 82 | 2.10k | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); Branch (82:20): [True: 0, False: 2.10k]
| 83 | 2.10k | } | 84 | 2.10k | } |
Unexecuted instantiation: _ZN5doris12StringParser14numeric_limitsIN4wide7integerILm256EiEEEET_b Unexecuted instantiation: _ZN5doris12StringParser14numeric_limitsIoEET_b _ZN5doris12StringParser14numeric_limitsImEET_b Line | Count | Source | 78 | 21 | static T numeric_limits(bool negative) { | 79 | 21 | if constexpr (std::is_same_v<T, __int128>) { Branch (79:23): [Folded - Ignored]
| 80 | 21 | return negative ? MIN_INT128 : MAX_INT128; | 81 | 21 | } else { | 82 | 21 | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); Branch (82:20): [True: 0, False: 21]
| 83 | 21 | } | 84 | 21 | } |
Unexecuted instantiation: _ZN5doris12StringParser14numeric_limitsIjEET_b _ZN5doris12StringParser14numeric_limitsIhEET_b Line | Count | Source | 78 | 93 | static T numeric_limits(bool negative) { | 79 | 93 | if constexpr (std::is_same_v<T, __int128>) { Branch (79:23): [Folded - Ignored]
| 80 | 93 | return negative ? MIN_INT128 : MAX_INT128; | 81 | 93 | } else { | 82 | 93 | return negative ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); Branch (82:20): [True: 0, False: 93]
| 83 | 93 | } | 84 | 93 | } |
Unexecuted instantiation: _ZN5doris12StringParser14numeric_limitsItEET_b |
85 | | |
86 | | template <typename T> |
87 | 132 | static T get_scale_multiplier(int scale) { |
88 | 132 | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || |
89 | 132 | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, |
90 | 132 | "You can only instantiate as int32_t, int64_t, __int128."); |
91 | 132 | if constexpr (std::is_same_v<T, int32_t>) { Branch (91:23): [Folded - Ignored]
Branch (91:23): [Folded - Ignored]
Branch (91:23): [Folded - Ignored]
Branch (91:23): [Folded - Ignored]
|
92 | 116 | return common::exp10_i32(scale); |
93 | 116 | } else if constexpr (std::is_same_v<T, int64_t>) { Branch (93:30): [Folded - Ignored]
Branch (93:30): [Folded - Ignored]
Branch (93:30): [Folded - Ignored]
|
94 | 109 | return common::exp10_i64(scale); |
95 | 109 | } else if constexpr (std::is_same_v<T, __int128>) { Branch (95:30): [Folded - Ignored]
Branch (95:30): [Folded - Ignored]
|
96 | 0 | return common::exp10_i128(scale); |
97 | 0 | } else if constexpr (std::is_same_v<T, wide::Int256>) { Branch (97:30): [Folded - Ignored]
|
98 | 0 | return common::exp10_i256(scale); |
99 | 0 | } |
100 | 132 | } _ZN5doris12StringParser20get_scale_multiplierIiEET_i Line | Count | Source | 87 | 16 | static T get_scale_multiplier(int scale) { | 88 | 16 | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || | 89 | 16 | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, | 90 | 16 | "You can only instantiate as int32_t, int64_t, __int128."); | 91 | 16 | if constexpr (std::is_same_v<T, int32_t>) { Branch (91:23): [Folded - Ignored]
| 92 | 16 | return common::exp10_i32(scale); | 93 | 16 | } else if constexpr (std::is_same_v<T, int64_t>) { | 94 | 16 | return common::exp10_i64(scale); | 95 | 16 | } else if constexpr (std::is_same_v<T, __int128>) { | 96 | 16 | return common::exp10_i128(scale); | 97 | 16 | } else if constexpr (std::is_same_v<T, wide::Int256>) { | 98 | 16 | return common::exp10_i256(scale); | 99 | 16 | } | 100 | 16 | } |
_ZN5doris12StringParser20get_scale_multiplierIlEET_i Line | Count | Source | 87 | 7 | static T get_scale_multiplier(int scale) { | 88 | 7 | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || | 89 | 7 | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, | 90 | 7 | "You can only instantiate as int32_t, int64_t, __int128."); | 91 | 7 | if constexpr (std::is_same_v<T, int32_t>) { Branch (91:23): [Folded - Ignored]
| 92 | 7 | return common::exp10_i32(scale); | 93 | 7 | } else if constexpr (std::is_same_v<T, int64_t>) { Branch (93:30): [Folded - Ignored]
| 94 | 7 | return common::exp10_i64(scale); | 95 | 7 | } else if constexpr (std::is_same_v<T, __int128>) { | 96 | 7 | return common::exp10_i128(scale); | 97 | 7 | } else if constexpr (std::is_same_v<T, wide::Int256>) { | 98 | 7 | return common::exp10_i256(scale); | 99 | 7 | } | 100 | 7 | } |
_ZN5doris12StringParser20get_scale_multiplierInEET_i Line | Count | Source | 87 | 109 | static T get_scale_multiplier(int scale) { | 88 | 109 | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || | 89 | 109 | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, | 90 | 109 | "You can only instantiate as int32_t, int64_t, __int128."); | 91 | 109 | if constexpr (std::is_same_v<T, int32_t>) { Branch (91:23): [Folded - Ignored]
| 92 | 109 | return common::exp10_i32(scale); | 93 | 109 | } else if constexpr (std::is_same_v<T, int64_t>) { Branch (93:30): [Folded - Ignored]
| 94 | 109 | return common::exp10_i64(scale); | 95 | 109 | } else if constexpr (std::is_same_v<T, __int128>) { Branch (95:30): [Folded - Ignored]
| 96 | 109 | return common::exp10_i128(scale); | 97 | 109 | } else if constexpr (std::is_same_v<T, wide::Int256>) { | 98 | 109 | return common::exp10_i256(scale); | 99 | 109 | } | 100 | 109 | } |
Unexecuted instantiation: _ZN5doris12StringParser20get_scale_multiplierIN4wide7integerILm256EiEEEET_i |
101 | | |
102 | | // This is considerably faster than glibc's implementation (25x). |
103 | | // In the case of overflow, the max/min value for the data type will be returned. |
104 | | // Assumes s represents a decimal number. |
105 | | template <typename T> |
106 | 149k | static inline T string_to_int(const char* __restrict s, int len, ParseResult* result) { |
107 | 149k | T ans = string_to_int_internal<T>(s, len, result); |
108 | 149k | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 119k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 119k, False: 6]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 26.3k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.85k, False: 24.4k]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 451 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 52, False: 399]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 2.51k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 90, False: 2.42k]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 663 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 258, False: 405]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 20 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 20, False: 0]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 64 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 35, False: 29]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
|
109 | 121k | return ans; |
110 | 121k | } |
111 | | |
112 | 27.7k | int i = skip_leading_whitespace(s, len); |
113 | 27.7k | return string_to_int_internal<T>(s + i, len - i, result); |
114 | 149k | } _ZN5doris12StringParser13string_to_intInEET_PKciPNS0_11ParseResultE Line | Count | Source | 106 | 119k | static inline T string_to_int(const char* __restrict s, int len, ParseResult* result) { | 107 | 119k | T ans = string_to_int_internal<T>(s, len, result); | 108 | 119k | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 119k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 119k, False: 6]
|
| 109 | 119k | return ans; | 110 | 119k | } | 111 | | | 112 | 6 | int i = skip_leading_whitespace(s, len); | 113 | 6 | return string_to_int_internal<T>(s + i, len - i, result); | 114 | 119k | } |
_ZN5doris12StringParser13string_to_intIaEET_PKciPNS0_11ParseResultE Line | Count | Source | 106 | 26.3k | static inline T string_to_int(const char* __restrict s, int len, ParseResult* result) { | 107 | 26.3k | T ans = string_to_int_internal<T>(s, len, result); | 108 | 26.3k | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 26.3k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.85k, False: 24.4k]
|
| 109 | 1.85k | return ans; | 110 | 1.85k | } | 111 | | | 112 | 24.4k | int i = skip_leading_whitespace(s, len); | 113 | 24.4k | return string_to_int_internal<T>(s + i, len - i, result); | 114 | 26.3k | } |
_ZN5doris12StringParser13string_to_intIsEET_PKciPNS0_11ParseResultE Line | Count | Source | 106 | 451 | static inline T string_to_int(const char* __restrict s, int len, ParseResult* result) { | 107 | 451 | T ans = string_to_int_internal<T>(s, len, result); | 108 | 451 | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 451 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 52, False: 399]
|
| 109 | 52 | return ans; | 110 | 52 | } | 111 | | | 112 | 399 | int i = skip_leading_whitespace(s, len); | 113 | 399 | return string_to_int_internal<T>(s + i, len - i, result); | 114 | 451 | } |
_ZN5doris12StringParser13string_to_intIiEET_PKciPNS0_11ParseResultE Line | Count | Source | 106 | 2.51k | static inline T string_to_int(const char* __restrict s, int len, ParseResult* result) { | 107 | 2.51k | T ans = string_to_int_internal<T>(s, len, result); | 108 | 2.51k | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 2.51k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 90, False: 2.42k]
|
| 109 | 90 | return ans; | 110 | 90 | } | 111 | | | 112 | 2.42k | int i = skip_leading_whitespace(s, len); | 113 | 2.42k | return string_to_int_internal<T>(s + i, len - i, result); | 114 | 2.51k | } |
_ZN5doris12StringParser13string_to_intIlEET_PKciPNS0_11ParseResultE Line | Count | Source | 106 | 663 | static inline T string_to_int(const char* __restrict s, int len, ParseResult* result) { | 107 | 663 | T ans = string_to_int_internal<T>(s, len, result); | 108 | 663 | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 663 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 258, False: 405]
|
| 109 | 258 | return ans; | 110 | 258 | } | 111 | | | 112 | 405 | int i = skip_leading_whitespace(s, len); | 113 | 405 | return string_to_int_internal<T>(s + i, len - i, result); | 114 | 663 | } |
Unexecuted instantiation: _ZN5doris12StringParser13string_to_intIN4wide7integerILm256EiEEEET_PKciPNS0_11ParseResultE Unexecuted instantiation: _ZN5doris12StringParser13string_to_intIoEET_PKciPNS0_11ParseResultE _ZN5doris12StringParser13string_to_intImEET_PKciPNS0_11ParseResultE Line | Count | Source | 106 | 20 | static inline T string_to_int(const char* __restrict s, int len, ParseResult* result) { | 107 | 20 | T ans = string_to_int_internal<T>(s, len, result); | 108 | 20 | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 20 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 20, False: 0]
|
| 109 | 20 | return ans; | 110 | 20 | } | 111 | | | 112 | 0 | int i = skip_leading_whitespace(s, len); | 113 | 0 | return string_to_int_internal<T>(s + i, len - i, result); | 114 | 20 | } |
Unexecuted instantiation: _ZN5doris12StringParser13string_to_intIjEET_PKciPNS0_11ParseResultE _ZN5doris12StringParser13string_to_intIhEET_PKciPNS0_11ParseResultE Line | Count | Source | 106 | 64 | static inline T string_to_int(const char* __restrict s, int len, ParseResult* result) { | 107 | 64 | T ans = string_to_int_internal<T>(s, len, result); | 108 | 64 | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 64 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 35, False: 29]
|
| 109 | 35 | return ans; | 110 | 35 | } | 111 | | | 112 | 29 | int i = skip_leading_whitespace(s, len); | 113 | 29 | return string_to_int_internal<T>(s + i, len - i, result); | 114 | 64 | } |
Unexecuted instantiation: _ZN5doris12StringParser13string_to_intItEET_PKciPNS0_11ParseResultE |
115 | | |
116 | | // This is considerably faster than glibc's implementation. |
117 | | // In the case of overflow, the max/min value for the data type will be returned. |
118 | | // Assumes s represents a decimal number. |
119 | | template <typename T> |
120 | 1.37k | static inline T string_to_unsigned_int(const char* __restrict s, int len, ParseResult* result) { |
121 | 1.37k | T ans = string_to_unsigned_int_internal<T>(s, len, result); |
122 | 1.37k | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 343 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 21, False: 322]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 343 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 21, False: 322]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 343 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 21, False: 322]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 343 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 21, False: 322]
|
|
123 | 84 | return ans; |
124 | 84 | } |
125 | | |
126 | 1.28k | int i = skip_leading_whitespace(s, len); |
127 | 1.28k | return string_to_unsigned_int_internal<T>(s + i, len - i, result); |
128 | 1.37k | } _ZN5doris12StringParser22string_to_unsigned_intIhEET_PKciPNS0_11ParseResultE Line | Count | Source | 120 | 343 | static inline T string_to_unsigned_int(const char* __restrict s, int len, ParseResult* result) { | 121 | 343 | T ans = string_to_unsigned_int_internal<T>(s, len, result); | 122 | 343 | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 343 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 21, False: 322]
|
| 123 | 21 | return ans; | 124 | 21 | } | 125 | | | 126 | 322 | int i = skip_leading_whitespace(s, len); | 127 | 322 | return string_to_unsigned_int_internal<T>(s + i, len - i, result); | 128 | 343 | } |
_ZN5doris12StringParser22string_to_unsigned_intItEET_PKciPNS0_11ParseResultE Line | Count | Source | 120 | 343 | static inline T string_to_unsigned_int(const char* __restrict s, int len, ParseResult* result) { | 121 | 343 | T ans = string_to_unsigned_int_internal<T>(s, len, result); | 122 | 343 | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 343 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 21, False: 322]
|
| 123 | 21 | return ans; | 124 | 21 | } | 125 | | | 126 | 322 | int i = skip_leading_whitespace(s, len); | 127 | 322 | return string_to_unsigned_int_internal<T>(s + i, len - i, result); | 128 | 343 | } |
_ZN5doris12StringParser22string_to_unsigned_intIjEET_PKciPNS0_11ParseResultE Line | Count | Source | 120 | 343 | static inline T string_to_unsigned_int(const char* __restrict s, int len, ParseResult* result) { | 121 | 343 | T ans = string_to_unsigned_int_internal<T>(s, len, result); | 122 | 343 | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 343 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 21, False: 322]
|
| 123 | 21 | return ans; | 124 | 21 | } | 125 | | | 126 | 322 | int i = skip_leading_whitespace(s, len); | 127 | 322 | return string_to_unsigned_int_internal<T>(s + i, len - i, result); | 128 | 343 | } |
_ZN5doris12StringParser22string_to_unsigned_intImEET_PKciPNS0_11ParseResultE Line | Count | Source | 120 | 343 | static inline T string_to_unsigned_int(const char* __restrict s, int len, ParseResult* result) { | 121 | 343 | T ans = string_to_unsigned_int_internal<T>(s, len, result); | 122 | 343 | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 343 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 21, False: 322]
|
| 123 | 21 | return ans; | 124 | 21 | } | 125 | | | 126 | 322 | int i = skip_leading_whitespace(s, len); | 127 | 322 | return string_to_unsigned_int_internal<T>(s + i, len - i, result); | 128 | 343 | } |
|
129 | | |
130 | | // Convert a string s representing a number in given base into a decimal number. |
131 | | template <typename T> |
132 | | static inline T string_to_int(const char* __restrict s, int len, int base, |
133 | 27.8k | ParseResult* result) { |
134 | 27.8k | T ans = string_to_int_internal<T>(s, len, base, result); |
135 | 27.8k | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 26.4k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.91k, False: 24.5k]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 490 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 56, False: 434]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 441 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 49, False: 392]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 441 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 49, False: 392]
|
| if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 1 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1, False: 0]
|
|
136 | 2.06k | return ans; |
137 | 2.06k | } |
138 | | |
139 | 25.7k | int i = skip_leading_whitespace(s, len); |
140 | 25.7k | return string_to_int_internal<T>(s + i, len - i, base, result); |
141 | 27.8k | } _ZN5doris12StringParser13string_to_intIaEET_PKciiPNS0_11ParseResultE Line | Count | Source | 133 | 26.4k | ParseResult* result) { | 134 | 26.4k | T ans = string_to_int_internal<T>(s, len, base, result); | 135 | 26.4k | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 26.4k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.91k, False: 24.5k]
|
| 136 | 1.91k | return ans; | 137 | 1.91k | } | 138 | | | 139 | 24.5k | int i = skip_leading_whitespace(s, len); | 140 | 24.5k | return string_to_int_internal<T>(s + i, len - i, base, result); | 141 | 26.4k | } |
_ZN5doris12StringParser13string_to_intIsEET_PKciiPNS0_11ParseResultE Line | Count | Source | 133 | 490 | ParseResult* result) { | 134 | 490 | T ans = string_to_int_internal<T>(s, len, base, result); | 135 | 490 | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 490 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 56, False: 434]
|
| 136 | 56 | return ans; | 137 | 56 | } | 138 | | | 139 | 434 | int i = skip_leading_whitespace(s, len); | 140 | 434 | return string_to_int_internal<T>(s + i, len - i, base, result); | 141 | 490 | } |
_ZN5doris12StringParser13string_to_intIiEET_PKciiPNS0_11ParseResultE Line | Count | Source | 133 | 441 | ParseResult* result) { | 134 | 441 | T ans = string_to_int_internal<T>(s, len, base, result); | 135 | 441 | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 441 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 49, False: 392]
|
| 136 | 49 | return ans; | 137 | 49 | } | 138 | | | 139 | 392 | int i = skip_leading_whitespace(s, len); | 140 | 392 | return string_to_int_internal<T>(s + i, len - i, base, result); | 141 | 441 | } |
_ZN5doris12StringParser13string_to_intIlEET_PKciiPNS0_11ParseResultE Line | Count | Source | 133 | 441 | ParseResult* result) { | 134 | 441 | T ans = string_to_int_internal<T>(s, len, base, result); | 135 | 441 | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 441 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 49, False: 392]
|
| 136 | 49 | return ans; | 137 | 49 | } | 138 | | | 139 | 392 | int i = skip_leading_whitespace(s, len); | 140 | 392 | return string_to_int_internal<T>(s + i, len - i, base, result); | 141 | 441 | } |
_ZN5doris12StringParser13string_to_intImEET_PKciiPNS0_11ParseResultE Line | Count | Source | 133 | 1 | ParseResult* result) { | 134 | 1 | T ans = string_to_int_internal<T>(s, len, base, result); | 135 | 1 | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 1 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1, False: 0]
|
| 136 | 1 | return ans; | 137 | 1 | } | 138 | | | 139 | 0 | int i = skip_leading_whitespace(s, len); | 140 | 0 | return string_to_int_internal<T>(s + i, len - i, base, result); | 141 | 1 | } |
|
142 | | |
143 | | template <typename T> |
144 | 66.9k | static inline T string_to_float(const char* __restrict s, int len, ParseResult* result) { |
145 | 66.9k | return string_to_float_internal<T>(s, len, result); |
146 | 66.9k | } _ZN5doris12StringParser15string_to_floatIdEET_PKciPNS0_11ParseResultE Line | Count | Source | 144 | 58.6k | static inline T string_to_float(const char* __restrict s, int len, ParseResult* result) { | 145 | 58.6k | return string_to_float_internal<T>(s, len, result); | 146 | 58.6k | } |
_ZN5doris12StringParser15string_to_floatIfEET_PKciPNS0_11ParseResultE Line | Count | Source | 144 | 8.25k | static inline T string_to_float(const char* __restrict s, int len, ParseResult* result) { | 145 | 8.25k | return string_to_float_internal<T>(s, len, result); | 146 | 8.25k | } |
|
147 | | |
148 | | // Parses a string for 'true' or 'false', case insensitive. |
149 | 323 | static inline bool string_to_bool(const char* __restrict s, int len, ParseResult* result) { |
150 | 323 | bool ans = string_to_bool_internal(s, len, result); |
151 | 323 | if (LIKELY(*result == PARSE_SUCCESS)) {Line | Count | Source | 35 | 323 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 26, False: 297]
|
|
152 | 26 | return ans; |
153 | 26 | } |
154 | | |
155 | 297 | int i = skip_leading_whitespace(s, len); |
156 | 297 | return string_to_bool_internal(s + i, len - i, result); |
157 | 323 | } |
158 | | |
159 | | template <PrimitiveType P, typename T = PrimitiveTypeTraits<P>::CppType::NativeType, |
160 | | typename DecimalType = PrimitiveTypeTraits<P>::ColumnType::value_type> |
161 | | static inline T string_to_decimal(const char* __restrict s, int len, int type_precision, |
162 | | int type_scale, ParseResult* result); |
163 | | |
164 | | template <typename T> |
165 | | static Status split_string_to_map(const std::string& base, const T element_separator, |
166 | | const T key_value_separator, |
167 | | std::map<std::string, std::string>* result) { |
168 | | int key_pos = 0; |
169 | | int key_end; |
170 | | int val_pos; |
171 | | int val_end; |
172 | | |
173 | | while ((key_end = base.find(key_value_separator, key_pos)) != std::string::npos) { |
174 | | if ((val_pos = base.find_first_not_of(key_value_separator, key_end)) == |
175 | | std::string::npos) { |
176 | | break; |
177 | | } |
178 | | if ((val_end = base.find(element_separator, val_pos)) == std::string::npos) { |
179 | | val_end = base.size(); |
180 | | } |
181 | | result->insert(std::make_pair(base.substr(key_pos, key_end - key_pos), |
182 | | base.substr(val_pos, val_end - val_pos))); |
183 | | key_pos = val_end; |
184 | | if (key_pos != std::string::npos) { |
185 | | ++key_pos; |
186 | | } |
187 | | } |
188 | | |
189 | | return Status::OK(); |
190 | | } |
191 | | |
192 | | private: |
193 | | // This is considerably faster than glibc's implementation. |
194 | | // In the case of overflow, the max/min value for the data type will be returned. |
195 | | // Assumes s represents a decimal number. |
196 | | // Return PARSE_FAILURE on leading whitespace. Trailing whitespace is allowed. |
197 | | template <typename T> |
198 | | static inline T string_to_int_internal(const char* __restrict s, int len, ParseResult* result); |
199 | | |
200 | | // This is considerably faster than glibc's implementation. |
201 | | // In the case of overflow, the max/min value for the data type will be returned. |
202 | | // Assumes s represents a decimal number. |
203 | | // Return PARSE_FAILURE on leading whitespace. Trailing whitespace is allowed. |
204 | | template <typename T> |
205 | | static inline T string_to_unsigned_int_internal(const char* __restrict s, int len, |
206 | | ParseResult* result); |
207 | | |
208 | | // Convert a string s representing a number in given base into a decimal number. |
209 | | // Return PARSE_FAILURE on leading whitespace. Trailing whitespace is allowed. |
210 | | template <typename T> |
211 | | static inline T string_to_int_internal(const char* __restrict s, int len, int base, |
212 | | ParseResult* result); |
213 | | |
214 | | // Converts an ascii string to an integer of type T assuming it cannot overflow |
215 | | // and the number is positive. |
216 | | // Leading whitespace is not allowed. Trailing whitespace will be skipped. |
217 | | template <typename T> |
218 | | static inline T string_to_int_no_overflow(const char* __restrict s, int len, |
219 | | ParseResult* result); |
220 | | |
221 | | // This is considerably faster than glibc's implementation (>100x why???) |
222 | | // No special case handling needs to be done for overflows, the floating point spec |
223 | | // already does it and will cap the values to -inf/inf |
224 | | // To avoid inaccurate conversions this function falls back to strtod for |
225 | | // scientific notation. |
226 | | // Return PARSE_FAILURE on leading whitespace. Trailing whitespace is allowed. |
227 | | // TODO: Investigate using intrinsics to speed up the slow strtod path. |
228 | | template <typename T> |
229 | | static inline T string_to_float_internal(const char* __restrict s, int len, |
230 | | ParseResult* result); |
231 | | |
232 | | // parses a string for 'true' or 'false', case insensitive |
233 | | // Return PARSE_FAILURE on leading whitespace. Trailing whitespace is allowed. |
234 | | static inline bool string_to_bool_internal(const char* __restrict s, int len, |
235 | | ParseResult* result); |
236 | | |
237 | | // Returns true if s only contains whitespace. |
238 | 25.5k | static inline bool is_all_whitespace(const char* __restrict s, int len) { |
239 | 100k | for (int i = 0; i < len; ++i) { Branch (239:25): [True: 75.6k, False: 24.8k]
|
240 | 75.6k | if (!LIKELY(is_whitespace(s[i]))) {Line | Count | Source | 35 | 75.6k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) |
Branch (240:17): [True: 790, False: 74.8k]
|
241 | 790 | return false; |
242 | 790 | } |
243 | 75.6k | } |
244 | 24.8k | return true; |
245 | 25.5k | } |
246 | | |
247 | | // For strings like "3.0", "3.123", and "3.", can parse them as 3. |
248 | 511 | static inline bool is_float_suffix(const char* __restrict s, int len) { |
249 | 511 | return (s[0] == '.' && is_all_digit(s + 1, len - 1)); Branch (249:17): [True: 3, False: 508]
Branch (249:32): [True: 1, False: 2]
|
250 | 511 | } |
251 | | |
252 | 3 | static inline bool is_all_digit(const char* __restrict s, int len) { |
253 | 4 | for (int i = 0; i < len; ++i) { Branch (253:25): [True: 3, False: 1]
|
254 | 3 | if (!LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 6 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:42): [True: 3, False: 0]
Branch (35:42): [True: 1, False: 2]
|
Branch (254:17): [True: 2, False: 1]
|
255 | 2 | return false; |
256 | 2 | } |
257 | 3 | } |
258 | 1 | return true; |
259 | 3 | } |
260 | | |
261 | | // Returns the position of the first non-whitespace character in s. |
262 | 55.1k | static inline int skip_leading_whitespace(const char* __restrict s, int len) { |
263 | 55.1k | int i = 0; |
264 | 204k | while (i < len && is_whitespace(s[i])) { Branch (264:16): [True: 203k, False: 1.25k]
Branch (264:27): [True: 149k, False: 53.8k]
|
265 | 149k | ++i; |
266 | 149k | } |
267 | 55.1k | return i; |
268 | 55.1k | } |
269 | | |
270 | | // Our own definition of "isspace" that optimize on the ' ' branch. |
271 | 495k | static inline bool is_whitespace(const char& c) { |
272 | 495k | return LIKELY(c == ' ') || Line | Count | Source | 35 | 990k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 53.3k, False: 441k]
|
|
273 | 495k | UNLIKELY(c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'); Line | Count | Source | 36 | 3.02M | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 252k, False: 188k]
Branch (36:44): [True: 50.5k, False: 391k]
Branch (36:44): [True: 50.5k, False: 340k]
Branch (36:44): [True: 50.5k, False: 290k]
Branch (36:44): [True: 50.5k, False: 239k]
Branch (36:44): [True: 50.5k, False: 188k]
|
|
274 | 495k | } |
275 | | |
276 | | }; // end of class StringParser |
277 | | |
278 | | template <typename T> |
279 | 177k | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { |
280 | 177k | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 50.8k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 206, False: 50.6k]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 119k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 119k]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 850 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 850]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 4.94k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 2.11k, False: 2.83k]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 1.06k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1.06k]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 20 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 20]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 93 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 93]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
|
281 | 2.31k | *result = PARSE_FAILURE; |
282 | 2.31k | return 0; |
283 | 2.31k | } |
284 | | |
285 | 175k | typedef typename std::make_unsigned<T>::type UnsignedT; |
286 | 175k | UnsignedT val = 0; |
287 | 175k | UnsignedT max_val = StringParser::numeric_limits<T>(false); |
288 | 175k | bool negative = false; |
289 | 175k | int i = 0; |
290 | 175k | switch (*s) { Branch (290:13): [True: 36.7k, False: 13.9k]
Branch (290:13): [True: 119k, False: 236]
Branch (290:13): [True: 592, False: 258]
Branch (290:13): [True: 2.53k, False: 302]
Branch (290:13): [True: 812, False: 256]
Branch (290:13): [True: 0, False: 0]
Branch (290:13): [True: 0, False: 0]
Branch (290:13): [True: 20, False: 0]
Branch (290:13): [True: 0, False: 0]
Branch (290:13): [True: 85, False: 8]
Branch (290:13): [True: 0, False: 0]
|
291 | 14.6k | case '-': Branch (291:5): [True: 13.8k, False: 36.8k]
Branch (291:5): [True: 236, False: 119k]
Branch (291:5): [True: 209, False: 641]
Branch (291:5): [True: 180, False: 2.65k]
Branch (291:5): [True: 207, False: 861]
Branch (291:5): [True: 0, False: 0]
Branch (291:5): [True: 0, False: 0]
Branch (291:5): [True: 0, False: 20]
Branch (291:5): [True: 0, False: 0]
Branch (291:5): [True: 8, False: 85]
Branch (291:5): [True: 0, False: 0]
|
292 | 14.6k | negative = true; |
293 | 14.6k | max_val += 1; |
294 | 14.6k | [[fallthrough]]; |
295 | 14.9k | case '+': Branch (295:5): [True: 98, False: 50.5k]
Branch (295:5): [True: 0, False: 119k]
Branch (295:5): [True: 49, False: 801]
Branch (295:5): [True: 122, False: 2.71k]
Branch (295:5): [True: 49, False: 1.01k]
Branch (295:5): [True: 0, False: 0]
Branch (295:5): [True: 0, False: 0]
Branch (295:5): [True: 0, False: 20]
Branch (295:5): [True: 0, False: 0]
Branch (295:5): [True: 0, False: 93]
Branch (295:5): [True: 0, False: 0]
|
296 | 14.9k | ++i; |
297 | | // only one '+'/'-' char, so could return failure directly |
298 | 14.9k | if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 13.9k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 13.9k]
|
| if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 236 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 236]
|
| if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 258 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 258]
|
| if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 302 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 6, False: 296]
|
| if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 256 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 256]
|
| if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 8 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 8]
|
| if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
|
299 | 6 | *result = PARSE_FAILURE; |
300 | 6 | return 0; |
301 | 6 | } |
302 | 175k | } |
303 | | |
304 | | // This is the fast path where the string cannot overflow. |
305 | 175k | if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 50.6k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.43k, False: 49.1k]
|
| if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 119k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 119k, False: 15]
|
| if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 850 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 114, False: 736]
|
| if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 2.83k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.57k, False: 1.25k]
|
| if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 1.06k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 635, False: 433]
|
| if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
| if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
| if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 20 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 20, False: 0]
|
| if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
| if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 93 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 53, False: 40]
|
| if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
|
306 | 123k | val = string_to_int_no_overflow<UnsignedT>(s + i, len - i, result); |
307 | 123k | return static_cast<T>(negative ? -val : val); Branch (307:31): [True: 700, False: 739]
Branch (307:31): [True: 236, False: 119k]
Branch (307:31): [True: 56, False: 58]
Branch (307:31): [True: 63, False: 1.51k]
Branch (307:31): [True: 99, False: 536]
Branch (307:31): [True: 0, False: 0]
Branch (307:31): [True: 0, False: 0]
Branch (307:31): [True: 0, False: 20]
Branch (307:31): [True: 0, False: 0]
Branch (307:31): [True: 8, False: 45]
Branch (307:31): [True: 0, False: 0]
|
308 | 123k | } |
309 | | |
310 | 51.6k | const T max_div_10 = max_val / 10; |
311 | 51.6k | const T max_mod_10 = max_val % 10; |
312 | | |
313 | 51.6k | int first = i; |
314 | 115k | for (; i < len; ++i) { Branch (314:12): [True: 103k, False: 433]
Branch (314:12): [True: 357, False: 3]
Branch (314:12): [True: 2.16k, False: 24]
Branch (314:12): [True: 3.77k, False: 17]
Branch (314:12): [True: 4.63k, False: 27]
Branch (314:12): [True: 0, False: 0]
Branch (314:12): [True: 0, False: 0]
Branch (314:12): [True: 0, False: 0]
Branch (314:12): [True: 0, False: 0]
Branch (314:12): [True: 40, False: 0]
Branch (314:12): [True: 0, False: 0]
|
315 | 114k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 173k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 69.4k, False: 34.2k]
Branch (35:42): [True: 69.8k, False: 33.8k]
Branch (35:42): [True: 69.4k, False: 370]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 708 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 351, False: 6]
Branch (35:42): [True: 351, False: 6]
Branch (35:42): [True: 351, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 3.74k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.58k, False: 588]
Branch (35:42): [True: 1.58k, False: 588]
Branch (35:42): [True: 1.58k, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 6.96k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 2.66k, False: 1.11k]
Branch (35:42): [True: 3.18k, False: 595]
Branch (35:42): [True: 2.66k, False: 520]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 8.99k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 4.35k, False: 288]
Branch (35:42): [True: 4.35k, False: 288]
Branch (35:42): [True: 4.35k, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 76 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 40]
Branch (35:42): [True: 36, False: 4]
Branch (35:42): [True: 0, False: 36]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
|
|
316 | 78.3k | T digit = s[i] - '0'; |
317 | | // This is a tricky check to see if adding this digit will cause an overflow. |
318 | 78.3k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 69.4k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 14.5k, False: 54.9k]
|
| if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 351 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 6, False: 345]
|
| if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 1.58k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 124, False: 1.45k]
|
| if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 2.66k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 124, False: 2.54k]
|
| if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 4.35k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 118, False: 4.23k]
|
| if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
|
319 | 14.8k | *result = PARSE_OVERFLOW; |
320 | 14.8k | return negative ? -max_val : max_val; Branch (320:24): [True: 7.23k, False: 7.28k]
Branch (320:24): [True: 0, False: 6]
Branch (320:24): [True: 62, False: 62]
Branch (320:24): [True: 62, False: 62]
Branch (320:24): [True: 56, False: 62]
Branch (320:24): [True: 0, False: 0]
Branch (320:24): [True: 0, False: 0]
Branch (320:24): [True: 0, False: 0]
Branch (320:24): [True: 0, False: 0]
Branch (320:24): [True: 0, False: 0]
Branch (320:24): [True: 0, False: 0]
|
321 | 14.8k | } |
322 | 63.4k | val = val * 10 + digit; |
323 | 63.4k | } else { |
324 | 36.2k | if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 57.3k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 322, False: 11.0k]
Branch (36:44): [True: 322, False: 0]
Branch (36:44): [True: 22.8k, False: 11.3k]
|
| if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 6 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 6, False: 0]
|
| if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 1.00k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 210]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 378, False: 210]
|
| if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 1.58k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 72, False: 126]
Branch (36:44): [True: 72, False: 0]
Branch (36:44): [True: 917, False: 198]
|
| if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 456 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 84]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 204, False: 84]
|
| if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
|
| if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
|
| if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
|
| if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
|
| if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 40 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 40, False: 0]
|
| if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
|
Branch (324:17): [True: 23.2k, False: 11.0k]
Branch (324:17): [True: 6, False: 0]
Branch (324:17): [True: 378, False: 210]
Branch (324:17): [True: 989, False: 126]
Branch (324:17): [True: 204, False: 84]
Branch (324:17): [True: 0, False: 0]
Branch (324:17): [True: 0, False: 0]
Branch (324:17): [True: 0, False: 0]
Branch (324:17): [True: 0, False: 0]
Branch (324:17): [True: 40, False: 0]
Branch (324:17): [True: 0, False: 0]
|
325 | 36.2k | !is_float_suffix(s + i, len - i))))) { |
326 | | // Reject the string because either the first char was not a digit, |
327 | | // or the remaining chars are not all whitespace |
328 | 24.8k | *result = PARSE_FAILURE; |
329 | 24.8k | return 0; |
330 | 24.8k | } |
331 | | // Returning here is slightly faster than breaking the loop. |
332 | 11.4k | *result = PARSE_SUCCESS; |
333 | 11.4k | return static_cast<T>(negative ? -val : val); Branch (333:35): [True: 5.46k, False: 5.58k]
Branch (333:35): [True: 0, False: 0]
Branch (333:35): [True: 84, False: 126]
Branch (333:35): [True: 42, False: 84]
Branch (333:35): [True: 42, False: 42]
Branch (333:35): [True: 0, False: 0]
Branch (333:35): [True: 0, False: 0]
Branch (333:35): [True: 0, False: 0]
Branch (333:35): [True: 0, False: 0]
Branch (333:35): [True: 0, False: 0]
Branch (333:35): [True: 0, False: 0]
|
334 | 36.2k | } |
335 | 114k | } |
336 | 504 | *result = PARSE_SUCCESS; |
337 | 504 | return static_cast<T>(negative ? -val : val); Branch (337:27): [True: 213, False: 220]
Branch (337:27): [True: 0, False: 3]
Branch (337:27): [True: 7, False: 17]
Branch (337:27): [True: 7, False: 10]
Branch (337:27): [True: 10, False: 17]
Branch (337:27): [True: 0, False: 0]
Branch (337:27): [True: 0, False: 0]
Branch (337:27): [True: 0, False: 0]
Branch (337:27): [True: 0, False: 0]
Branch (337:27): [True: 0, False: 0]
Branch (337:27): [True: 0, False: 0]
|
338 | 51.6k | } _ZN5doris12StringParser22string_to_int_internalIaEET_PKciPNS0_11ParseResultE Line | Count | Source | 279 | 50.8k | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 280 | 50.8k | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 50.8k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 206, False: 50.6k]
|
| 281 | 206 | *result = PARSE_FAILURE; | 282 | 206 | return 0; | 283 | 206 | } | 284 | | | 285 | 50.6k | typedef typename std::make_unsigned<T>::type UnsignedT; | 286 | 50.6k | UnsignedT val = 0; | 287 | 50.6k | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 288 | 50.6k | bool negative = false; | 289 | 50.6k | int i = 0; | 290 | 50.6k | switch (*s) { Branch (290:13): [True: 36.7k, False: 13.9k]
| 291 | 13.8k | case '-': Branch (291:5): [True: 13.8k, False: 36.8k]
| 292 | 13.8k | negative = true; | 293 | 13.8k | max_val += 1; | 294 | 13.8k | [[fallthrough]]; | 295 | 13.9k | case '+': Branch (295:5): [True: 98, False: 50.5k]
| 296 | 13.9k | ++i; | 297 | | // only one '+'/'-' char, so could return failure directly | 298 | 13.9k | if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 13.9k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 13.9k]
|
| 299 | 0 | *result = PARSE_FAILURE; | 300 | 0 | return 0; | 301 | 0 | } | 302 | 50.6k | } | 303 | | | 304 | | // This is the fast path where the string cannot overflow. | 305 | 50.6k | if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 50.6k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.43k, False: 49.1k]
|
| 306 | 1.43k | val = string_to_int_no_overflow<UnsignedT>(s + i, len - i, result); | 307 | 1.43k | return static_cast<T>(negative ? -val : val); Branch (307:31): [True: 700, False: 739]
| 308 | 1.43k | } | 309 | | | 310 | 49.1k | const T max_div_10 = max_val / 10; | 311 | 49.1k | const T max_mod_10 = max_val % 10; | 312 | | | 313 | 49.1k | int first = i; | 314 | 104k | for (; i < len; ++i) { Branch (314:12): [True: 103k, False: 433]
| 315 | 103k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 173k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 69.4k, False: 34.2k]
Branch (35:42): [True: 69.8k, False: 33.8k]
Branch (35:42): [True: 69.4k, False: 370]
|
| 316 | 69.4k | T digit = s[i] - '0'; | 317 | | // This is a tricky check to see if adding this digit will cause an overflow. | 318 | 69.4k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 69.4k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 14.5k, False: 54.9k]
|
| 319 | 14.5k | *result = PARSE_OVERFLOW; | 320 | 14.5k | return negative ? -max_val : max_val; Branch (320:24): [True: 7.23k, False: 7.28k]
| 321 | 14.5k | } | 322 | 54.9k | val = val * 10 + digit; | 323 | 54.9k | } else { | 324 | 34.2k | if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 57.3k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 322, False: 11.0k]
Branch (36:44): [True: 322, False: 0]
Branch (36:44): [True: 22.8k, False: 11.3k]
|
Branch (324:17): [True: 23.2k, False: 11.0k]
| 325 | 34.2k | !is_float_suffix(s + i, len - i))))) { | 326 | | // Reject the string because either the first char was not a digit, | 327 | | // or the remaining chars are not all whitespace | 328 | 23.2k | *result = PARSE_FAILURE; | 329 | 23.2k | return 0; | 330 | 23.2k | } | 331 | | // Returning here is slightly faster than breaking the loop. | 332 | 11.0k | *result = PARSE_SUCCESS; | 333 | 11.0k | return static_cast<T>(negative ? -val : val); Branch (333:35): [True: 5.46k, False: 5.58k]
| 334 | 34.2k | } | 335 | 103k | } | 336 | 433 | *result = PARSE_SUCCESS; | 337 | 433 | return static_cast<T>(negative ? -val : val); Branch (337:27): [True: 213, False: 220]
| 338 | 49.1k | } |
_ZN5doris12StringParser22string_to_int_internalInEET_PKciPNS0_11ParseResultE Line | Count | Source | 279 | 119k | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 280 | 119k | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 119k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 119k]
|
| 281 | 0 | *result = PARSE_FAILURE; | 282 | 0 | return 0; | 283 | 0 | } | 284 | | | 285 | 119k | typedef typename std::make_unsigned<T>::type UnsignedT; | 286 | 119k | UnsignedT val = 0; | 287 | 119k | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 288 | 119k | bool negative = false; | 289 | 119k | int i = 0; | 290 | 119k | switch (*s) { Branch (290:13): [True: 119k, False: 236]
| 291 | 236 | case '-': Branch (291:5): [True: 236, False: 119k]
| 292 | 236 | negative = true; | 293 | 236 | max_val += 1; | 294 | 236 | [[fallthrough]]; | 295 | 236 | case '+': Branch (295:5): [True: 0, False: 119k]
| 296 | 236 | ++i; | 297 | | // only one '+'/'-' char, so could return failure directly | 298 | 236 | if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 236 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 236]
|
| 299 | 0 | *result = PARSE_FAILURE; | 300 | 0 | return 0; | 301 | 0 | } | 302 | 119k | } | 303 | | | 304 | | // This is the fast path where the string cannot overflow. | 305 | 119k | if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 119k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 119k, False: 15]
|
| 306 | 119k | val = string_to_int_no_overflow<UnsignedT>(s + i, len - i, result); | 307 | 119k | return static_cast<T>(negative ? -val : val); Branch (307:31): [True: 236, False: 119k]
| 308 | 119k | } | 309 | | | 310 | 15 | const T max_div_10 = max_val / 10; | 311 | 15 | const T max_mod_10 = max_val % 10; | 312 | | | 313 | 15 | int first = i; | 314 | 360 | for (; i < len; ++i) { Branch (314:12): [True: 357, False: 3]
| 315 | 357 | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 708 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 351, False: 6]
Branch (35:42): [True: 351, False: 6]
Branch (35:42): [True: 351, False: 0]
|
| 316 | 351 | T digit = s[i] - '0'; | 317 | | // This is a tricky check to see if adding this digit will cause an overflow. | 318 | 351 | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 351 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 6, False: 345]
|
| 319 | 6 | *result = PARSE_OVERFLOW; | 320 | 6 | return negative ? -max_val : max_val; Branch (320:24): [True: 0, False: 6]
| 321 | 6 | } | 322 | 345 | val = val * 10 + digit; | 323 | 345 | } else { | 324 | 6 | if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 6 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 6, False: 0]
|
Branch (324:17): [True: 6, False: 0]
| 325 | 6 | !is_float_suffix(s + i, len - i))))) { | 326 | | // Reject the string because either the first char was not a digit, | 327 | | // or the remaining chars are not all whitespace | 328 | 6 | *result = PARSE_FAILURE; | 329 | 6 | return 0; | 330 | 6 | } | 331 | | // Returning here is slightly faster than breaking the loop. | 332 | 0 | *result = PARSE_SUCCESS; | 333 | 0 | return static_cast<T>(negative ? -val : val); Branch (333:35): [True: 0, False: 0]
| 334 | 6 | } | 335 | 357 | } | 336 | 3 | *result = PARSE_SUCCESS; | 337 | 3 | return static_cast<T>(negative ? -val : val); Branch (337:27): [True: 0, False: 3]
| 338 | 15 | } |
_ZN5doris12StringParser22string_to_int_internalIsEET_PKciPNS0_11ParseResultE Line | Count | Source | 279 | 850 | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 280 | 850 | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 850 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 850]
|
| 281 | 0 | *result = PARSE_FAILURE; | 282 | 0 | return 0; | 283 | 0 | } | 284 | | | 285 | 850 | typedef typename std::make_unsigned<T>::type UnsignedT; | 286 | 850 | UnsignedT val = 0; | 287 | 850 | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 288 | 850 | bool negative = false; | 289 | 850 | int i = 0; | 290 | 850 | switch (*s) { Branch (290:13): [True: 592, False: 258]
| 291 | 209 | case '-': Branch (291:5): [True: 209, False: 641]
| 292 | 209 | negative = true; | 293 | 209 | max_val += 1; | 294 | 209 | [[fallthrough]]; | 295 | 258 | case '+': Branch (295:5): [True: 49, False: 801]
| 296 | 258 | ++i; | 297 | | // only one '+'/'-' char, so could return failure directly | 298 | 258 | if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 258 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 258]
|
| 299 | 0 | *result = PARSE_FAILURE; | 300 | 0 | return 0; | 301 | 0 | } | 302 | 850 | } | 303 | | | 304 | | // This is the fast path where the string cannot overflow. | 305 | 850 | if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 850 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 114, False: 736]
|
| 306 | 114 | val = string_to_int_no_overflow<UnsignedT>(s + i, len - i, result); | 307 | 114 | return static_cast<T>(negative ? -val : val); Branch (307:31): [True: 56, False: 58]
| 308 | 114 | } | 309 | | | 310 | 736 | const T max_div_10 = max_val / 10; | 311 | 736 | const T max_mod_10 = max_val % 10; | 312 | | | 313 | 736 | int first = i; | 314 | 2.19k | for (; i < len; ++i) { Branch (314:12): [True: 2.16k, False: 24]
| 315 | 2.16k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 3.74k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.58k, False: 588]
Branch (35:42): [True: 1.58k, False: 588]
Branch (35:42): [True: 1.58k, False: 0]
|
| 316 | 1.58k | T digit = s[i] - '0'; | 317 | | // This is a tricky check to see if adding this digit will cause an overflow. | 318 | 1.58k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 1.58k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 124, False: 1.45k]
|
| 319 | 124 | *result = PARSE_OVERFLOW; | 320 | 124 | return negative ? -max_val : max_val; Branch (320:24): [True: 62, False: 62]
| 321 | 124 | } | 322 | 1.45k | val = val * 10 + digit; | 323 | 1.45k | } else { | 324 | 588 | if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 1.00k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 210]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 378, False: 210]
|
Branch (324:17): [True: 378, False: 210]
| 325 | 588 | !is_float_suffix(s + i, len - i))))) { | 326 | | // Reject the string because either the first char was not a digit, | 327 | | // or the remaining chars are not all whitespace | 328 | 378 | *result = PARSE_FAILURE; | 329 | 378 | return 0; | 330 | 378 | } | 331 | | // Returning here is slightly faster than breaking the loop. | 332 | 210 | *result = PARSE_SUCCESS; | 333 | 210 | return static_cast<T>(negative ? -val : val); Branch (333:35): [True: 84, False: 126]
| 334 | 588 | } | 335 | 2.16k | } | 336 | 24 | *result = PARSE_SUCCESS; | 337 | 24 | return static_cast<T>(negative ? -val : val); Branch (337:27): [True: 7, False: 17]
| 338 | 736 | } |
_ZN5doris12StringParser22string_to_int_internalIiEET_PKciPNS0_11ParseResultE Line | Count | Source | 279 | 4.94k | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 280 | 4.94k | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 4.94k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 2.11k, False: 2.83k]
|
| 281 | 2.11k | *result = PARSE_FAILURE; | 282 | 2.11k | return 0; | 283 | 2.11k | } | 284 | | | 285 | 2.83k | typedef typename std::make_unsigned<T>::type UnsignedT; | 286 | 2.83k | UnsignedT val = 0; | 287 | 2.83k | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 288 | 2.83k | bool negative = false; | 289 | 2.83k | int i = 0; | 290 | 2.83k | switch (*s) { Branch (290:13): [True: 2.53k, False: 302]
| 291 | 180 | case '-': Branch (291:5): [True: 180, False: 2.65k]
| 292 | 180 | negative = true; | 293 | 180 | max_val += 1; | 294 | 180 | [[fallthrough]]; | 295 | 302 | case '+': Branch (295:5): [True: 122, False: 2.71k]
| 296 | 302 | ++i; | 297 | | // only one '+'/'-' char, so could return failure directly | 298 | 302 | if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 302 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 6, False: 296]
|
| 299 | 6 | *result = PARSE_FAILURE; | 300 | 6 | return 0; | 301 | 6 | } | 302 | 2.83k | } | 303 | | | 304 | | // This is the fast path where the string cannot overflow. | 305 | 2.83k | if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 2.83k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.57k, False: 1.25k]
|
| 306 | 1.57k | val = string_to_int_no_overflow<UnsignedT>(s + i, len - i, result); | 307 | 1.57k | return static_cast<T>(negative ? -val : val); Branch (307:31): [True: 63, False: 1.51k]
| 308 | 1.57k | } | 309 | | | 310 | 1.25k | const T max_div_10 = max_val / 10; | 311 | 1.25k | const T max_mod_10 = max_val % 10; | 312 | | | 313 | 1.25k | int first = i; | 314 | 3.79k | for (; i < len; ++i) { Branch (314:12): [True: 3.77k, False: 17]
| 315 | 3.77k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 6.96k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 2.66k, False: 1.11k]
Branch (35:42): [True: 3.18k, False: 595]
Branch (35:42): [True: 2.66k, False: 520]
|
| 316 | 2.66k | T digit = s[i] - '0'; | 317 | | // This is a tricky check to see if adding this digit will cause an overflow. | 318 | 2.66k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 2.66k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 124, False: 2.54k]
|
| 319 | 124 | *result = PARSE_OVERFLOW; | 320 | 124 | return negative ? -max_val : max_val; Branch (320:24): [True: 62, False: 62]
| 321 | 124 | } | 322 | 2.54k | val = val * 10 + digit; | 323 | 2.54k | } else { | 324 | 1.11k | if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 1.58k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 72, False: 126]
Branch (36:44): [True: 72, False: 0]
Branch (36:44): [True: 917, False: 198]
|
Branch (324:17): [True: 989, False: 126]
| 325 | 1.11k | !is_float_suffix(s + i, len - i))))) { | 326 | | // Reject the string because either the first char was not a digit, | 327 | | // or the remaining chars are not all whitespace | 328 | 989 | *result = PARSE_FAILURE; | 329 | 989 | return 0; | 330 | 989 | } | 331 | | // Returning here is slightly faster than breaking the loop. | 332 | 126 | *result = PARSE_SUCCESS; | 333 | 126 | return static_cast<T>(negative ? -val : val); Branch (333:35): [True: 42, False: 84]
| 334 | 1.11k | } | 335 | 3.77k | } | 336 | 17 | *result = PARSE_SUCCESS; | 337 | 17 | return static_cast<T>(negative ? -val : val); Branch (337:27): [True: 7, False: 10]
| 338 | 1.25k | } |
_ZN5doris12StringParser22string_to_int_internalIlEET_PKciPNS0_11ParseResultE Line | Count | Source | 279 | 1.06k | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 280 | 1.06k | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 1.06k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1.06k]
|
| 281 | 0 | *result = PARSE_FAILURE; | 282 | 0 | return 0; | 283 | 0 | } | 284 | | | 285 | 1.06k | typedef typename std::make_unsigned<T>::type UnsignedT; | 286 | 1.06k | UnsignedT val = 0; | 287 | 1.06k | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 288 | 1.06k | bool negative = false; | 289 | 1.06k | int i = 0; | 290 | 1.06k | switch (*s) { Branch (290:13): [True: 812, False: 256]
| 291 | 207 | case '-': Branch (291:5): [True: 207, False: 861]
| 292 | 207 | negative = true; | 293 | 207 | max_val += 1; | 294 | 207 | [[fallthrough]]; | 295 | 256 | case '+': Branch (295:5): [True: 49, False: 1.01k]
| 296 | 256 | ++i; | 297 | | // only one '+'/'-' char, so could return failure directly | 298 | 256 | if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 256 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 256]
|
| 299 | 0 | *result = PARSE_FAILURE; | 300 | 0 | return 0; | 301 | 0 | } | 302 | 1.06k | } | 303 | | | 304 | | // This is the fast path where the string cannot overflow. | 305 | 1.06k | if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 1.06k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 635, False: 433]
|
| 306 | 635 | val = string_to_int_no_overflow<UnsignedT>(s + i, len - i, result); | 307 | 635 | return static_cast<T>(negative ? -val : val); Branch (307:31): [True: 99, False: 536]
| 308 | 635 | } | 309 | | | 310 | 433 | const T max_div_10 = max_val / 10; | 311 | 433 | const T max_mod_10 = max_val % 10; | 312 | | | 313 | 433 | int first = i; | 314 | 4.66k | for (; i < len; ++i) { Branch (314:12): [True: 4.63k, False: 27]
| 315 | 4.63k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 8.99k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 4.35k, False: 288]
Branch (35:42): [True: 4.35k, False: 288]
Branch (35:42): [True: 4.35k, False: 0]
|
| 316 | 4.35k | T digit = s[i] - '0'; | 317 | | // This is a tricky check to see if adding this digit will cause an overflow. | 318 | 4.35k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 4.35k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 118, False: 4.23k]
|
| 319 | 118 | *result = PARSE_OVERFLOW; | 320 | 118 | return negative ? -max_val : max_val; Branch (320:24): [True: 56, False: 62]
| 321 | 118 | } | 322 | 4.23k | val = val * 10 + digit; | 323 | 4.23k | } else { | 324 | 288 | if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 456 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 84]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 204, False: 84]
|
Branch (324:17): [True: 204, False: 84]
| 325 | 288 | !is_float_suffix(s + i, len - i))))) { | 326 | | // Reject the string because either the first char was not a digit, | 327 | | // or the remaining chars are not all whitespace | 328 | 204 | *result = PARSE_FAILURE; | 329 | 204 | return 0; | 330 | 204 | } | 331 | | // Returning here is slightly faster than breaking the loop. | 332 | 84 | *result = PARSE_SUCCESS; | 333 | 84 | return static_cast<T>(negative ? -val : val); Branch (333:35): [True: 42, False: 42]
| 334 | 288 | } | 335 | 4.63k | } | 336 | 27 | *result = PARSE_SUCCESS; | 337 | 27 | return static_cast<T>(negative ? -val : val); Branch (337:27): [True: 10, False: 17]
| 338 | 433 | } |
Unexecuted instantiation: _ZN5doris12StringParser22string_to_int_internalIN4wide7integerILm256EiEEEET_PKciPNS0_11ParseResultE Unexecuted instantiation: _ZN5doris12StringParser22string_to_int_internalIoEET_PKciPNS0_11ParseResultE _ZN5doris12StringParser22string_to_int_internalImEET_PKciPNS0_11ParseResultE Line | Count | Source | 279 | 20 | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 280 | 20 | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 20 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 20]
|
| 281 | 0 | *result = PARSE_FAILURE; | 282 | 0 | return 0; | 283 | 0 | } | 284 | | | 285 | 20 | typedef typename std::make_unsigned<T>::type UnsignedT; | 286 | 20 | UnsignedT val = 0; | 287 | 20 | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 288 | 20 | bool negative = false; | 289 | 20 | int i = 0; | 290 | 20 | switch (*s) { Branch (290:13): [True: 20, False: 0]
| 291 | 0 | case '-': Branch (291:5): [True: 0, False: 20]
| 292 | 0 | negative = true; | 293 | 0 | max_val += 1; | 294 | 0 | [[fallthrough]]; | 295 | 0 | case '+': Branch (295:5): [True: 0, False: 20]
| 296 | 0 | ++i; | 297 | | // only one '+'/'-' char, so could return failure directly | 298 | 0 | if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| 299 | 0 | *result = PARSE_FAILURE; | 300 | 0 | return 0; | 301 | 0 | } | 302 | 20 | } | 303 | | | 304 | | // This is the fast path where the string cannot overflow. | 305 | 20 | if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 20 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 20, False: 0]
|
| 306 | 20 | val = string_to_int_no_overflow<UnsignedT>(s + i, len - i, result); | 307 | 20 | return static_cast<T>(negative ? -val : val); Branch (307:31): [True: 0, False: 20]
| 308 | 20 | } | 309 | | | 310 | 0 | const T max_div_10 = max_val / 10; | 311 | 0 | const T max_mod_10 = max_val % 10; | 312 | |
| 313 | 0 | int first = i; | 314 | 0 | for (; i < len; ++i) { Branch (314:12): [True: 0, False: 0]
| 315 | 0 | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
|
| 316 | 0 | T digit = s[i] - '0'; | 317 | | // This is a tricky check to see if adding this digit will cause an overflow. | 318 | 0 | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| 319 | 0 | *result = PARSE_OVERFLOW; | 320 | 0 | return negative ? -max_val : max_val; Branch (320:24): [True: 0, False: 0]
| 321 | 0 | } | 322 | 0 | val = val * 10 + digit; | 323 | 0 | } else { | 324 | 0 | if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
|
Branch (324:17): [True: 0, False: 0]
| 325 | 0 | !is_float_suffix(s + i, len - i))))) { | 326 | | // Reject the string because either the first char was not a digit, | 327 | | // or the remaining chars are not all whitespace | 328 | 0 | *result = PARSE_FAILURE; | 329 | 0 | return 0; | 330 | 0 | } | 331 | | // Returning here is slightly faster than breaking the loop. | 332 | 0 | *result = PARSE_SUCCESS; | 333 | 0 | return static_cast<T>(negative ? -val : val); Branch (333:35): [True: 0, False: 0]
| 334 | 0 | } | 335 | 0 | } | 336 | 0 | *result = PARSE_SUCCESS; | 337 | 0 | return static_cast<T>(negative ? -val : val); Branch (337:27): [True: 0, False: 0]
| 338 | 0 | } |
Unexecuted instantiation: _ZN5doris12StringParser22string_to_int_internalIjEET_PKciPNS0_11ParseResultE _ZN5doris12StringParser22string_to_int_internalIhEET_PKciPNS0_11ParseResultE Line | Count | Source | 279 | 93 | T StringParser::string_to_int_internal(const char* __restrict s, int len, ParseResult* result) { | 280 | 93 | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 93 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 93]
|
| 281 | 0 | *result = PARSE_FAILURE; | 282 | 0 | return 0; | 283 | 0 | } | 284 | | | 285 | 93 | typedef typename std::make_unsigned<T>::type UnsignedT; | 286 | 93 | UnsignedT val = 0; | 287 | 93 | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 288 | 93 | bool negative = false; | 289 | 93 | int i = 0; | 290 | 93 | switch (*s) { Branch (290:13): [True: 85, False: 8]
| 291 | 8 | case '-': Branch (291:5): [True: 8, False: 85]
| 292 | 8 | negative = true; | 293 | 8 | max_val += 1; | 294 | 8 | [[fallthrough]]; | 295 | 8 | case '+': Branch (295:5): [True: 0, False: 93]
| 296 | 8 | ++i; | 297 | | // only one '+'/'-' char, so could return failure directly | 298 | 8 | if (UNLIKELY(len == 1)) {Line | Count | Source | 36 | 8 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 8]
|
| 299 | 0 | *result = PARSE_FAILURE; | 300 | 0 | return 0; | 301 | 0 | } | 302 | 93 | } | 303 | | | 304 | | // This is the fast path where the string cannot overflow. | 305 | 93 | if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<T>())) {Line | Count | Source | 35 | 93 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 53, False: 40]
|
| 306 | 53 | val = string_to_int_no_overflow<UnsignedT>(s + i, len - i, result); | 307 | 53 | return static_cast<T>(negative ? -val : val); Branch (307:31): [True: 8, False: 45]
| 308 | 53 | } | 309 | | | 310 | 40 | const T max_div_10 = max_val / 10; | 311 | 40 | const T max_mod_10 = max_val % 10; | 312 | | | 313 | 40 | int first = i; | 314 | 40 | for (; i < len; ++i) { Branch (314:12): [True: 40, False: 0]
| 315 | 40 | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 76 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 40]
Branch (35:42): [True: 36, False: 4]
Branch (35:42): [True: 0, False: 36]
|
| 316 | 0 | T digit = s[i] - '0'; | 317 | | // This is a tricky check to see if adding this digit will cause an overflow. | 318 | 0 | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| 319 | 0 | *result = PARSE_OVERFLOW; | 320 | 0 | return negative ? -max_val : max_val; Branch (320:24): [True: 0, False: 0]
| 321 | 0 | } | 322 | 0 | val = val * 10 + digit; | 323 | 40 | } else { | 324 | 40 | if ((UNLIKELY(i == first || (!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 40 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 40, False: 0]
|
Branch (324:17): [True: 40, False: 0]
| 325 | 40 | !is_float_suffix(s + i, len - i))))) { | 326 | | // Reject the string because either the first char was not a digit, | 327 | | // or the remaining chars are not all whitespace | 328 | 40 | *result = PARSE_FAILURE; | 329 | 40 | return 0; | 330 | 40 | } | 331 | | // Returning here is slightly faster than breaking the loop. | 332 | 0 | *result = PARSE_SUCCESS; | 333 | 0 | return static_cast<T>(negative ? -val : val); Branch (333:35): [True: 0, False: 0]
| 334 | 40 | } | 335 | 40 | } | 336 | 0 | *result = PARSE_SUCCESS; | 337 | 0 | return static_cast<T>(negative ? -val : val); Branch (337:27): [True: 0, False: 0]
| 338 | 40 | } |
Unexecuted instantiation: _ZN5doris12StringParser22string_to_int_internalItEET_PKciPNS0_11ParseResultE |
339 | | |
340 | | template <typename T> |
341 | | T StringParser::string_to_unsigned_int_internal(const char* __restrict s, int len, |
342 | 2.66k | ParseResult* result) { |
343 | 2.66k | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 665 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 665]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 665 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 665]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 665 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 665]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 665 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 665]
|
|
344 | 0 | *result = PARSE_FAILURE; |
345 | 0 | return 0; |
346 | 0 | } |
347 | | |
348 | 2.66k | T val = 0; |
349 | 2.66k | T max_val = std::numeric_limits<T>::max(); |
350 | 2.66k | int i = 0; |
351 | | |
352 | 2.66k | typedef typename std::make_signed<T>::type signedT; |
353 | | // This is the fast path where the string cannot overflow. |
354 | 2.66k | if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<signedT>())) {Line | Count | Source | 35 | 665 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 16, False: 649]
|
| if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<signedT>())) {Line | Count | Source | 35 | 665 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 31, False: 634]
|
| if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<signedT>())) {Line | Count | Source | 35 | 665 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 392, False: 273]
|
| if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<signedT>())) {Line | Count | Source | 35 | 665 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 440, False: 225]
|
|
355 | 879 | val = string_to_int_no_overflow<T>(s + i, len - i, result); |
356 | 879 | return val; |
357 | 879 | } |
358 | | |
359 | 1.78k | const T max_div_10 = max_val / 10; |
360 | 1.78k | const T max_mod_10 = max_val % 10; |
361 | | |
362 | 1.78k | int first = i; |
363 | 6.54k | for (; i < len; ++i) { Branch (363:12): [True: 1.18k, False: 21]
Branch (363:12): [True: 1.46k, False: 14]
Branch (363:12): [True: 1.59k, False: 7]
Branch (363:12): [True: 2.26k, False: 7]
|
364 | 6.49k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 1.79k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 609, False: 572]
Branch (35:42): [True: 609, False: 572]
Branch (35:42): [True: 609, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 2.35k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 896, False: 564]
Branch (35:42): [True: 896, False: 564]
Branch (35:42): [True: 896, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 2.98k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.38k, False: 210]
Branch (35:42): [True: 1.38k, False: 210]
Branch (35:42): [True: 1.38k, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 4.36k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 2.10k, False: 162]
Branch (35:42): [True: 2.10k, False: 162]
Branch (35:42): [True: 2.10k, False: 0]
|
|
365 | 4.99k | T digit = s[i] - '0'; |
366 | | // This is a tricky check to see if adding this digit will cause an overflow. |
367 | 4.99k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 609 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 56, False: 553]
|
| if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 896 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 56, False: 840]
|
| if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 1.38k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 56, False: 1.33k]
|
| if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 2.10k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 56, False: 2.04k]
|
|
368 | 224 | *result = PARSE_OVERFLOW; |
369 | 224 | return max_val; |
370 | 224 | } |
371 | 4.76k | val = val * 10 + digit; |
372 | 4.76k | } else { |
373 | 1.50k | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 698 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 446, False: 126]
Branch (36:44): [True: 0, False: 126]
|
| if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 690 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 438, False: 126]
Branch (36:44): [True: 0, False: 126]
|
| if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 294 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 126, False: 84]
Branch (36:44): [True: 0, False: 84]
|
| if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 204 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 120, False: 42]
Branch (36:44): [True: 0, False: 42]
|
Branch (373:17): [True: 446, False: 126]
Branch (373:17): [True: 438, False: 126]
Branch (373:17): [True: 126, False: 84]
Branch (373:17): [True: 120, False: 42]
|
374 | | // Reject the string because either the first char was not a digit, |
375 | | // or the remaining chars are not all whitespace |
376 | 1.13k | *result = PARSE_FAILURE; |
377 | 1.13k | return 0; |
378 | 1.13k | } |
379 | | // Returning here is slightly faster than breaking the loop. |
380 | 378 | *result = PARSE_SUCCESS; |
381 | 378 | return val; |
382 | 1.50k | } |
383 | 6.49k | } |
384 | 49 | *result = PARSE_SUCCESS; |
385 | 49 | return val; |
386 | 1.78k | } _ZN5doris12StringParser31string_to_unsigned_int_internalIhEET_PKciPNS0_11ParseResultE Line | Count | Source | 342 | 665 | ParseResult* result) { | 343 | 665 | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 665 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 665]
|
| 344 | 0 | *result = PARSE_FAILURE; | 345 | 0 | return 0; | 346 | 0 | } | 347 | | | 348 | 665 | T val = 0; | 349 | 665 | T max_val = std::numeric_limits<T>::max(); | 350 | 665 | int i = 0; | 351 | | | 352 | 665 | typedef typename std::make_signed<T>::type signedT; | 353 | | // This is the fast path where the string cannot overflow. | 354 | 665 | if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<signedT>())) {Line | Count | Source | 35 | 665 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 16, False: 649]
|
| 355 | 16 | val = string_to_int_no_overflow<T>(s + i, len - i, result); | 356 | 16 | return val; | 357 | 16 | } | 358 | | | 359 | 649 | const T max_div_10 = max_val / 10; | 360 | 649 | const T max_mod_10 = max_val % 10; | 361 | | | 362 | 649 | int first = i; | 363 | 1.20k | for (; i < len; ++i) { Branch (363:12): [True: 1.18k, False: 21]
| 364 | 1.18k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 1.79k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 609, False: 572]
Branch (35:42): [True: 609, False: 572]
Branch (35:42): [True: 609, False: 0]
|
| 365 | 609 | T digit = s[i] - '0'; | 366 | | // This is a tricky check to see if adding this digit will cause an overflow. | 367 | 609 | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 609 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 56, False: 553]
|
| 368 | 56 | *result = PARSE_OVERFLOW; | 369 | 56 | return max_val; | 370 | 56 | } | 371 | 553 | val = val * 10 + digit; | 372 | 572 | } else { | 373 | 572 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 698 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 446, False: 126]
Branch (36:44): [True: 0, False: 126]
|
Branch (373:17): [True: 446, False: 126]
| 374 | | // Reject the string because either the first char was not a digit, | 375 | | // or the remaining chars are not all whitespace | 376 | 446 | *result = PARSE_FAILURE; | 377 | 446 | return 0; | 378 | 446 | } | 379 | | // Returning here is slightly faster than breaking the loop. | 380 | 126 | *result = PARSE_SUCCESS; | 381 | 126 | return val; | 382 | 572 | } | 383 | 1.18k | } | 384 | 21 | *result = PARSE_SUCCESS; | 385 | 21 | return val; | 386 | 649 | } |
_ZN5doris12StringParser31string_to_unsigned_int_internalItEET_PKciPNS0_11ParseResultE Line | Count | Source | 342 | 665 | ParseResult* result) { | 343 | 665 | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 665 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 665]
|
| 344 | 0 | *result = PARSE_FAILURE; | 345 | 0 | return 0; | 346 | 0 | } | 347 | | | 348 | 665 | T val = 0; | 349 | 665 | T max_val = std::numeric_limits<T>::max(); | 350 | 665 | int i = 0; | 351 | | | 352 | 665 | typedef typename std::make_signed<T>::type signedT; | 353 | | // This is the fast path where the string cannot overflow. | 354 | 665 | if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<signedT>())) {Line | Count | Source | 35 | 665 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 31, False: 634]
|
| 355 | 31 | val = string_to_int_no_overflow<T>(s + i, len - i, result); | 356 | 31 | return val; | 357 | 31 | } | 358 | | | 359 | 634 | const T max_div_10 = max_val / 10; | 360 | 634 | const T max_mod_10 = max_val % 10; | 361 | | | 362 | 634 | int first = i; | 363 | 1.47k | for (; i < len; ++i) { Branch (363:12): [True: 1.46k, False: 14]
| 364 | 1.46k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 2.35k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 896, False: 564]
Branch (35:42): [True: 896, False: 564]
Branch (35:42): [True: 896, False: 0]
|
| 365 | 896 | T digit = s[i] - '0'; | 366 | | // This is a tricky check to see if adding this digit will cause an overflow. | 367 | 896 | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 896 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 56, False: 840]
|
| 368 | 56 | *result = PARSE_OVERFLOW; | 369 | 56 | return max_val; | 370 | 56 | } | 371 | 840 | val = val * 10 + digit; | 372 | 840 | } else { | 373 | 564 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 690 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 438, False: 126]
Branch (36:44): [True: 0, False: 126]
|
Branch (373:17): [True: 438, False: 126]
| 374 | | // Reject the string because either the first char was not a digit, | 375 | | // or the remaining chars are not all whitespace | 376 | 438 | *result = PARSE_FAILURE; | 377 | 438 | return 0; | 378 | 438 | } | 379 | | // Returning here is slightly faster than breaking the loop. | 380 | 126 | *result = PARSE_SUCCESS; | 381 | 126 | return val; | 382 | 564 | } | 383 | 1.46k | } | 384 | 14 | *result = PARSE_SUCCESS; | 385 | 14 | return val; | 386 | 634 | } |
_ZN5doris12StringParser31string_to_unsigned_int_internalIjEET_PKciPNS0_11ParseResultE Line | Count | Source | 342 | 665 | ParseResult* result) { | 343 | 665 | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 665 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 665]
|
| 344 | 0 | *result = PARSE_FAILURE; | 345 | 0 | return 0; | 346 | 0 | } | 347 | | | 348 | 665 | T val = 0; | 349 | 665 | T max_val = std::numeric_limits<T>::max(); | 350 | 665 | int i = 0; | 351 | | | 352 | 665 | typedef typename std::make_signed<T>::type signedT; | 353 | | // This is the fast path where the string cannot overflow. | 354 | 665 | if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<signedT>())) {Line | Count | Source | 35 | 665 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 392, False: 273]
|
| 355 | 392 | val = string_to_int_no_overflow<T>(s + i, len - i, result); | 356 | 392 | return val; | 357 | 392 | } | 358 | | | 359 | 273 | const T max_div_10 = max_val / 10; | 360 | 273 | const T max_mod_10 = max_val % 10; | 361 | | | 362 | 273 | int first = i; | 363 | 1.60k | for (; i < len; ++i) { Branch (363:12): [True: 1.59k, False: 7]
| 364 | 1.59k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 2.98k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.38k, False: 210]
Branch (35:42): [True: 1.38k, False: 210]
Branch (35:42): [True: 1.38k, False: 0]
|
| 365 | 1.38k | T digit = s[i] - '0'; | 366 | | // This is a tricky check to see if adding this digit will cause an overflow. | 367 | 1.38k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 1.38k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 56, False: 1.33k]
|
| 368 | 56 | *result = PARSE_OVERFLOW; | 369 | 56 | return max_val; | 370 | 56 | } | 371 | 1.33k | val = val * 10 + digit; | 372 | 1.33k | } else { | 373 | 210 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 294 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 126, False: 84]
Branch (36:44): [True: 0, False: 84]
|
Branch (373:17): [True: 126, False: 84]
| 374 | | // Reject the string because either the first char was not a digit, | 375 | | // or the remaining chars are not all whitespace | 376 | 126 | *result = PARSE_FAILURE; | 377 | 126 | return 0; | 378 | 126 | } | 379 | | // Returning here is slightly faster than breaking the loop. | 380 | 84 | *result = PARSE_SUCCESS; | 381 | 84 | return val; | 382 | 210 | } | 383 | 1.59k | } | 384 | 7 | *result = PARSE_SUCCESS; | 385 | 7 | return val; | 386 | 273 | } |
_ZN5doris12StringParser31string_to_unsigned_int_internalImEET_PKciPNS0_11ParseResultE Line | Count | Source | 342 | 665 | ParseResult* result) { | 343 | 665 | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 665 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 665]
|
| 344 | 0 | *result = PARSE_FAILURE; | 345 | 0 | return 0; | 346 | 0 | } | 347 | | | 348 | 665 | T val = 0; | 349 | 665 | T max_val = std::numeric_limits<T>::max(); | 350 | 665 | int i = 0; | 351 | | | 352 | 665 | typedef typename std::make_signed<T>::type signedT; | 353 | | // This is the fast path where the string cannot overflow. | 354 | 665 | if (LIKELY(len - i < vectorized::NumberTraits::max_ascii_len<signedT>())) {Line | Count | Source | 35 | 665 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 440, False: 225]
|
| 355 | 440 | val = string_to_int_no_overflow<T>(s + i, len - i, result); | 356 | 440 | return val; | 357 | 440 | } | 358 | | | 359 | 225 | const T max_div_10 = max_val / 10; | 360 | 225 | const T max_mod_10 = max_val % 10; | 361 | | | 362 | 225 | int first = i; | 363 | 2.26k | for (; i < len; ++i) { Branch (363:12): [True: 2.26k, False: 7]
| 364 | 2.26k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 4.36k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 2.10k, False: 162]
Branch (35:42): [True: 2.10k, False: 162]
Branch (35:42): [True: 2.10k, False: 0]
|
| 365 | 2.10k | T digit = s[i] - '0'; | 366 | | // This is a tricky check to see if adding this digit will cause an overflow. | 367 | 2.10k | if (UNLIKELY(val > (max_div_10 - (digit > max_mod_10)))) {Line | Count | Source | 36 | 2.10k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 56, False: 2.04k]
|
| 368 | 56 | *result = PARSE_OVERFLOW; | 369 | 56 | return max_val; | 370 | 56 | } | 371 | 2.04k | val = val * 10 + digit; | 372 | 2.04k | } else { | 373 | 162 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 204 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 120, False: 42]
Branch (36:44): [True: 0, False: 42]
|
Branch (373:17): [True: 120, False: 42]
| 374 | | // Reject the string because either the first char was not a digit, | 375 | | // or the remaining chars are not all whitespace | 376 | 120 | *result = PARSE_FAILURE; | 377 | 120 | return 0; | 378 | 120 | } | 379 | | // Returning here is slightly faster than breaking the loop. | 380 | 42 | *result = PARSE_SUCCESS; | 381 | 42 | return val; | 382 | 162 | } | 383 | 2.26k | } | 384 | 7 | *result = PARSE_SUCCESS; | 385 | 7 | return val; | 386 | 225 | } |
|
387 | | |
388 | | template <typename T> |
389 | | T StringParser::string_to_int_internal(const char* __restrict s, int len, int base, |
390 | 53.6k | ParseResult* result) { |
391 | 53.6k | typedef typename std::make_unsigned<T>::type UnsignedT; |
392 | 53.6k | UnsignedT val = 0; |
393 | 53.6k | UnsignedT max_val = StringParser::numeric_limits<T>(false); |
394 | 53.6k | bool negative = false; |
395 | 53.6k | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 51.0k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 51.0k]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 924 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 924]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 833 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 833]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 833 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 833]
|
| if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1]
|
|
396 | 0 | *result = PARSE_FAILURE; |
397 | 0 | return 0; |
398 | 0 | } |
399 | 53.6k | int i = 0; |
400 | 53.6k | switch (*s) { Branch (400:13): [True: 37.1k, False: 13.8k]
Branch (400:13): [True: 672, False: 252]
Branch (400:13): [True: 581, False: 252]
Branch (400:13): [True: 581, False: 252]
Branch (400:13): [True: 1, False: 0]
|
401 | 14.3k | case '-': Branch (401:5): [True: 13.7k, False: 37.2k]
Branch (401:5): [True: 203, False: 721]
Branch (401:5): [True: 154, False: 679]
Branch (401:5): [True: 203, False: 630]
Branch (401:5): [True: 0, False: 1]
|
402 | 14.3k | negative = true; |
403 | 14.3k | max_val = StringParser::numeric_limits<T>(false) + 1; |
404 | 14.3k | [[fallthrough]]; |
405 | 14.6k | case '+': Branch (405:5): [True: 98, False: 50.9k]
Branch (405:5): [True: 49, False: 875]
Branch (405:5): [True: 98, False: 735]
Branch (405:5): [True: 49, False: 784]
Branch (405:5): [True: 0, False: 1]
|
406 | 14.6k | i = 1; |
407 | 53.6k | } |
408 | | |
409 | 53.6k | const T max_div_base = max_val / base; |
410 | 53.6k | const T max_mod_base = max_val % base; |
411 | | |
412 | 53.6k | int first = i; |
413 | 120k | for (; i < len; ++i) { Branch (413:12): [True: 107k, False: 1.89k]
Branch (413:12): [True: 2.54k, False: 56]
Branch (413:12): [True: 3.50k, False: 49]
Branch (413:12): [True: 5.69k, False: 49]
Branch (413:12): [True: 2, False: 1]
|
414 | 118k | T digit; |
415 | 118k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 179k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 72.1k, False: 34.8k]
Branch (35:42): [True: 72.7k, False: 34.2k]
Branch (35:42): [True: 72.1k, False: 637]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 4.32k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.68k, False: 854]
Branch (35:42): [True: 1.78k, False: 756]
Branch (35:42): [True: 1.68k, False: 98]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 6.34k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 2.83k, False: 672]
Branch (35:42): [True: 2.83k, False: 672]
Branch (35:42): [True: 2.83k, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 10.7k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 5.01k, False: 672]
Branch (35:42): [True: 5.01k, False: 672]
Branch (35:42): [True: 5.01k, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 4 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 2]
Branch (35:42): [True: 2, False: 0]
Branch (35:42): [True: 0, False: 2]
|
|
416 | 81.6k | digit = s[i] - '0'; |
417 | 81.6k | } else if (s[i] >= 'a' && s[i] <= 'z') { Branch (417:20): [True: 539, False: 34.3k]
Branch (417:35): [True: 539, False: 0]
Branch (417:20): [True: 98, False: 756]
Branch (417:35): [True: 98, False: 0]
Branch (417:20): [True: 0, False: 672]
Branch (417:35): [True: 0, False: 0]
Branch (417:20): [True: 0, False: 672]
Branch (417:35): [True: 0, False: 0]
Branch (417:20): [True: 2, False: 0]
Branch (417:35): [True: 2, False: 0]
|
418 | 639 | digit = (s[i] - 'a' + 10); |
419 | 36.4k | } else if (s[i] >= 'A' && s[i] <= 'Z') { Branch (419:20): [True: 98, False: 34.2k]
Branch (419:35): [True: 98, False: 0]
Branch (419:20): [True: 0, False: 756]
Branch (419:35): [True: 0, False: 0]
Branch (419:20): [True: 0, False: 672]
Branch (419:35): [True: 0, False: 0]
Branch (419:20): [True: 0, False: 672]
Branch (419:35): [True: 0, False: 0]
Branch (419:20): [True: 0, False: 0]
Branch (419:35): [True: 0, False: 0]
|
420 | 98 | digit = (s[i] - 'A' + 10); |
421 | 36.3k | } else { |
422 | 36.3k | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 45.7k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 22.7k, False: 11.5k]
Branch (36:44): [True: 161, False: 11.3k]
|
| if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 1.09k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 420, False: 336]
Branch (36:44): [True: 0, False: 336]
|
| if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 966 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 378, False: 294]
Branch (36:44): [True: 0, False: 294]
|
| if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 966 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 378, False: 294]
Branch (36:44): [True: 0, False: 294]
|
| if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
|
Branch (422:17): [True: 22.8k, False: 11.3k]
Branch (422:17): [True: 420, False: 336]
Branch (422:17): [True: 378, False: 294]
Branch (422:17): [True: 378, False: 294]
Branch (422:17): [True: 0, False: 0]
|
423 | | // Reject the string because either the first char was not an alpha/digit, |
424 | | // or the remaining chars are not all whitespace |
425 | 24.0k | *result = PARSE_FAILURE; |
426 | 24.0k | return 0; |
427 | 24.0k | } |
428 | | // skip trailing whitespace. |
429 | 12.2k | break; |
430 | 36.3k | } |
431 | | |
432 | | // Bail, if we encounter a digit that is not available in base. |
433 | 82.4k | if (digit >= base) { Branch (433:13): [True: 392, False: 72.4k]
Branch (433:13): [True: 0, False: 1.78k]
Branch (433:13): [True: 0, False: 2.83k]
Branch (433:13): [True: 0, False: 5.01k]
Branch (433:13): [True: 0, False: 2]
|
434 | 392 | break; |
435 | 392 | } |
436 | | |
437 | | // This is a tricky check to see if adding this digit will cause an overflow. |
438 | 82.0k | if (UNLIKELY(val > (max_div_base - (digit > max_mod_base)))) {Line | Count | Source | 36 | 72.4k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 14.5k, False: 57.8k]
|
| if (UNLIKELY(val > (max_div_base - (digit > max_mod_base)))) {Line | Count | Source | 36 | 1.78k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 112, False: 1.67k]
|
| if (UNLIKELY(val > (max_div_base - (digit > max_mod_base)))) {Line | Count | Source | 36 | 2.83k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 112, False: 2.72k]
|
| if (UNLIKELY(val > (max_div_base - (digit > max_mod_base)))) {Line | Count | Source | 36 | 5.01k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 112, False: 4.90k]
|
| if (UNLIKELY(val > (max_div_base - (digit > max_mod_base)))) {Line | Count | Source | 36 | 2 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 2]
|
|
439 | 14.8k | *result = PARSE_OVERFLOW; |
440 | 14.8k | return static_cast<T>(negative ? -max_val : max_val); Branch (440:35): [True: 7.22k, False: 7.28k]
Branch (440:35): [True: 56, False: 56]
Branch (440:35): [True: 56, False: 56]
Branch (440:35): [True: 56, False: 56]
Branch (440:35): [True: 0, False: 0]
|
441 | 14.8k | } |
442 | 67.2k | val = val * base + digit; |
443 | 67.2k | } |
444 | 14.7k | *result = PARSE_SUCCESS; |
445 | 14.7k | return static_cast<T>(negative ? -val : val); Branch (445:27): [True: 6.46k, False: 7.15k]
Branch (445:27): [True: 147, False: 245]
Branch (445:27): [True: 98, False: 245]
Branch (445:27): [True: 147, False: 196]
Branch (445:27): [True: 0, False: 1]
|
446 | 53.6k | } _ZN5doris12StringParser22string_to_int_internalIaEET_PKciiPNS0_11ParseResultE Line | Count | Source | 390 | 51.0k | ParseResult* result) { | 391 | 51.0k | typedef typename std::make_unsigned<T>::type UnsignedT; | 392 | 51.0k | UnsignedT val = 0; | 393 | 51.0k | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 394 | 51.0k | bool negative = false; | 395 | 51.0k | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 51.0k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 51.0k]
|
| 396 | 0 | *result = PARSE_FAILURE; | 397 | 0 | return 0; | 398 | 0 | } | 399 | 51.0k | int i = 0; | 400 | 51.0k | switch (*s) { Branch (400:13): [True: 37.1k, False: 13.8k]
| 401 | 13.7k | case '-': Branch (401:5): [True: 13.7k, False: 37.2k]
| 402 | 13.7k | negative = true; | 403 | 13.7k | max_val = StringParser::numeric_limits<T>(false) + 1; | 404 | 13.7k | [[fallthrough]]; | 405 | 13.8k | case '+': Branch (405:5): [True: 98, False: 50.9k]
| 406 | 13.8k | i = 1; | 407 | 51.0k | } | 408 | | | 409 | 51.0k | const T max_div_base = max_val / base; | 410 | 51.0k | const T max_mod_base = max_val % base; | 411 | | | 412 | 51.0k | int first = i; | 413 | 108k | for (; i < len; ++i) { Branch (413:12): [True: 107k, False: 1.89k]
| 414 | 107k | T digit; | 415 | 107k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 179k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 72.1k, False: 34.8k]
Branch (35:42): [True: 72.7k, False: 34.2k]
Branch (35:42): [True: 72.1k, False: 637]
|
| 416 | 72.1k | digit = s[i] - '0'; | 417 | 72.1k | } else if (s[i] >= 'a' && s[i] <= 'z') { Branch (417:20): [True: 539, False: 34.3k]
Branch (417:35): [True: 539, False: 0]
| 418 | 539 | digit = (s[i] - 'a' + 10); | 419 | 34.3k | } else if (s[i] >= 'A' && s[i] <= 'Z') { Branch (419:20): [True: 98, False: 34.2k]
Branch (419:35): [True: 98, False: 0]
| 420 | 98 | digit = (s[i] - 'A' + 10); | 421 | 34.2k | } else { | 422 | 34.2k | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 45.7k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 22.7k, False: 11.5k]
Branch (36:44): [True: 161, False: 11.3k]
|
Branch (422:17): [True: 22.8k, False: 11.3k]
| 423 | | // Reject the string because either the first char was not an alpha/digit, | 424 | | // or the remaining chars are not all whitespace | 425 | 22.8k | *result = PARSE_FAILURE; | 426 | 22.8k | return 0; | 427 | 22.8k | } | 428 | | // skip trailing whitespace. | 429 | 11.3k | break; | 430 | 34.2k | } | 431 | | | 432 | | // Bail, if we encounter a digit that is not available in base. | 433 | 72.7k | if (digit >= base) { Branch (433:13): [True: 392, False: 72.4k]
| 434 | 392 | break; | 435 | 392 | } | 436 | | | 437 | | // This is a tricky check to see if adding this digit will cause an overflow. | 438 | 72.4k | if (UNLIKELY(val > (max_div_base - (digit > max_mod_base)))) {Line | Count | Source | 36 | 72.4k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 14.5k, False: 57.8k]
|
| 439 | 14.5k | *result = PARSE_OVERFLOW; | 440 | 14.5k | return static_cast<T>(negative ? -max_val : max_val); Branch (440:35): [True: 7.22k, False: 7.28k]
| 441 | 14.5k | } | 442 | 57.8k | val = val * base + digit; | 443 | 57.8k | } | 444 | 13.6k | *result = PARSE_SUCCESS; | 445 | 13.6k | return static_cast<T>(negative ? -val : val); Branch (445:27): [True: 6.46k, False: 7.15k]
| 446 | 51.0k | } |
_ZN5doris12StringParser22string_to_int_internalIsEET_PKciiPNS0_11ParseResultE Line | Count | Source | 390 | 924 | ParseResult* result) { | 391 | 924 | typedef typename std::make_unsigned<T>::type UnsignedT; | 392 | 924 | UnsignedT val = 0; | 393 | 924 | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 394 | 924 | bool negative = false; | 395 | 924 | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 924 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 924]
|
| 396 | 0 | *result = PARSE_FAILURE; | 397 | 0 | return 0; | 398 | 0 | } | 399 | 924 | int i = 0; | 400 | 924 | switch (*s) { Branch (400:13): [True: 672, False: 252]
| 401 | 203 | case '-': Branch (401:5): [True: 203, False: 721]
| 402 | 203 | negative = true; | 403 | 203 | max_val = StringParser::numeric_limits<T>(false) + 1; | 404 | 203 | [[fallthrough]]; | 405 | 252 | case '+': Branch (405:5): [True: 49, False: 875]
| 406 | 252 | i = 1; | 407 | 924 | } | 408 | | | 409 | 924 | const T max_div_base = max_val / base; | 410 | 924 | const T max_mod_base = max_val % base; | 411 | | | 412 | 924 | int first = i; | 413 | 2.59k | for (; i < len; ++i) { Branch (413:12): [True: 2.54k, False: 56]
| 414 | 2.54k | T digit; | 415 | 2.54k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 4.32k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.68k, False: 854]
Branch (35:42): [True: 1.78k, False: 756]
Branch (35:42): [True: 1.68k, False: 98]
|
| 416 | 1.68k | digit = s[i] - '0'; | 417 | 1.68k | } else if (s[i] >= 'a' && s[i] <= 'z') { Branch (417:20): [True: 98, False: 756]
Branch (417:35): [True: 98, False: 0]
| 418 | 98 | digit = (s[i] - 'a' + 10); | 419 | 756 | } else if (s[i] >= 'A' && s[i] <= 'Z') { Branch (419:20): [True: 0, False: 756]
Branch (419:35): [True: 0, False: 0]
| 420 | 0 | digit = (s[i] - 'A' + 10); | 421 | 756 | } else { | 422 | 756 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 1.09k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 420, False: 336]
Branch (36:44): [True: 0, False: 336]
|
Branch (422:17): [True: 420, False: 336]
| 423 | | // Reject the string because either the first char was not an alpha/digit, | 424 | | // or the remaining chars are not all whitespace | 425 | 420 | *result = PARSE_FAILURE; | 426 | 420 | return 0; | 427 | 420 | } | 428 | | // skip trailing whitespace. | 429 | 336 | break; | 430 | 756 | } | 431 | | | 432 | | // Bail, if we encounter a digit that is not available in base. | 433 | 1.78k | if (digit >= base) { Branch (433:13): [True: 0, False: 1.78k]
| 434 | 0 | break; | 435 | 0 | } | 436 | | | 437 | | // This is a tricky check to see if adding this digit will cause an overflow. | 438 | 1.78k | if (UNLIKELY(val > (max_div_base - (digit > max_mod_base)))) {Line | Count | Source | 36 | 1.78k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 112, False: 1.67k]
|
| 439 | 112 | *result = PARSE_OVERFLOW; | 440 | 112 | return static_cast<T>(negative ? -max_val : max_val); Branch (440:35): [True: 56, False: 56]
| 441 | 112 | } | 442 | 1.67k | val = val * base + digit; | 443 | 1.67k | } | 444 | 392 | *result = PARSE_SUCCESS; | 445 | 392 | return static_cast<T>(negative ? -val : val); Branch (445:27): [True: 147, False: 245]
| 446 | 924 | } |
_ZN5doris12StringParser22string_to_int_internalIiEET_PKciiPNS0_11ParseResultE Line | Count | Source | 390 | 833 | ParseResult* result) { | 391 | 833 | typedef typename std::make_unsigned<T>::type UnsignedT; | 392 | 833 | UnsignedT val = 0; | 393 | 833 | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 394 | 833 | bool negative = false; | 395 | 833 | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 833 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 833]
|
| 396 | 0 | *result = PARSE_FAILURE; | 397 | 0 | return 0; | 398 | 0 | } | 399 | 833 | int i = 0; | 400 | 833 | switch (*s) { Branch (400:13): [True: 581, False: 252]
| 401 | 154 | case '-': Branch (401:5): [True: 154, False: 679]
| 402 | 154 | negative = true; | 403 | 154 | max_val = StringParser::numeric_limits<T>(false) + 1; | 404 | 154 | [[fallthrough]]; | 405 | 252 | case '+': Branch (405:5): [True: 98, False: 735]
| 406 | 252 | i = 1; | 407 | 833 | } | 408 | | | 409 | 833 | const T max_div_base = max_val / base; | 410 | 833 | const T max_mod_base = max_val % base; | 411 | | | 412 | 833 | int first = i; | 413 | 3.55k | for (; i < len; ++i) { Branch (413:12): [True: 3.50k, False: 49]
| 414 | 3.50k | T digit; | 415 | 3.50k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 6.34k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 2.83k, False: 672]
Branch (35:42): [True: 2.83k, False: 672]
Branch (35:42): [True: 2.83k, False: 0]
|
| 416 | 2.83k | digit = s[i] - '0'; | 417 | 2.83k | } else if (s[i] >= 'a' && s[i] <= 'z') { Branch (417:20): [True: 0, False: 672]
Branch (417:35): [True: 0, False: 0]
| 418 | 0 | digit = (s[i] - 'a' + 10); | 419 | 672 | } else if (s[i] >= 'A' && s[i] <= 'Z') { Branch (419:20): [True: 0, False: 672]
Branch (419:35): [True: 0, False: 0]
| 420 | 0 | digit = (s[i] - 'A' + 10); | 421 | 672 | } else { | 422 | 672 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 966 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 378, False: 294]
Branch (36:44): [True: 0, False: 294]
|
Branch (422:17): [True: 378, False: 294]
| 423 | | // Reject the string because either the first char was not an alpha/digit, | 424 | | // or the remaining chars are not all whitespace | 425 | 378 | *result = PARSE_FAILURE; | 426 | 378 | return 0; | 427 | 378 | } | 428 | | // skip trailing whitespace. | 429 | 294 | break; | 430 | 672 | } | 431 | | | 432 | | // Bail, if we encounter a digit that is not available in base. | 433 | 2.83k | if (digit >= base) { Branch (433:13): [True: 0, False: 2.83k]
| 434 | 0 | break; | 435 | 0 | } | 436 | | | 437 | | // This is a tricky check to see if adding this digit will cause an overflow. | 438 | 2.83k | if (UNLIKELY(val > (max_div_base - (digit > max_mod_base)))) {Line | Count | Source | 36 | 2.83k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 112, False: 2.72k]
|
| 439 | 112 | *result = PARSE_OVERFLOW; | 440 | 112 | return static_cast<T>(negative ? -max_val : max_val); Branch (440:35): [True: 56, False: 56]
| 441 | 112 | } | 442 | 2.72k | val = val * base + digit; | 443 | 2.72k | } | 444 | 343 | *result = PARSE_SUCCESS; | 445 | 343 | return static_cast<T>(negative ? -val : val); Branch (445:27): [True: 98, False: 245]
| 446 | 833 | } |
_ZN5doris12StringParser22string_to_int_internalIlEET_PKciiPNS0_11ParseResultE Line | Count | Source | 390 | 833 | ParseResult* result) { | 391 | 833 | typedef typename std::make_unsigned<T>::type UnsignedT; | 392 | 833 | UnsignedT val = 0; | 393 | 833 | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 394 | 833 | bool negative = false; | 395 | 833 | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 833 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 833]
|
| 396 | 0 | *result = PARSE_FAILURE; | 397 | 0 | return 0; | 398 | 0 | } | 399 | 833 | int i = 0; | 400 | 833 | switch (*s) { Branch (400:13): [True: 581, False: 252]
| 401 | 203 | case '-': Branch (401:5): [True: 203, False: 630]
| 402 | 203 | negative = true; | 403 | 203 | max_val = StringParser::numeric_limits<T>(false) + 1; | 404 | 203 | [[fallthrough]]; | 405 | 252 | case '+': Branch (405:5): [True: 49, False: 784]
| 406 | 252 | i = 1; | 407 | 833 | } | 408 | | | 409 | 833 | const T max_div_base = max_val / base; | 410 | 833 | const T max_mod_base = max_val % base; | 411 | | | 412 | 833 | int first = i; | 413 | 5.74k | for (; i < len; ++i) { Branch (413:12): [True: 5.69k, False: 49]
| 414 | 5.69k | T digit; | 415 | 5.69k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 10.7k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 5.01k, False: 672]
Branch (35:42): [True: 5.01k, False: 672]
Branch (35:42): [True: 5.01k, False: 0]
|
| 416 | 5.01k | digit = s[i] - '0'; | 417 | 5.01k | } else if (s[i] >= 'a' && s[i] <= 'z') { Branch (417:20): [True: 0, False: 672]
Branch (417:35): [True: 0, False: 0]
| 418 | 0 | digit = (s[i] - 'a' + 10); | 419 | 672 | } else if (s[i] >= 'A' && s[i] <= 'Z') { Branch (419:20): [True: 0, False: 672]
Branch (419:35): [True: 0, False: 0]
| 420 | 0 | digit = (s[i] - 'A' + 10); | 421 | 672 | } else { | 422 | 672 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 966 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 378, False: 294]
Branch (36:44): [True: 0, False: 294]
|
Branch (422:17): [True: 378, False: 294]
| 423 | | // Reject the string because either the first char was not an alpha/digit, | 424 | | // or the remaining chars are not all whitespace | 425 | 378 | *result = PARSE_FAILURE; | 426 | 378 | return 0; | 427 | 378 | } | 428 | | // skip trailing whitespace. | 429 | 294 | break; | 430 | 672 | } | 431 | | | 432 | | // Bail, if we encounter a digit that is not available in base. | 433 | 5.01k | if (digit >= base) { Branch (433:13): [True: 0, False: 5.01k]
| 434 | 0 | break; | 435 | 0 | } | 436 | | | 437 | | // This is a tricky check to see if adding this digit will cause an overflow. | 438 | 5.01k | if (UNLIKELY(val > (max_div_base - (digit > max_mod_base)))) {Line | Count | Source | 36 | 5.01k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 112, False: 4.90k]
|
| 439 | 112 | *result = PARSE_OVERFLOW; | 440 | 112 | return static_cast<T>(negative ? -max_val : max_val); Branch (440:35): [True: 56, False: 56]
| 441 | 112 | } | 442 | 4.90k | val = val * base + digit; | 443 | 4.90k | } | 444 | 343 | *result = PARSE_SUCCESS; | 445 | 343 | return static_cast<T>(negative ? -val : val); Branch (445:27): [True: 147, False: 196]
| 446 | 833 | } |
_ZN5doris12StringParser22string_to_int_internalImEET_PKciiPNS0_11ParseResultE Line | Count | Source | 390 | 1 | ParseResult* result) { | 391 | 1 | typedef typename std::make_unsigned<T>::type UnsignedT; | 392 | 1 | UnsignedT val = 0; | 393 | 1 | UnsignedT max_val = StringParser::numeric_limits<T>(false); | 394 | 1 | bool negative = false; | 395 | 1 | if (UNLIKELY(len <= 0)) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1]
|
| 396 | 0 | *result = PARSE_FAILURE; | 397 | 0 | return 0; | 398 | 0 | } | 399 | 1 | int i = 0; | 400 | 1 | switch (*s) { Branch (400:13): [True: 1, False: 0]
| 401 | 0 | case '-': Branch (401:5): [True: 0, False: 1]
| 402 | 0 | negative = true; | 403 | 0 | max_val = StringParser::numeric_limits<T>(false) + 1; | 404 | 0 | [[fallthrough]]; | 405 | 0 | case '+': Branch (405:5): [True: 0, False: 1]
| 406 | 0 | i = 1; | 407 | 1 | } | 408 | | | 409 | 1 | const T max_div_base = max_val / base; | 410 | 1 | const T max_mod_base = max_val % base; | 411 | | | 412 | 1 | int first = i; | 413 | 3 | for (; i < len; ++i) { Branch (413:12): [True: 2, False: 1]
| 414 | 2 | T digit; | 415 | 2 | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 4 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 2]
Branch (35:42): [True: 2, False: 0]
Branch (35:42): [True: 0, False: 2]
|
| 416 | 0 | digit = s[i] - '0'; | 417 | 2 | } else if (s[i] >= 'a' && s[i] <= 'z') { Branch (417:20): [True: 2, False: 0]
Branch (417:35): [True: 2, False: 0]
| 418 | 2 | digit = (s[i] - 'a' + 10); | 419 | 2 | } else if (s[i] >= 'A' && s[i] <= 'Z') { Branch (419:20): [True: 0, False: 0]
Branch (419:35): [True: 0, False: 0]
| 420 | 0 | digit = (s[i] - 'A' + 10); | 421 | 0 | } else { | 422 | 0 | if ((UNLIKELY(i == first || !is_all_whitespace(s + i, len - i)))) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
|
Branch (422:17): [True: 0, False: 0]
| 423 | | // Reject the string because either the first char was not an alpha/digit, | 424 | | // or the remaining chars are not all whitespace | 425 | 0 | *result = PARSE_FAILURE; | 426 | 0 | return 0; | 427 | 0 | } | 428 | | // skip trailing whitespace. | 429 | 0 | break; | 430 | 0 | } | 431 | | | 432 | | // Bail, if we encounter a digit that is not available in base. | 433 | 2 | if (digit >= base) { Branch (433:13): [True: 0, False: 2]
| 434 | 0 | break; | 435 | 0 | } | 436 | | | 437 | | // This is a tricky check to see if adding this digit will cause an overflow. | 438 | 2 | if (UNLIKELY(val > (max_div_base - (digit > max_mod_base)))) {Line | Count | Source | 36 | 2 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 2]
|
| 439 | 0 | *result = PARSE_OVERFLOW; | 440 | 0 | return static_cast<T>(negative ? -max_val : max_val); Branch (440:35): [True: 0, False: 0]
| 441 | 0 | } | 442 | 2 | val = val * base + digit; | 443 | 2 | } | 444 | 1 | *result = PARSE_SUCCESS; | 445 | 1 | return static_cast<T>(negative ? -val : val); Branch (445:27): [True: 0, False: 1]
| 446 | 1 | } |
|
447 | | |
448 | | template <typename T> |
449 | 124k | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { |
450 | 124k | T val = 0; |
451 | 124k | if (UNLIKELY(len == 0)) {Line | Count | Source | 36 | 1.50k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1.50k]
|
| if (UNLIKELY(len == 0)) {Line | Count | Source | 36 | 119k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 119k]
|
| if (UNLIKELY(len == 0)) {Line | Count | Source | 36 | 145 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 145]
|
| if (UNLIKELY(len == 0)) {Line | Count | Source | 36 | 1.96k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1.96k]
|
| if (UNLIKELY(len == 0)) {Line | Count | Source | 36 | 1.09k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1.09k]
|
| if (UNLIKELY(len == 0)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
|
452 | 0 | *result = PARSE_SUCCESS; |
453 | 0 | return val; |
454 | 0 | } |
455 | | // Factor out the first char for error handling speeds up the loop. |
456 | 124k | if (LIKELY(s[0] >= '0' && s[0] <= '9')) {Line | Count | Source | 35 | 3.00k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.45k, False: 50]
Branch (35:42): [True: 1.49k, False: 16]
Branch (35:42): [True: 1.45k, False: 34]
|
| if (LIKELY(s[0] >= '0' && s[0] <= '9')) {Line | Count | Source | 35 | 239k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 119k, False: 0]
Branch (35:42): [True: 119k, False: 0]
Branch (35:42): [True: 119k, False: 0]
|
| if (LIKELY(s[0] >= '0' && s[0] <= '9')) {Line | Count | Source | 35 | 266 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 119, False: 26]
Branch (35:42): [True: 121, False: 24]
Branch (35:42): [True: 119, False: 2]
|
| if (LIKELY(s[0] >= '0' && s[0] <= '9')) {Line | Count | Source | 35 | 3.07k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 397, False: 1.57k]
Branch (35:42): [True: 1.10k, False: 859]
Branch (35:42): [True: 397, False: 712]
|
| if (LIKELY(s[0] >= '0' && s[0] <= '9')) {Line | Count | Source | 35 | 1.67k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 575, False: 520]
Branch (35:42): [True: 579, False: 516]
Branch (35:42): [True: 575, False: 4]
|
| if (LIKELY(s[0] >= '0' && s[0] <= '9')) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
|
|
457 | 122k | val = s[0] - '0'; |
458 | 122k | } else { |
459 | 2.16k | *result = PARSE_FAILURE; |
460 | 2.16k | return 0; |
461 | 2.16k | } |
462 | 974k | for (int i = 1; i < len; ++i) { Branch (462:21): [True: 1.27k, False: 1.45k]
Branch (462:21): [True: 848k, False: 119k]
Branch (462:21): [True: 119, False: 35]
Branch (462:21): [True: 676, False: 87]
Branch (462:21): [True: 2.71k, False: 264]
Branch (462:21): [True: 0, False: 0]
|
463 | 853k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 2.54k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.27k, False: 0]
Branch (35:42): [True: 1.27k, False: 0]
Branch (35:42): [True: 1.27k, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 1.69M | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 848k, False: 0]
Branch (35:42): [True: 848k, False: 0]
Branch (35:42): [True: 848k, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 154 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 35, False: 84]
Branch (35:42): [True: 35, False: 84]
Branch (35:42): [True: 35, False: 0]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 1.10k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 366, False: 310]
Branch (35:42): [True: 424, False: 252]
Branch (35:42): [True: 366, False: 58]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 5.14k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 2.40k, False: 311]
Branch (35:42): [True: 2.42k, False: 297]
Branch (35:42): [True: 2.40k, False: 14]
|
| if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
Branch (35:42): [True: 0, False: 0]
|
|
464 | 852k | T digit = s[i] - '0'; |
465 | 852k | val = val * 10 + digit; |
466 | 852k | } else { |
467 | 705 | if ((UNLIKELY(!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
|
| if ((UNLIKELY(!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
|
| if ((UNLIKELY(!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 84 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 84]
Branch (36:44): [True: 0, False: 0]
|
| if ((UNLIKELY(!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 410 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 100, False: 210]
Branch (36:44): [True: 100, False: 0]
|
| if ((UNLIKELY(!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 328 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 17, False: 294]
Branch (36:44): [True: 16, False: 1]
|
| if ((UNLIKELY(!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
|
Branch (467:17): [True: 0, False: 0]
Branch (467:17): [True: 0, False: 0]
Branch (467:17): [True: 0, False: 84]
Branch (467:17): [True: 100, False: 210]
Branch (467:17): [True: 16, False: 295]
Branch (467:17): [True: 0, False: 0]
|
468 | 705 | !is_float_suffix(s + i, len - i)))) { |
469 | 116 | *result = PARSE_FAILURE; |
470 | 116 | return 0; |
471 | 116 | } |
472 | 589 | *result = PARSE_SUCCESS; |
473 | 589 | return val; |
474 | 705 | } |
475 | 853k | } |
476 | 121k | *result = PARSE_SUCCESS; |
477 | 121k | return val; |
478 | 122k | } _ZN5doris12StringParser25string_to_int_no_overflowIhEET_PKciPNS0_11ParseResultE Line | Count | Source | 449 | 1.50k | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 450 | 1.50k | T val = 0; | 451 | 1.50k | if (UNLIKELY(len == 0)) {Line | Count | Source | 36 | 1.50k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1.50k]
|
| 452 | 0 | *result = PARSE_SUCCESS; | 453 | 0 | return val; | 454 | 0 | } | 455 | | // Factor out the first char for error handling speeds up the loop. | 456 | 1.50k | if (LIKELY(s[0] >= '0' && s[0] <= '9')) {Line | Count | Source | 35 | 3.00k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.45k, False: 50]
Branch (35:42): [True: 1.49k, False: 16]
Branch (35:42): [True: 1.45k, False: 34]
|
| 457 | 1.45k | val = s[0] - '0'; | 458 | 1.45k | } else { | 459 | 50 | *result = PARSE_FAILURE; | 460 | 50 | return 0; | 461 | 50 | } | 462 | 2.72k | for (int i = 1; i < len; ++i) { Branch (462:21): [True: 1.27k, False: 1.45k]
| 463 | 1.27k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 2.54k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.27k, False: 0]
Branch (35:42): [True: 1.27k, False: 0]
Branch (35:42): [True: 1.27k, False: 0]
|
| 464 | 1.27k | T digit = s[i] - '0'; | 465 | 1.27k | val = val * 10 + digit; | 466 | 1.27k | } else { | 467 | 0 | if ((UNLIKELY(!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
|
Branch (467:17): [True: 0, False: 0]
| 468 | 0 | !is_float_suffix(s + i, len - i)))) { | 469 | 0 | *result = PARSE_FAILURE; | 470 | 0 | return 0; | 471 | 0 | } | 472 | 0 | *result = PARSE_SUCCESS; | 473 | 0 | return val; | 474 | 0 | } | 475 | 1.27k | } | 476 | 1.45k | *result = PARSE_SUCCESS; | 477 | 1.45k | return val; | 478 | 1.45k | } |
_ZN5doris12StringParser25string_to_int_no_overflowIoEET_PKciPNS0_11ParseResultE Line | Count | Source | 449 | 119k | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 450 | 119k | T val = 0; | 451 | 119k | if (UNLIKELY(len == 0)) {Line | Count | Source | 36 | 119k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 119k]
|
| 452 | 0 | *result = PARSE_SUCCESS; | 453 | 0 | return val; | 454 | 0 | } | 455 | | // Factor out the first char for error handling speeds up the loop. | 456 | 119k | if (LIKELY(s[0] >= '0' && s[0] <= '9')) {Line | Count | Source | 35 | 239k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 119k, False: 0]
Branch (35:42): [True: 119k, False: 0]
Branch (35:42): [True: 119k, False: 0]
|
| 457 | 119k | val = s[0] - '0'; | 458 | 119k | } else { | 459 | 0 | *result = PARSE_FAILURE; | 460 | 0 | return 0; | 461 | 0 | } | 462 | 968k | for (int i = 1; i < len; ++i) { Branch (462:21): [True: 848k, False: 119k]
| 463 | 848k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 1.69M | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 848k, False: 0]
Branch (35:42): [True: 848k, False: 0]
Branch (35:42): [True: 848k, False: 0]
|
| 464 | 848k | T digit = s[i] - '0'; | 465 | 848k | val = val * 10 + digit; | 466 | 848k | } else { | 467 | 0 | if ((UNLIKELY(!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 0]
Branch (36:44): [True: 0, False: 0]
|
Branch (467:17): [True: 0, False: 0]
| 468 | 0 | !is_float_suffix(s + i, len - i)))) { | 469 | 0 | *result = PARSE_FAILURE; | 470 | 0 | return 0; | 471 | 0 | } | 472 | 0 | *result = PARSE_SUCCESS; | 473 | 0 | return val; | 474 | 0 | } | 475 | 848k | } | 476 | 119k | *result = PARSE_SUCCESS; | 477 | 119k | return val; | 478 | 119k | } |
_ZN5doris12StringParser25string_to_int_no_overflowItEET_PKciPNS0_11ParseResultE Line | Count | Source | 449 | 145 | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 450 | 145 | T val = 0; | 451 | 145 | if (UNLIKELY(len == 0)) {Line | Count | Source | 36 | 145 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 145]
|
| 452 | 0 | *result = PARSE_SUCCESS; | 453 | 0 | return val; | 454 | 0 | } | 455 | | // Factor out the first char for error handling speeds up the loop. | 456 | 145 | if (LIKELY(s[0] >= '0' && s[0] <= '9')) {Line | Count | Source | 35 | 266 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 119, False: 26]
Branch (35:42): [True: 121, False: 24]
Branch (35:42): [True: 119, False: 2]
|
| 457 | 119 | val = s[0] - '0'; | 458 | 119 | } else { | 459 | 26 | *result = PARSE_FAILURE; | 460 | 26 | return 0; | 461 | 26 | } | 462 | 154 | for (int i = 1; i < len; ++i) { Branch (462:21): [True: 119, False: 35]
| 463 | 119 | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 154 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 35, False: 84]
Branch (35:42): [True: 35, False: 84]
Branch (35:42): [True: 35, False: 0]
|
| 464 | 35 | T digit = s[i] - '0'; | 465 | 35 | val = val * 10 + digit; | 466 | 84 | } else { | 467 | 84 | if ((UNLIKELY(!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 84 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 0, False: 84]
Branch (36:44): [True: 0, False: 0]
|
Branch (467:17): [True: 0, False: 84]
| 468 | 84 | !is_float_suffix(s + i, len - i)))) { | 469 | 0 | *result = PARSE_FAILURE; | 470 | 0 | return 0; | 471 | 0 | } | 472 | 84 | *result = PARSE_SUCCESS; | 473 | 84 | return val; | 474 | 84 | } | 475 | 119 | } | 476 | 35 | *result = PARSE_SUCCESS; | 477 | 35 | return val; | 478 | 119 | } |
_ZN5doris12StringParser25string_to_int_no_overflowIjEET_PKciPNS0_11ParseResultE Line | Count | Source | 449 | 1.96k | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 450 | 1.96k | T val = 0; | 451 | 1.96k | if (UNLIKELY(len == 0)) {Line | Count | Source | 36 | 1.96k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1.96k]
|
| 452 | 0 | *result = PARSE_SUCCESS; | 453 | 0 | return val; | 454 | 0 | } | 455 | | // Factor out the first char for error handling speeds up the loop. | 456 | 1.96k | if (LIKELY(s[0] >= '0' && s[0] <= '9')) {Line | Count | Source | 35 | 3.07k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 397, False: 1.57k]
Branch (35:42): [True: 1.10k, False: 859]
Branch (35:42): [True: 397, False: 712]
|
| 457 | 397 | val = s[0] - '0'; | 458 | 1.57k | } else { | 459 | 1.57k | *result = PARSE_FAILURE; | 460 | 1.57k | return 0; | 461 | 1.57k | } | 462 | 763 | for (int i = 1; i < len; ++i) { Branch (462:21): [True: 676, False: 87]
| 463 | 676 | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 1.10k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 366, False: 310]
Branch (35:42): [True: 424, False: 252]
Branch (35:42): [True: 366, False: 58]
|
| 464 | 366 | T digit = s[i] - '0'; | 465 | 366 | val = val * 10 + digit; | 466 | 366 | } else { | 467 | 310 | if ((UNLIKELY(!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 410 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 100, False: 210]
Branch (36:44): [True: 100, False: 0]
|
Branch (467:17): [True: 100, False: 210]
| 468 | 310 | !is_float_suffix(s + i, len - i)))) { | 469 | 100 | *result = PARSE_FAILURE; | 470 | 100 | return 0; | 471 | 100 | } | 472 | 210 | *result = PARSE_SUCCESS; | 473 | 210 | return val; | 474 | 310 | } | 475 | 676 | } | 476 | 87 | *result = PARSE_SUCCESS; | 477 | 87 | return val; | 478 | 397 | } |
_ZN5doris12StringParser25string_to_int_no_overflowImEET_PKciPNS0_11ParseResultE Line | Count | Source | 449 | 1.09k | T StringParser::string_to_int_no_overflow(const char* __restrict s, int len, ParseResult* result) { | 450 | 1.09k | T val = 0; | 451 | 1.09k | if (UNLIKELY(len == 0)) {Line | Count | Source | 36 | 1.09k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1.09k]
|
| 452 | 0 | *result = PARSE_SUCCESS; | 453 | 0 | return val; | 454 | 0 | } | 455 | | // Factor out the first char for error handling speeds up the loop. | 456 | 1.09k | if (LIKELY(s[0] >= '0' && s[0] <= '9')) {Line | Count | Source | 35 | 1.67k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 575, False: 520]
Branch (35:42): [True: 579, False: 516]
Branch (35:42): [True: 575, False: 4]
|
| 457 | 575 | val = s[0] - '0'; | 458 | 575 | } else { | 459 | 520 | *result = PARSE_FAILURE; | 460 | 520 | return 0; | 461 | 520 | } | 462 | 2.98k | for (int i = 1; i < len; ++i) { Branch (462:21): [True: 2.71k, False: 264]
| 463 | 2.71k | if (LIKELY(s[i] >= '0' && s[i] <= '9')) {Line | Count | Source | 35 | 5.14k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 2.40k, False: 311]
Branch (35:42): [True: 2.42k, False: 297]
Branch (35:42): [True: 2.40k, False: 14]
|
| 464 | 2.40k | T digit = s[i] - '0'; | 465 | 2.40k | val = val * 10 + digit; | 466 | 2.40k | } else { | 467 | 311 | if ((UNLIKELY(!is_all_whitespace(s + i, len - i) && Line | Count | Source | 36 | 328 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:44): [True: 17, False: 294]
Branch (36:44): [True: 16, False: 1]
|
Branch (467:17): [True: 16, False: 295]
| 468 | 311 | !is_float_suffix(s + i, len - i)))) { | 469 | 16 | *result = PARSE_FAILURE; | 470 | 16 | return 0; | 471 | 16 | } | 472 | 295 | *result = PARSE_SUCCESS; | 473 | 295 | return val; | 474 | 311 | } | 475 | 2.71k | } | 476 | 264 | *result = PARSE_SUCCESS; | 477 | 264 | return val; | 478 | 575 | } |
Unexecuted instantiation: _ZN5doris12StringParser25string_to_int_no_overflowIN4wide7integerILm256EjEEEET_PKciPNS0_11ParseResultE |
479 | | |
480 | | template <typename T> |
481 | 66.9k | T StringParser::string_to_float_internal(const char* __restrict s, int len, ParseResult* result) { |
482 | 66.9k | int i = 0; |
483 | | // skip leading spaces |
484 | 107k | for (; i < len; ++i) { Branch (484:12): [True: 79.0k, False: 3]
Branch (484:12): [True: 28.6k, False: 0]
|
485 | 107k | if (!is_whitespace(s[i])) { Branch (485:13): [True: 58.6k, False: 20.4k]
Branch (485:13): [True: 8.25k, False: 20.4k]
|
486 | 66.8k | break; |
487 | 66.8k | } |
488 | 107k | } |
489 | | |
490 | | // skip back spaces |
491 | 66.9k | int j = len - 1; |
492 | 108k | for (; j >= i; j--) { Branch (492:12): [True: 79.2k, False: 3]
Branch (492:12): [True: 28.8k, False: 0]
|
493 | 108k | if (!is_whitespace(s[j])) { Branch (493:13): [True: 58.6k, False: 20.5k]
Branch (493:13): [True: 8.25k, False: 20.5k]
|
494 | 66.8k | break; |
495 | 66.8k | } |
496 | 108k | } |
497 | | |
498 | | // skip leading '+', from_chars can handle '-' |
499 | 66.9k | if (i < len && s[i] == '+') { Branch (499:9): [True: 58.6k, False: 3]
Branch (499:20): [True: 2.64k, False: 56.0k]
Branch (499:9): [True: 8.25k, False: 0]
Branch (499:20): [True: 2.64k, False: 5.60k]
|
500 | 5.29k | i++; |
501 | 5.29k | } |
502 | 66.9k | if (UNLIKELY(i > j)) {Line | Count | Source | 36 | 58.6k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 3, False: 58.6k]
|
| if (UNLIKELY(i > j)) {Line | Count | Source | 36 | 8.25k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 8.25k]
|
|
503 | 3 | *result = PARSE_FAILURE; |
504 | 3 | return 0; |
505 | 3 | } |
506 | | |
507 | | // Use double here to not lose precision while accumulating the result |
508 | 66.8k | double val = 0; |
509 | 66.8k | auto res = fast_float::from_chars(s + i, s + j + 1, val); |
510 | | |
511 | 66.8k | if (res.ec == std::errc() && res.ptr == s + j + 1) { Branch (511:9): [True: 57.9k, False: 744]
Branch (511:34): [True: 56.7k, False: 1.19k]
Branch (511:9): [True: 7.51k, False: 739]
Branch (511:34): [True: 6.32k, False: 1.18k]
|
512 | 63.0k | if (abs(val) == std::numeric_limits<T>::infinity()) { Branch (512:13): [True: 809, False: 55.9k]
Branch (512:13): [True: 443, False: 5.88k]
|
513 | 1.25k | auto contain_inf = false; |
514 | 9.32k | for (int k = i; k < j + 1; k++) { Branch (514:29): [True: 8.33k, False: 368]
Branch (514:29): [True: 627, False: 2]
|
515 | 8.95k | if (s[k] == 'i' || s[k] == 'I') { Branch (515:21): [True: 294, False: 8.03k]
Branch (515:36): [True: 147, False: 7.89k]
Branch (515:21): [True: 294, False: 333]
Branch (515:36): [True: 147, False: 186]
|
516 | 882 | contain_inf = true; |
517 | 882 | break; |
518 | 882 | } |
519 | 8.95k | } |
520 | | |
521 | 1.25k | *result = contain_inf ? PARSE_SUCCESS : PARSE_OVERFLOW; Branch (521:23): [True: 441, False: 368]
Branch (521:23): [True: 441, False: 2]
|
522 | 61.7k | } else { |
523 | 61.7k | *result = PARSE_SUCCESS; |
524 | 61.7k | } |
525 | 63.0k | return val; |
526 | 63.0k | } else { |
527 | 3.86k | *result = PARSE_FAILURE; |
528 | 3.86k | } |
529 | 3.86k | return 0; |
530 | 66.8k | } _ZN5doris12StringParser24string_to_float_internalIdEET_PKciPNS0_11ParseResultE Line | Count | Source | 481 | 58.6k | T StringParser::string_to_float_internal(const char* __restrict s, int len, ParseResult* result) { | 482 | 58.6k | int i = 0; | 483 | | // skip leading spaces | 484 | 79.0k | for (; i < len; ++i) { Branch (484:12): [True: 79.0k, False: 3]
| 485 | 79.0k | if (!is_whitespace(s[i])) { Branch (485:13): [True: 58.6k, False: 20.4k]
| 486 | 58.6k | break; | 487 | 58.6k | } | 488 | 79.0k | } | 489 | | | 490 | | // skip back spaces | 491 | 58.6k | int j = len - 1; | 492 | 79.2k | for (; j >= i; j--) { Branch (492:12): [True: 79.2k, False: 3]
| 493 | 79.2k | if (!is_whitespace(s[j])) { Branch (493:13): [True: 58.6k, False: 20.5k]
| 494 | 58.6k | break; | 495 | 58.6k | } | 496 | 79.2k | } | 497 | | | 498 | | // skip leading '+', from_chars can handle '-' | 499 | 58.6k | if (i < len && s[i] == '+') { Branch (499:9): [True: 58.6k, False: 3]
Branch (499:20): [True: 2.64k, False: 56.0k]
| 500 | 2.64k | i++; | 501 | 2.64k | } | 502 | 58.6k | if (UNLIKELY(i > j)) {Line | Count | Source | 36 | 58.6k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 3, False: 58.6k]
|
| 503 | 3 | *result = PARSE_FAILURE; | 504 | 3 | return 0; | 505 | 3 | } | 506 | | | 507 | | // Use double here to not lose precision while accumulating the result | 508 | 58.6k | double val = 0; | 509 | 58.6k | auto res = fast_float::from_chars(s + i, s + j + 1, val); | 510 | | | 511 | 58.6k | if (res.ec == std::errc() && res.ptr == s + j + 1) { Branch (511:9): [True: 57.9k, False: 744]
Branch (511:34): [True: 56.7k, False: 1.19k]
| 512 | 56.7k | if (abs(val) == std::numeric_limits<T>::infinity()) { Branch (512:13): [True: 809, False: 55.9k]
| 513 | 809 | auto contain_inf = false; | 514 | 8.69k | for (int k = i; k < j + 1; k++) { Branch (514:29): [True: 8.33k, False: 368]
| 515 | 8.33k | if (s[k] == 'i' || s[k] == 'I') { Branch (515:21): [True: 294, False: 8.03k]
Branch (515:36): [True: 147, False: 7.89k]
| 516 | 441 | contain_inf = true; | 517 | 441 | break; | 518 | 441 | } | 519 | 8.33k | } | 520 | | | 521 | 809 | *result = contain_inf ? PARSE_SUCCESS : PARSE_OVERFLOW; Branch (521:23): [True: 441, False: 368]
| 522 | 55.9k | } else { | 523 | 55.9k | *result = PARSE_SUCCESS; | 524 | 55.9k | } | 525 | 56.7k | return val; | 526 | 56.7k | } else { | 527 | 1.93k | *result = PARSE_FAILURE; | 528 | 1.93k | } | 529 | 1.93k | return 0; | 530 | 58.6k | } |
_ZN5doris12StringParser24string_to_float_internalIfEET_PKciPNS0_11ParseResultE Line | Count | Source | 481 | 8.25k | T StringParser::string_to_float_internal(const char* __restrict s, int len, ParseResult* result) { | 482 | 8.25k | int i = 0; | 483 | | // skip leading spaces | 484 | 28.6k | for (; i < len; ++i) { Branch (484:12): [True: 28.6k, False: 0]
| 485 | 28.6k | if (!is_whitespace(s[i])) { Branch (485:13): [True: 8.25k, False: 20.4k]
| 486 | 8.25k | break; | 487 | 8.25k | } | 488 | 28.6k | } | 489 | | | 490 | | // skip back spaces | 491 | 8.25k | int j = len - 1; | 492 | 28.8k | for (; j >= i; j--) { Branch (492:12): [True: 28.8k, False: 0]
| 493 | 28.8k | if (!is_whitespace(s[j])) { Branch (493:13): [True: 8.25k, False: 20.5k]
| 494 | 8.25k | break; | 495 | 8.25k | } | 496 | 28.8k | } | 497 | | | 498 | | // skip leading '+', from_chars can handle '-' | 499 | 8.25k | if (i < len && s[i] == '+') { Branch (499:9): [True: 8.25k, False: 0]
Branch (499:20): [True: 2.64k, False: 5.60k]
| 500 | 2.64k | i++; | 501 | 2.64k | } | 502 | 8.25k | if (UNLIKELY(i > j)) {Line | Count | Source | 36 | 8.25k | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 8.25k]
|
| 503 | 0 | *result = PARSE_FAILURE; | 504 | 0 | return 0; | 505 | 0 | } | 506 | | | 507 | | // Use double here to not lose precision while accumulating the result | 508 | 8.25k | double val = 0; | 509 | 8.25k | auto res = fast_float::from_chars(s + i, s + j + 1, val); | 510 | | | 511 | 8.25k | if (res.ec == std::errc() && res.ptr == s + j + 1) { Branch (511:9): [True: 7.51k, False: 739]
Branch (511:34): [True: 6.32k, False: 1.18k]
| 512 | 6.32k | if (abs(val) == std::numeric_limits<T>::infinity()) { Branch (512:13): [True: 443, False: 5.88k]
| 513 | 443 | auto contain_inf = false; | 514 | 629 | for (int k = i; k < j + 1; k++) { Branch (514:29): [True: 627, False: 2]
| 515 | 627 | if (s[k] == 'i' || s[k] == 'I') { Branch (515:21): [True: 294, False: 333]
Branch (515:36): [True: 147, False: 186]
| 516 | 441 | contain_inf = true; | 517 | 441 | break; | 518 | 441 | } | 519 | 627 | } | 520 | | | 521 | 443 | *result = contain_inf ? PARSE_SUCCESS : PARSE_OVERFLOW; Branch (521:23): [True: 441, False: 2]
| 522 | 5.88k | } else { | 523 | 5.88k | *result = PARSE_SUCCESS; | 524 | 5.88k | } | 525 | 6.32k | return val; | 526 | 6.32k | } else { | 527 | 1.92k | *result = PARSE_FAILURE; | 528 | 1.92k | } | 529 | 1.92k | return 0; | 530 | 8.25k | } |
|
531 | | |
532 | | inline bool StringParser::string_to_bool_internal(const char* __restrict s, int len, |
533 | 620 | ParseResult* result) { |
534 | 620 | *result = PARSE_SUCCESS; |
535 | | |
536 | 620 | if (len >= 4 && (s[0] == 't' || s[0] == 'T')) { Branch (536:9): [True: 598, False: 22]
Branch (536:22): [True: 170, False: 428]
Branch (536:37): [True: 0, False: 428]
|
537 | 170 | bool match = (s[1] == 'r' || s[1] == 'R') && (s[2] == 'u' || s[2] == 'U') && Branch (537:23): [True: 114, False: 56]
Branch (537:38): [True: 0, False: 56]
Branch (537:55): [True: 114, False: 0]
Branch (537:70): [True: 0, False: 0]
|
538 | 170 | (s[3] == 'e' || s[3] == 'E'); Branch (538:23): [True: 114, False: 0]
Branch (538:38): [True: 0, False: 0]
|
539 | 170 | if (match && LIKELY(is_all_whitespace(s + 4, len - 4))) {Line | Count | Source | 35 | 114 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 58, False: 56]
|
Branch (539:13): [True: 114, False: 56]
|
540 | 58 | return true; |
541 | 58 | } |
542 | 450 | } else if (len >= 5 && (s[0] == 'f' || s[0] == 'F')) { Branch (542:16): [True: 426, False: 24]
Branch (542:29): [True: 170, False: 256]
Branch (542:44): [True: 0, False: 256]
|
543 | 170 | bool match = (s[1] == 'a' || s[1] == 'A') && (s[2] == 'l' || s[2] == 'L') && Branch (543:23): [True: 114, False: 56]
Branch (543:38): [True: 0, False: 56]
Branch (543:55): [True: 114, False: 0]
Branch (543:70): [True: 0, False: 0]
|
544 | 170 | (s[3] == 's' || s[3] == 'S') && (s[4] == 'e' || s[4] == 'E'); Branch (544:23): [True: 114, False: 0]
Branch (544:38): [True: 0, False: 0]
Branch (544:55): [True: 114, False: 0]
Branch (544:70): [True: 0, False: 0]
|
545 | 170 | if (match && LIKELY(is_all_whitespace(s + 5, len - 5))) {Line | Count | Source | 35 | 114 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 52, False: 62]
|
Branch (545:13): [True: 114, False: 56]
|
546 | 52 | return false; |
547 | 52 | } |
548 | 170 | } |
549 | | |
550 | 510 | *result = PARSE_FAILURE; |
551 | 510 | return false; |
552 | 620 | } |
553 | | |
554 | | template <PrimitiveType P, typename T, typename DecimalType> |
555 | | T StringParser::string_to_decimal(const char* __restrict s, int len, int type_precision, |
556 | 231 | int type_scale, ParseResult* result) { |
557 | 231 | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || |
558 | 231 | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, |
559 | 231 | "Cast string to decimal only support target type int32_t, int64_t, __int128 or " |
560 | 231 | "wide::Int256."); |
561 | | // Special cases: |
562 | | // 1) '' == Fail, an empty string fails to parse. |
563 | | // 2) ' # ' == #, leading and trailing white space is ignored. |
564 | | // 3) '.' == 0, a single dot parses as zero (for consistency with other types). |
565 | | // 4) '#.' == '#', a trailing dot is ignored. |
566 | | |
567 | | // Ignore leading and trailing spaces. |
568 | 231 | while (len > 0 && is_whitespace(*s)) { Branch (568:12): [True: 28, False: 0]
Branch (568:23): [True: 0, False: 28]
Branch (568:12): [True: 35, False: 1]
Branch (568:23): [True: 0, False: 35]
Branch (568:12): [True: 28, False: 0]
Branch (568:23): [True: 0, False: 28]
Branch (568:12): [True: 1, False: 0]
Branch (568:23): [True: 0, False: 1]
Branch (568:12): [True: 138, False: 0]
Branch (568:23): [True: 0, False: 138]
|
569 | 0 | ++s; |
570 | 0 | --len; |
571 | 0 | } |
572 | 231 | while (len > 0 && is_whitespace(s[len - 1])) { Branch (572:12): [True: 28, False: 0]
Branch (572:23): [True: 0, False: 28]
Branch (572:12): [True: 35, False: 1]
Branch (572:23): [True: 0, False: 35]
Branch (572:12): [True: 28, False: 0]
Branch (572:23): [True: 0, False: 28]
Branch (572:12): [True: 1, False: 0]
Branch (572:23): [True: 0, False: 1]
Branch (572:12): [True: 138, False: 0]
Branch (572:23): [True: 0, False: 138]
|
573 | 0 | --len; |
574 | 0 | } |
575 | | |
576 | 231 | bool is_negative = false; |
577 | 231 | if (len > 0) { Branch (577:9): [True: 28, False: 0]
Branch (577:9): [True: 35, False: 1]
Branch (577:9): [True: 28, False: 0]
Branch (577:9): [True: 1, False: 0]
Branch (577:9): [True: 138, False: 0]
|
578 | 230 | switch (*s) { Branch (578:17): [True: 22, False: 6]
Branch (578:17): [True: 28, False: 7]
Branch (578:17): [True: 27, False: 1]
Branch (578:17): [True: 1, False: 0]
Branch (578:17): [True: 113, False: 25]
|
579 | 39 | case '-': Branch (579:9): [True: 6, False: 22]
Branch (579:9): [True: 7, False: 28]
Branch (579:9): [True: 1, False: 27]
Branch (579:9): [True: 0, False: 1]
Branch (579:9): [True: 25, False: 113]
|
580 | 39 | is_negative = true; |
581 | 39 | [[fallthrough]]; |
582 | 39 | case '+': Branch (582:9): [True: 0, False: 28]
Branch (582:9): [True: 0, False: 35]
Branch (582:9): [True: 0, False: 28]
Branch (582:9): [True: 0, False: 1]
Branch (582:9): [True: 0, False: 138]
|
583 | 39 | ++s; |
584 | 39 | --len; |
585 | 230 | } |
586 | 230 | } |
587 | | |
588 | | // Ignore leading zeros. |
589 | 231 | bool found_value = false; |
590 | 258 | while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 28 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 28]
|
| while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 36 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 1, False: 35]
|
| while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 32 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 4, False: 28]
|
| while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1]
|
| while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 155 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 22, False: 133]
|
Branch (590:12): [True: 28, False: 0]
Branch (590:12): [True: 36, False: 1]
Branch (590:12): [True: 32, False: 0]
Branch (590:12): [True: 1, False: 0]
Branch (590:12): [True: 155, False: 5]
|
591 | 27 | found_value = true; |
592 | 27 | ++s; |
593 | 27 | --len; |
594 | 27 | } |
595 | | |
596 | | // Ignore leading zeros even after a dot. This allows for differentiating between |
597 | | // cases like 0.01e2, which would fit in a DECIMAL(1, 0), and 0.10e2, which would |
598 | | // overflow. |
599 | 231 | int scale = 0; |
600 | 231 | int found_dot = 0; |
601 | 231 | if (len > 0 && *s == '.') { Branch (601:9): [True: 28, False: 0]
Branch (601:20): [True: 0, False: 28]
Branch (601:9): [True: 35, False: 1]
Branch (601:20): [True: 1, False: 34]
Branch (601:9): [True: 28, False: 0]
Branch (601:20): [True: 0, False: 28]
Branch (601:9): [True: 1, False: 0]
Branch (601:20): [True: 0, False: 1]
Branch (601:9): [True: 133, False: 5]
Branch (601:20): [True: 9, False: 124]
|
602 | 10 | found_dot = 1; |
603 | 10 | ++s; |
604 | 10 | --len; |
605 | 16 | while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 1, False: 0]
|
| while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 12 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 5, False: 7]
|
Branch (605:16): [True: 0, False: 0]
Branch (605:16): [True: 1, False: 1]
Branch (605:16): [True: 0, False: 0]
Branch (605:16): [True: 0, False: 0]
Branch (605:16): [True: 12, False: 2]
|
606 | 6 | found_value = true; |
607 | 6 | ++scale; |
608 | 6 | ++s; |
609 | 6 | --len; |
610 | 6 | } |
611 | 10 | } |
612 | | |
613 | 231 | int precision = 0; |
614 | 231 | int max_digit = type_precision - type_scale; |
615 | 231 | int cur_digit = 0; |
616 | 231 | bool found_exponent = false; |
617 | 231 | int8_t exponent = 0; |
618 | 231 | T value = 0; |
619 | 231 | bool has_round = false; |
620 | 4.27k | for (int i = 0; i < len; ++i) { Branch (620:21): [True: 306, False: 16]
Branch (620:21): [True: 525, False: 34]
Branch (620:21): [True: 1.04k, False: 28]
Branch (620:21): [True: 77, False: 1]
Branch (620:21): [True: 2.12k, False: 127]
|
621 | 4.07k | const char& c = s[i]; |
622 | 4.07k | if (LIKELY('0' <= c && c <= '9')) {Line | Count | Source | 35 | 572 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 266, False: 40]
Branch (35:42): [True: 266, False: 40]
Branch (35:42): [True: 266, False: 0]
|
| if (LIKELY('0' <= c && c <= '9')) {Line | Count | Source | 35 | 1.01k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 491, False: 34]
Branch (35:42): [True: 493, False: 32]
Branch (35:42): [True: 491, False: 2]
|
| if (LIKELY('0' <= c && c <= '9')) {Line | Count | Source | 35 | 2.05k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.01k, False: 26]
Branch (35:42): [True: 1.01k, False: 26]
Branch (35:42): [True: 1.01k, False: 0]
|
| if (LIKELY('0' <= c && c <= '9')) {Line | Count | Source | 35 | 153 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 76, False: 1]
Branch (35:42): [True: 76, False: 1]
Branch (35:42): [True: 76, False: 0]
|
| if (LIKELY('0' <= c && c <= '9')) {Line | Count | Source | 35 | 4.12k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 2.00k, False: 118]
Branch (35:42): [True: 2.00k, False: 113]
Branch (35:42): [True: 2.00k, False: 5]
|
|
623 | 3.85k | found_value = true; |
624 | | // Ignore digits once the type's precision limit is reached. This avoids |
625 | | // overflowing the underlying storage while handling a string like |
626 | | // 10000000000e-10 into a DECIMAL(1, 0). Adjustments for ignored digits and |
627 | | // an exponent will be made later. |
628 | 3.85k | if (LIKELY(type_precision > precision) && !has_round) {Line | Count | Source | 35 | 532 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 252, False: 14]
|
| if (LIKELY(type_precision > precision) && !has_round) {Line | Count | Source | 35 | 982 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 481, False: 10]
|
| if (LIKELY(type_precision > precision) && !has_round) {Line | Count | Source | 35 | 2.03k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.01k, False: 4]
|
| if (LIKELY(type_precision > precision) && !has_round) {Line | Count | Source | 35 | 152 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 76, False: 0]
|
| if (LIKELY(type_precision > precision) && !has_round) {Line | Count | Source | 35 | 4.00k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.99k, False: 8]
|
Branch (628:55): [True: 252, False: 0]
Branch (628:55): [True: 481, False: 0]
Branch (628:55): [True: 1.01k, False: 0]
Branch (628:55): [True: 76, False: 0]
Branch (628:55): [True: 1.99k, False: 0]
|
629 | 3.81k | value = (value * 10) + (c - '0'); // Benchmarks are faster with parenthesis... |
630 | 3.81k | ++precision; |
631 | 3.81k | scale += found_dot; |
632 | 3.81k | cur_digit = precision - scale; |
633 | 3.81k | } else if (!found_dot && max_digit < (precision - scale)) { Branch (633:24): [True: 0, False: 14]
Branch (633:38): [True: 0, False: 0]
Branch (633:24): [True: 0, False: 10]
Branch (633:38): [True: 0, False: 0]
Branch (633:24): [True: 0, False: 4]
Branch (633:38): [True: 0, False: 0]
Branch (633:24): [True: 0, False: 0]
Branch (633:38): [True: 0, False: 0]
Branch (633:24): [True: 0, False: 8]
Branch (633:38): [True: 0, False: 0]
|
634 | 0 | *result = StringParser::PARSE_OVERFLOW; |
635 | 0 | value = is_negative ? vectorized::min_decimal_value<DecimalType>(type_precision) Branch (635:25): [True: 0, False: 0]
Branch (635:25): [True: 0, False: 0]
Branch (635:25): [True: 0, False: 0]
Branch (635:25): [True: 0, False: 0]
Branch (635:25): [True: 0, False: 0]
|
636 | 0 | : vectorized::max_decimal_value<DecimalType>(type_precision); |
637 | 0 | return value; |
638 | 36 | } else if (found_dot && scale >= type_scale && !has_round) { Branch (638:24): [True: 14, False: 0]
Branch (638:37): [True: 4, False: 10]
Branch (638:60): [True: 4, False: 0]
Branch (638:24): [True: 10, False: 0]
Branch (638:37): [True: 4, False: 6]
Branch (638:60): [True: 4, False: 0]
Branch (638:24): [True: 4, False: 0]
Branch (638:37): [True: 4, False: 0]
Branch (638:60): [True: 4, False: 0]
Branch (638:24): [True: 0, False: 0]
Branch (638:37): [True: 0, False: 0]
Branch (638:60): [True: 0, False: 0]
Branch (638:24): [True: 8, False: 0]
Branch (638:37): [True: 8, False: 0]
Branch (638:60): [True: 8, False: 0]
|
639 | | // make rounding cases |
640 | 20 | if (c > '4') { Branch (640:21): [True: 0, False: 4]
Branch (640:21): [True: 4, False: 0]
Branch (640:21): [True: 4, False: 0]
Branch (640:21): [True: 0, False: 0]
Branch (640:21): [True: 0, False: 8]
|
641 | 8 | value += 1; |
642 | 8 | } |
643 | 20 | has_round = true; |
644 | 20 | continue; |
645 | 20 | } else if (!found_dot) { Branch (645:24): [True: 0, False: 10]
Branch (645:24): [True: 0, False: 6]
Branch (645:24): [True: 0, False: 0]
Branch (645:24): [True: 0, False: 0]
Branch (645:24): [True: 0, False: 0]
|
646 | 0 | ++cur_digit; |
647 | 0 | } |
648 | 3.83k | DCHECK(value >= 0); // For some reason //DCHECK_GE doesn't work with __int128. |
649 | 3.83k | } else if (c == '.' && LIKELY(!found_dot)) {Line | Count | Source | 35 | 28 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 28, False: 0]
|
| } else if (c == '.' && LIKELY(!found_dot)) {Line | Count | Source | 35 | 32 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 32, False: 0]
|
| } else if (c == '.' && LIKELY(!found_dot)) {Line | Count | Source | 35 | 26 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 26, False: 0]
|
| } else if (c == '.' && LIKELY(!found_dot)) {Line | Count | Source | 35 | 1 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1, False: 0]
|
| } else if (c == '.' && LIKELY(!found_dot)) {Line | Count | Source | 35 | 107 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 107, False: 0]
|
Branch (649:20): [True: 28, False: 12]
Branch (649:20): [True: 32, False: 2]
Branch (649:20): [True: 26, False: 0]
Branch (649:20): [True: 1, False: 0]
Branch (649:20): [True: 107, False: 11]
|
650 | 194 | found_dot = 1; |
651 | 194 | } else if ((c == 'e' || c == 'E') && LIKELY(!found_exponent)) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
| } else if ((c == 'e' || c == 'E') && LIKELY(!found_exponent)) {Line | Count | Source | 35 | 1 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1, False: 0]
|
| } else if ((c == 'e' || c == 'E') && LIKELY(!found_exponent)) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
| } else if ((c == 'e' || c == 'E') && LIKELY(!found_exponent)) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
| } else if ((c == 'e' || c == 'E') && LIKELY(!found_exponent)) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
Branch (651:21): [True: 0, False: 12]
Branch (651:33): [True: 0, False: 12]
Branch (651:21): [True: 1, False: 1]
Branch (651:33): [True: 0, False: 1]
Branch (651:21): [True: 0, False: 0]
Branch (651:33): [True: 0, False: 0]
Branch (651:21): [True: 0, False: 0]
Branch (651:33): [True: 0, False: 0]
Branch (651:21): [True: 0, False: 11]
Branch (651:33): [True: 0, False: 11]
|
652 | 1 | found_exponent = true; |
653 | 1 | exponent = string_to_int_internal<int8_t>(s + i + 1, len - i - 1, result); |
654 | 1 | if (UNLIKELY(*result != StringParser::PARSE_SUCCESS)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(*result != StringParser::PARSE_SUCCESS)) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1]
|
| if (UNLIKELY(*result != StringParser::PARSE_SUCCESS)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(*result != StringParser::PARSE_SUCCESS)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(*result != StringParser::PARSE_SUCCESS)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
|
655 | 0 | if (*result == StringParser::PARSE_OVERFLOW && exponent < 0) { Branch (655:21): [True: 0, False: 0]
Branch (655:64): [True: 0, False: 0]
Branch (655:21): [True: 0, False: 0]
Branch (655:64): [True: 0, False: 0]
Branch (655:21): [True: 0, False: 0]
Branch (655:64): [True: 0, False: 0]
Branch (655:21): [True: 0, False: 0]
Branch (655:64): [True: 0, False: 0]
Branch (655:21): [True: 0, False: 0]
Branch (655:64): [True: 0, False: 0]
|
656 | 0 | *result = StringParser::PARSE_UNDERFLOW; |
657 | 0 | } |
658 | 0 | return 0; |
659 | 0 | } |
660 | 1 | break; |
661 | 24 | } else { |
662 | 24 | if (value == 0) { Branch (662:17): [True: 0, False: 12]
Branch (662:17): [True: 1, False: 0]
Branch (662:17): [True: 0, False: 0]
Branch (662:17): [True: 0, False: 0]
Branch (662:17): [True: 9, False: 2]
|
663 | 10 | *result = StringParser::PARSE_FAILURE; |
664 | 10 | return 0; |
665 | 10 | } |
666 | | // here to handle |
667 | 14 | *result = StringParser::PARSE_SUCCESS; |
668 | 14 | if (type_scale >= scale) { Branch (668:17): [True: 12, False: 0]
Branch (668:17): [True: 0, False: 0]
Branch (668:17): [True: 0, False: 0]
Branch (668:17): [True: 0, False: 0]
Branch (668:17): [True: 2, False: 0]
|
669 | 14 | value *= get_scale_multiplier<T>(type_scale - scale); |
670 | | // here meet non-valid character, should return the value, keep going to meet |
671 | | // the E/e character because we make right user-given type_precision |
672 | | // not max number type_precision |
673 | 14 | if (!is_numeric_ascii(c)) { Branch (673:21): [True: 12, False: 0]
Branch (673:21): [True: 0, False: 0]
Branch (673:21): [True: 0, False: 0]
Branch (673:21): [True: 0, False: 0]
Branch (673:21): [True: 2, False: 0]
|
674 | 14 | if (cur_digit > type_precision) { Branch (674:25): [True: 0, False: 12]
Branch (674:25): [True: 0, False: 0]
Branch (674:25): [True: 0, False: 0]
Branch (674:25): [True: 0, False: 0]
Branch (674:25): [True: 0, False: 2]
|
675 | 0 | *result = StringParser::PARSE_OVERFLOW; |
676 | 0 | value = is_negative Branch (676:33): [True: 0, False: 0]
Branch (676:33): [True: 0, False: 0]
Branch (676:33): [True: 0, False: 0]
Branch (676:33): [True: 0, False: 0]
Branch (676:33): [True: 0, False: 0]
|
677 | 0 | ? vectorized::min_decimal_value<DecimalType>(type_precision) |
678 | 0 | : vectorized::max_decimal_value<DecimalType>( |
679 | 0 | type_precision); |
680 | 0 | return value; |
681 | 0 | } |
682 | 14 | return is_negative ? T(-value) : T(value); Branch (682:28): [True: 6, False: 6]
Branch (682:28): [True: 0, False: 0]
Branch (682:28): [True: 0, False: 0]
Branch (682:28): [True: 0, False: 0]
Branch (682:28): [True: 0, False: 2]
|
683 | 14 | } |
684 | 14 | } |
685 | | |
686 | 0 | return is_negative ? T(-value) : T(value); Branch (686:20): [True: 0, False: 0]
Branch (686:20): [True: 0, False: 0]
Branch (686:20): [True: 0, False: 0]
Branch (686:20): [True: 0, False: 0]
Branch (686:20): [True: 0, False: 0]
|
687 | 14 | } |
688 | 4.07k | } |
689 | | |
690 | | // Find the number of truncated digits before adjusting the precision for an exponent. |
691 | 207 | if (exponent > scale) { Branch (691:9): [True: 0, False: 16]
Branch (691:9): [True: 1, False: 34]
Branch (691:9): [True: 0, False: 28]
Branch (691:9): [True: 0, False: 1]
Branch (691:9): [True: 0, False: 127]
|
692 | | // Ex: 0.1e3 (which at this point would have precision == 1 and scale == 1), the |
693 | | // scale must be set to 0 and the value set to 100 which means a precision of 3. |
694 | 1 | precision += exponent - scale; |
695 | | |
696 | 1 | value *= get_scale_multiplier<T>(exponent - scale); |
697 | 1 | scale = 0; |
698 | 206 | } else { |
699 | | // Ex: 100e-4, the scale must be set to 4 but no adjustment to the value is needed, |
700 | | // the precision must also be set to 4 but that will be done below for the |
701 | | // non-exponent case anyways. |
702 | 206 | scale -= exponent; |
703 | 206 | } |
704 | | // Ex: 0.001, at this point would have precision 1 and scale 3 since leading zeros |
705 | | // were ignored during previous parsing. |
706 | 207 | if (scale > precision) { Branch (706:9): [True: 0, False: 16]
Branch (706:9): [True: 1, False: 34]
Branch (706:9): [True: 0, False: 28]
Branch (706:9): [True: 0, False: 1]
Branch (706:9): [True: 3, False: 124]
|
707 | 4 | precision = scale; |
708 | 4 | } |
709 | | |
710 | | // Microbenchmarks show that beyond this point, returning on parse failure is slower |
711 | | // than just letting the function run out. |
712 | 127 | *result = StringParser::PARSE_SUCCESS; |
713 | 207 | if (UNLIKELY(precision - scale > type_precision - type_scale)) {Line | Count | Source | 36 | 16 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 4, False: 12]
|
| if (UNLIKELY(precision - scale > type_precision - type_scale)) {Line | Count | Source | 36 | 35 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 6, False: 29]
|
| if (UNLIKELY(precision - scale > type_precision - type_scale)) {Line | Count | Source | 36 | 28 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 2, False: 26]
|
| if (UNLIKELY(precision - scale > type_precision - type_scale)) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1]
|
| if (UNLIKELY(precision - scale > type_precision - type_scale)) {Line | Count | Source | 36 | 127 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 9, False: 118]
|
|
714 | 21 | *result = StringParser::PARSE_OVERFLOW; |
715 | 21 | if constexpr (TYPE_DECIMALV2 != P) { Branch (715:23): [Folded - Ignored]
Branch (715:23): [Folded - Ignored]
Branch (715:23): [Folded - Ignored]
Branch (715:23): [Folded - Ignored]
Branch (715:23): [Folded - Ignored]
|
716 | | // decimalv3 overflow will return max min value for type precision |
717 | 12 | value = is_negative ? vectorized::min_decimal_value<DecimalType>(type_precision) Branch (717:21): [True: 0, False: 4]
Branch (717:21): [True: 0, False: 6]
Branch (717:21): [True: 0, False: 2]
Branch (717:21): [True: 0, False: 0]
|
718 | 12 | : vectorized::max_decimal_value<DecimalType>(type_precision); |
719 | 12 | return value; |
720 | 12 | } |
721 | 186 | } else if (UNLIKELY(scale > type_scale)) {Line | Count | Source | 36 | 12 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 4, False: 8]
|
| } else if (UNLIKELY(scale > type_scale)) {Line | Count | Source | 36 | 29 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 29]
|
| } else if (UNLIKELY(scale > type_scale)) {Line | Count | Source | 36 | 26 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 8, False: 18]
|
| } else if (UNLIKELY(scale > type_scale)) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1]
|
| } else if (UNLIKELY(scale > type_scale)) {Line | Count | Source | 36 | 118 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 17, False: 101]
|
|
722 | 29 | *result = StringParser::PARSE_UNDERFLOW; |
723 | 29 | int shift = scale - type_scale; |
724 | 29 | T divisor = get_scale_multiplier<T>(shift); |
725 | 29 | if (UNLIKELY(divisor == std::numeric_limits<T>::max())) {Line | Count | Source | 36 | 4 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 4]
|
| if (UNLIKELY(divisor == std::numeric_limits<T>::max())) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(divisor == std::numeric_limits<T>::max())) {Line | Count | Source | 36 | 8 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 8]
|
| if (UNLIKELY(divisor == std::numeric_limits<T>::max())) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| if (UNLIKELY(divisor == std::numeric_limits<T>::max())) {Line | Count | Source | 36 | 17 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 17]
|
|
726 | 0 | value = 0; |
727 | 29 | } else { |
728 | 29 | T remainder = value % divisor; |
729 | 29 | value /= divisor; |
730 | 29 | if ((remainder > 0 ? T(remainder) : T(-remainder)) >= (divisor >> 1)) { Branch (730:17): [True: 0, False: 4]
Branch (730:18): [True: 4, False: 0]
Branch (730:17): [True: 0, False: 0]
Branch (730:18): [True: 0, False: 0]
Branch (730:17): [True: 8, False: 0]
Branch (730:18): [True: 8, False: 0]
Branch (730:17): [True: 0, False: 0]
Branch (730:18): [True: 0, False: 0]
Branch (730:17): [True: 17, False: 0]
Branch (730:18): [True: 17, False: 0]
|
731 | 25 | value += 1; |
732 | 25 | } |
733 | 29 | } |
734 | 29 | DCHECK(value >= 0); // //DCHECK_GE doesn't work with __int128. |
735 | 157 | } else if (UNLIKELY(!found_value && !found_dot)) {Line | Count | Source | 36 | 8 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 8]
Branch (36:44): [True: 0, False: 8]
Branch (36:44): [True: 0, False: 0]
|
| } else if (UNLIKELY(!found_value && !found_dot)) {Line | Count | Source | 36 | 30 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 1, False: 28]
Branch (36:44): [True: 1, False: 28]
Branch (36:44): [True: 1, False: 0]
|
| } else if (UNLIKELY(!found_value && !found_dot)) {Line | Count | Source | 36 | 18 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 18]
Branch (36:44): [True: 0, False: 18]
Branch (36:44): [True: 0, False: 0]
|
| } else if (UNLIKELY(!found_value && !found_dot)) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1]
Branch (36:44): [True: 0, False: 1]
Branch (36:44): [True: 0, False: 0]
|
| } else if (UNLIKELY(!found_value && !found_dot)) {Line | Count | Source | 36 | 101 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 101]
Branch (36:44): [True: 0, False: 101]
Branch (36:44): [True: 0, False: 0]
|
|
736 | 1 | *result = StringParser::PARSE_FAILURE; |
737 | 1 | } |
738 | | |
739 | 195 | if (type_scale > scale) { Branch (739:9): [True: 0, False: 12]
Branch (739:9): [True: 6, False: 23]
Branch (739:9): [True: 4, False: 22]
Branch (739:9): [True: 0, False: 1]
Branch (739:9): [True: 78, False: 49]
|
740 | 88 | value *= get_scale_multiplier<T>(type_scale - scale); |
741 | 88 | } |
742 | | |
743 | 195 | return is_negative ? T(-value) : T(value); Branch (743:12): [True: 0, False: 12]
Branch (743:12): [True: 7, False: 22]
Branch (743:12): [True: 1, False: 25]
Branch (743:12): [True: 0, False: 1]
Branch (743:12): [True: 25, False: 102]
|
744 | 80 | } _ZN5doris12StringParser17string_to_decimalILNS_13PrimitiveTypeE28EiNS_10vectorized7DecimalIiEEEET0_PKciiiPNS0_11ParseResultE Line | Count | Source | 556 | 28 | int type_scale, ParseResult* result) { | 557 | 28 | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || | 558 | 28 | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, | 559 | 28 | "Cast string to decimal only support target type int32_t, int64_t, __int128 or " | 560 | 28 | "wide::Int256."); | 561 | | // Special cases: | 562 | | // 1) '' == Fail, an empty string fails to parse. | 563 | | // 2) ' # ' == #, leading and trailing white space is ignored. | 564 | | // 3) '.' == 0, a single dot parses as zero (for consistency with other types). | 565 | | // 4) '#.' == '#', a trailing dot is ignored. | 566 | | | 567 | | // Ignore leading and trailing spaces. | 568 | 28 | while (len > 0 && is_whitespace(*s)) { Branch (568:12): [True: 28, False: 0]
Branch (568:23): [True: 0, False: 28]
| 569 | 0 | ++s; | 570 | 0 | --len; | 571 | 0 | } | 572 | 28 | while (len > 0 && is_whitespace(s[len - 1])) { Branch (572:12): [True: 28, False: 0]
Branch (572:23): [True: 0, False: 28]
| 573 | 0 | --len; | 574 | 0 | } | 575 | | | 576 | 28 | bool is_negative = false; | 577 | 28 | if (len > 0) { Branch (577:9): [True: 28, False: 0]
| 578 | 28 | switch (*s) { Branch (578:17): [True: 22, False: 6]
| 579 | 6 | case '-': Branch (579:9): [True: 6, False: 22]
| 580 | 6 | is_negative = true; | 581 | 6 | [[fallthrough]]; | 582 | 6 | case '+': Branch (582:9): [True: 0, False: 28]
| 583 | 6 | ++s; | 584 | 6 | --len; | 585 | 28 | } | 586 | 28 | } | 587 | | | 588 | | // Ignore leading zeros. | 589 | 28 | bool found_value = false; | 590 | 28 | while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 28 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 28]
|
Branch (590:12): [True: 28, False: 0]
| 591 | 0 | found_value = true; | 592 | 0 | ++s; | 593 | 0 | --len; | 594 | 0 | } | 595 | | | 596 | | // Ignore leading zeros even after a dot. This allows for differentiating between | 597 | | // cases like 0.01e2, which would fit in a DECIMAL(1, 0), and 0.10e2, which would | 598 | | // overflow. | 599 | 28 | int scale = 0; | 600 | 28 | int found_dot = 0; | 601 | 28 | if (len > 0 && *s == '.') { Branch (601:9): [True: 28, False: 0]
Branch (601:20): [True: 0, False: 28]
| 602 | 0 | found_dot = 1; | 603 | 0 | ++s; | 604 | 0 | --len; | 605 | 0 | while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
Branch (605:16): [True: 0, False: 0]
| 606 | 0 | found_value = true; | 607 | 0 | ++scale; | 608 | 0 | ++s; | 609 | 0 | --len; | 610 | 0 | } | 611 | 0 | } | 612 | | | 613 | 28 | int precision = 0; | 614 | 28 | int max_digit = type_precision - type_scale; | 615 | 28 | int cur_digit = 0; | 616 | 28 | bool found_exponent = false; | 617 | 28 | int8_t exponent = 0; | 618 | 28 | T value = 0; | 619 | 28 | bool has_round = false; | 620 | 322 | for (int i = 0; i < len; ++i) { Branch (620:21): [True: 306, False: 16]
| 621 | 306 | const char& c = s[i]; | 622 | 306 | if (LIKELY('0' <= c && c <= '9')) {Line | Count | Source | 35 | 572 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 266, False: 40]
Branch (35:42): [True: 266, False: 40]
Branch (35:42): [True: 266, False: 0]
|
| 623 | 266 | found_value = true; | 624 | | // Ignore digits once the type's precision limit is reached. This avoids | 625 | | // overflowing the underlying storage while handling a string like | 626 | | // 10000000000e-10 into a DECIMAL(1, 0). Adjustments for ignored digits and | 627 | | // an exponent will be made later. | 628 | 266 | if (LIKELY(type_precision > precision) && !has_round) {Line | Count | Source | 35 | 532 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 252, False: 14]
|
Branch (628:55): [True: 252, False: 0]
| 629 | 252 | value = (value * 10) + (c - '0'); // Benchmarks are faster with parenthesis... | 630 | 252 | ++precision; | 631 | 252 | scale += found_dot; | 632 | 252 | cur_digit = precision - scale; | 633 | 252 | } else if (!found_dot && max_digit < (precision - scale)) { Branch (633:24): [True: 0, False: 14]
Branch (633:38): [True: 0, False: 0]
| 634 | 0 | *result = StringParser::PARSE_OVERFLOW; | 635 | 0 | value = is_negative ? vectorized::min_decimal_value<DecimalType>(type_precision) Branch (635:25): [True: 0, False: 0]
| 636 | 0 | : vectorized::max_decimal_value<DecimalType>(type_precision); | 637 | 0 | return value; | 638 | 14 | } else if (found_dot && scale >= type_scale && !has_round) { Branch (638:24): [True: 14, False: 0]
Branch (638:37): [True: 4, False: 10]
Branch (638:60): [True: 4, False: 0]
| 639 | | // make rounding cases | 640 | 4 | if (c > '4') { Branch (640:21): [True: 0, False: 4]
| 641 | 0 | value += 1; | 642 | 0 | } | 643 | 4 | has_round = true; | 644 | 4 | continue; | 645 | 10 | } else if (!found_dot) { Branch (645:24): [True: 0, False: 10]
| 646 | 0 | ++cur_digit; | 647 | 0 | } | 648 | 262 | DCHECK(value >= 0); // For some reason //DCHECK_GE doesn't work with __int128. | 649 | 262 | } else if (c == '.' && LIKELY(!found_dot)) {Line | Count | Source | 35 | 28 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 28, False: 0]
|
Branch (649:20): [True: 28, False: 12]
| 650 | 28 | found_dot = 1; | 651 | 28 | } else if ((c == 'e' || c == 'E') && LIKELY(!found_exponent)) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
Branch (651:21): [True: 0, False: 12]
Branch (651:33): [True: 0, False: 12]
| 652 | 0 | found_exponent = true; | 653 | 0 | exponent = string_to_int_internal<int8_t>(s + i + 1, len - i - 1, result); | 654 | 0 | if (UNLIKELY(*result != StringParser::PARSE_SUCCESS)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| 655 | 0 | if (*result == StringParser::PARSE_OVERFLOW && exponent < 0) { Branch (655:21): [True: 0, False: 0]
Branch (655:64): [True: 0, False: 0]
| 656 | 0 | *result = StringParser::PARSE_UNDERFLOW; | 657 | 0 | } | 658 | 0 | return 0; | 659 | 0 | } | 660 | 0 | break; | 661 | 12 | } else { | 662 | 12 | if (value == 0) { Branch (662:17): [True: 0, False: 12]
| 663 | 0 | *result = StringParser::PARSE_FAILURE; | 664 | 0 | return 0; | 665 | 0 | } | 666 | | // here to handle | 667 | 12 | *result = StringParser::PARSE_SUCCESS; | 668 | 12 | if (type_scale >= scale) { Branch (668:17): [True: 12, False: 0]
| 669 | 12 | value *= get_scale_multiplier<T>(type_scale - scale); | 670 | | // here meet non-valid character, should return the value, keep going to meet | 671 | | // the E/e character because we make right user-given type_precision | 672 | | // not max number type_precision | 673 | 12 | if (!is_numeric_ascii(c)) { Branch (673:21): [True: 12, False: 0]
| 674 | 12 | if (cur_digit > type_precision) { Branch (674:25): [True: 0, False: 12]
| 675 | 0 | *result = StringParser::PARSE_OVERFLOW; | 676 | 0 | value = is_negative Branch (676:33): [True: 0, False: 0]
| 677 | 0 | ? vectorized::min_decimal_value<DecimalType>(type_precision) | 678 | 0 | : vectorized::max_decimal_value<DecimalType>( | 679 | 0 | type_precision); | 680 | 0 | return value; | 681 | 0 | } | 682 | 12 | return is_negative ? T(-value) : T(value); Branch (682:28): [True: 6, False: 6]
| 683 | 12 | } | 684 | 12 | } | 685 | | | 686 | 0 | return is_negative ? T(-value) : T(value); Branch (686:20): [True: 0, False: 0]
| 687 | 12 | } | 688 | 306 | } | 689 | | | 690 | | // Find the number of truncated digits before adjusting the precision for an exponent. | 691 | 16 | if (exponent > scale) { Branch (691:9): [True: 0, False: 16]
| 692 | | // Ex: 0.1e3 (which at this point would have precision == 1 and scale == 1), the | 693 | | // scale must be set to 0 and the value set to 100 which means a precision of 3. | 694 | 0 | precision += exponent - scale; | 695 | |
| 696 | 0 | value *= get_scale_multiplier<T>(exponent - scale); | 697 | 0 | scale = 0; | 698 | 16 | } else { | 699 | | // Ex: 100e-4, the scale must be set to 4 but no adjustment to the value is needed, | 700 | | // the precision must also be set to 4 but that will be done below for the | 701 | | // non-exponent case anyways. | 702 | 16 | scale -= exponent; | 703 | 16 | } | 704 | | // Ex: 0.001, at this point would have precision 1 and scale 3 since leading zeros | 705 | | // were ignored during previous parsing. | 706 | 16 | if (scale > precision) { Branch (706:9): [True: 0, False: 16]
| 707 | 0 | precision = scale; | 708 | 0 | } | 709 | | | 710 | | // Microbenchmarks show that beyond this point, returning on parse failure is slower | 711 | | // than just letting the function run out. | 712 | 16 | *result = StringParser::PARSE_SUCCESS; | 713 | 16 | if (UNLIKELY(precision - scale > type_precision - type_scale)) {Line | Count | Source | 36 | 16 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 4, False: 12]
|
| 714 | 4 | *result = StringParser::PARSE_OVERFLOW; | 715 | 4 | if constexpr (TYPE_DECIMALV2 != P) { Branch (715:23): [Folded - Ignored]
| 716 | | // decimalv3 overflow will return max min value for type precision | 717 | 4 | value = is_negative ? vectorized::min_decimal_value<DecimalType>(type_precision) Branch (717:21): [True: 0, False: 4]
| 718 | 4 | : vectorized::max_decimal_value<DecimalType>(type_precision); | 719 | 4 | return value; | 720 | 4 | } | 721 | 12 | } else if (UNLIKELY(scale > type_scale)) {Line | Count | Source | 36 | 12 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 4, False: 8]
|
| 722 | 4 | *result = StringParser::PARSE_UNDERFLOW; | 723 | 4 | int shift = scale - type_scale; | 724 | 4 | T divisor = get_scale_multiplier<T>(shift); | 725 | 4 | if (UNLIKELY(divisor == std::numeric_limits<T>::max())) {Line | Count | Source | 36 | 4 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 4]
|
| 726 | 0 | value = 0; | 727 | 4 | } else { | 728 | 4 | T remainder = value % divisor; | 729 | 4 | value /= divisor; | 730 | 4 | if ((remainder > 0 ? T(remainder) : T(-remainder)) >= (divisor >> 1)) { Branch (730:17): [True: 0, False: 4]
Branch (730:18): [True: 4, False: 0]
| 731 | 0 | value += 1; | 732 | 0 | } | 733 | 4 | } | 734 | 4 | DCHECK(value >= 0); // //DCHECK_GE doesn't work with __int128. | 735 | 8 | } else if (UNLIKELY(!found_value && !found_dot)) {Line | Count | Source | 36 | 8 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 8]
Branch (36:44): [True: 0, False: 8]
Branch (36:44): [True: 0, False: 0]
|
| 736 | 0 | *result = StringParser::PARSE_FAILURE; | 737 | 0 | } | 738 | | | 739 | 12 | if (type_scale > scale) { Branch (739:9): [True: 0, False: 12]
| 740 | 0 | value *= get_scale_multiplier<T>(type_scale - scale); | 741 | 0 | } | 742 | | | 743 | 12 | return is_negative ? T(-value) : T(value); Branch (743:12): [True: 0, False: 12]
| 744 | 16 | } |
_ZN5doris12StringParser17string_to_decimalILNS_13PrimitiveTypeE29ElNS_10vectorized7DecimalIlEEEET0_PKciiiPNS0_11ParseResultE Line | Count | Source | 556 | 36 | int type_scale, ParseResult* result) { | 557 | 36 | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || | 558 | 36 | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, | 559 | 36 | "Cast string to decimal only support target type int32_t, int64_t, __int128 or " | 560 | 36 | "wide::Int256."); | 561 | | // Special cases: | 562 | | // 1) '' == Fail, an empty string fails to parse. | 563 | | // 2) ' # ' == #, leading and trailing white space is ignored. | 564 | | // 3) '.' == 0, a single dot parses as zero (for consistency with other types). | 565 | | // 4) '#.' == '#', a trailing dot is ignored. | 566 | | | 567 | | // Ignore leading and trailing spaces. | 568 | 36 | while (len > 0 && is_whitespace(*s)) { Branch (568:12): [True: 35, False: 1]
Branch (568:23): [True: 0, False: 35]
| 569 | 0 | ++s; | 570 | 0 | --len; | 571 | 0 | } | 572 | 36 | while (len > 0 && is_whitespace(s[len - 1])) { Branch (572:12): [True: 35, False: 1]
Branch (572:23): [True: 0, False: 35]
| 573 | 0 | --len; | 574 | 0 | } | 575 | | | 576 | 36 | bool is_negative = false; | 577 | 36 | if (len > 0) { Branch (577:9): [True: 35, False: 1]
| 578 | 35 | switch (*s) { Branch (578:17): [True: 28, False: 7]
| 579 | 7 | case '-': Branch (579:9): [True: 7, False: 28]
| 580 | 7 | is_negative = true; | 581 | 7 | [[fallthrough]]; | 582 | 7 | case '+': Branch (582:9): [True: 0, False: 35]
| 583 | 7 | ++s; | 584 | 7 | --len; | 585 | 35 | } | 586 | 35 | } | 587 | | | 588 | | // Ignore leading zeros. | 589 | 36 | bool found_value = false; | 590 | 37 | while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 36 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 1, False: 35]
|
Branch (590:12): [True: 36, False: 1]
| 591 | 1 | found_value = true; | 592 | 1 | ++s; | 593 | 1 | --len; | 594 | 1 | } | 595 | | | 596 | | // Ignore leading zeros even after a dot. This allows for differentiating between | 597 | | // cases like 0.01e2, which would fit in a DECIMAL(1, 0), and 0.10e2, which would | 598 | | // overflow. | 599 | 36 | int scale = 0; | 600 | 36 | int found_dot = 0; | 601 | 36 | if (len > 0 && *s == '.') { Branch (601:9): [True: 35, False: 1]
Branch (601:20): [True: 1, False: 34]
| 602 | 1 | found_dot = 1; | 603 | 1 | ++s; | 604 | 1 | --len; | 605 | 2 | while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 1, False: 0]
|
Branch (605:16): [True: 1, False: 1]
| 606 | 1 | found_value = true; | 607 | 1 | ++scale; | 608 | 1 | ++s; | 609 | 1 | --len; | 610 | 1 | } | 611 | 1 | } | 612 | | | 613 | 36 | int precision = 0; | 614 | 36 | int max_digit = type_precision - type_scale; | 615 | 36 | int cur_digit = 0; | 616 | 36 | bool found_exponent = false; | 617 | 36 | int8_t exponent = 0; | 618 | 36 | T value = 0; | 619 | 36 | bool has_round = false; | 620 | 559 | for (int i = 0; i < len; ++i) { Branch (620:21): [True: 525, False: 34]
| 621 | 525 | const char& c = s[i]; | 622 | 525 | if (LIKELY('0' <= c && c <= '9')) {Line | Count | Source | 35 | 1.01k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 491, False: 34]
Branch (35:42): [True: 493, False: 32]
Branch (35:42): [True: 491, False: 2]
|
| 623 | 491 | found_value = true; | 624 | | // Ignore digits once the type's precision limit is reached. This avoids | 625 | | // overflowing the underlying storage while handling a string like | 626 | | // 10000000000e-10 into a DECIMAL(1, 0). Adjustments for ignored digits and | 627 | | // an exponent will be made later. | 628 | 491 | if (LIKELY(type_precision > precision) && !has_round) {Line | Count | Source | 35 | 982 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 481, False: 10]
|
Branch (628:55): [True: 481, False: 0]
| 629 | 481 | value = (value * 10) + (c - '0'); // Benchmarks are faster with parenthesis... | 630 | 481 | ++precision; | 631 | 481 | scale += found_dot; | 632 | 481 | cur_digit = precision - scale; | 633 | 481 | } else if (!found_dot && max_digit < (precision - scale)) { Branch (633:24): [True: 0, False: 10]
Branch (633:38): [True: 0, False: 0]
| 634 | 0 | *result = StringParser::PARSE_OVERFLOW; | 635 | 0 | value = is_negative ? vectorized::min_decimal_value<DecimalType>(type_precision) Branch (635:25): [True: 0, False: 0]
| 636 | 0 | : vectorized::max_decimal_value<DecimalType>(type_precision); | 637 | 0 | return value; | 638 | 10 | } else if (found_dot && scale >= type_scale && !has_round) { Branch (638:24): [True: 10, False: 0]
Branch (638:37): [True: 4, False: 6]
Branch (638:60): [True: 4, False: 0]
| 639 | | // make rounding cases | 640 | 4 | if (c > '4') { Branch (640:21): [True: 4, False: 0]
| 641 | 4 | value += 1; | 642 | 4 | } | 643 | 4 | has_round = true; | 644 | 4 | continue; | 645 | 6 | } else if (!found_dot) { Branch (645:24): [True: 0, False: 6]
| 646 | 0 | ++cur_digit; | 647 | 0 | } | 648 | 487 | DCHECK(value >= 0); // For some reason //DCHECK_GE doesn't work with __int128. | 649 | 487 | } else if (c == '.' && LIKELY(!found_dot)) {Line | Count | Source | 35 | 32 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 32, False: 0]
|
Branch (649:20): [True: 32, False: 2]
| 650 | 32 | found_dot = 1; | 651 | 32 | } else if ((c == 'e' || c == 'E') && LIKELY(!found_exponent)) {Line | Count | Source | 35 | 1 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1, False: 0]
|
Branch (651:21): [True: 1, False: 1]
Branch (651:33): [True: 0, False: 1]
| 652 | 1 | found_exponent = true; | 653 | 1 | exponent = string_to_int_internal<int8_t>(s + i + 1, len - i - 1, result); | 654 | 1 | if (UNLIKELY(*result != StringParser::PARSE_SUCCESS)) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1]
|
| 655 | 0 | if (*result == StringParser::PARSE_OVERFLOW && exponent < 0) { Branch (655:21): [True: 0, False: 0]
Branch (655:64): [True: 0, False: 0]
| 656 | 0 | *result = StringParser::PARSE_UNDERFLOW; | 657 | 0 | } | 658 | 0 | return 0; | 659 | 0 | } | 660 | 1 | break; | 661 | 1 | } else { | 662 | 1 | if (value == 0) { Branch (662:17): [True: 1, False: 0]
| 663 | 1 | *result = StringParser::PARSE_FAILURE; | 664 | 1 | return 0; | 665 | 1 | } | 666 | | // here to handle | 667 | 0 | *result = StringParser::PARSE_SUCCESS; | 668 | 0 | if (type_scale >= scale) { Branch (668:17): [True: 0, False: 0]
| 669 | 0 | value *= get_scale_multiplier<T>(type_scale - scale); | 670 | | // here meet non-valid character, should return the value, keep going to meet | 671 | | // the E/e character because we make right user-given type_precision | 672 | | // not max number type_precision | 673 | 0 | if (!is_numeric_ascii(c)) { Branch (673:21): [True: 0, False: 0]
| 674 | 0 | if (cur_digit > type_precision) { Branch (674:25): [True: 0, False: 0]
| 675 | 0 | *result = StringParser::PARSE_OVERFLOW; | 676 | 0 | value = is_negative Branch (676:33): [True: 0, False: 0]
| 677 | 0 | ? vectorized::min_decimal_value<DecimalType>(type_precision) | 678 | 0 | : vectorized::max_decimal_value<DecimalType>( | 679 | 0 | type_precision); | 680 | 0 | return value; | 681 | 0 | } | 682 | 0 | return is_negative ? T(-value) : T(value); Branch (682:28): [True: 0, False: 0]
| 683 | 0 | } | 684 | 0 | } | 685 | | | 686 | 0 | return is_negative ? T(-value) : T(value); Branch (686:20): [True: 0, False: 0]
| 687 | 0 | } | 688 | 525 | } | 689 | | | 690 | | // Find the number of truncated digits before adjusting the precision for an exponent. | 691 | 35 | if (exponent > scale) { Branch (691:9): [True: 1, False: 34]
| 692 | | // Ex: 0.1e3 (which at this point would have precision == 1 and scale == 1), the | 693 | | // scale must be set to 0 and the value set to 100 which means a precision of 3. | 694 | 1 | precision += exponent - scale; | 695 | | | 696 | 1 | value *= get_scale_multiplier<T>(exponent - scale); | 697 | 1 | scale = 0; | 698 | 34 | } else { | 699 | | // Ex: 100e-4, the scale must be set to 4 but no adjustment to the value is needed, | 700 | | // the precision must also be set to 4 but that will be done below for the | 701 | | // non-exponent case anyways. | 702 | 34 | scale -= exponent; | 703 | 34 | } | 704 | | // Ex: 0.001, at this point would have precision 1 and scale 3 since leading zeros | 705 | | // were ignored during previous parsing. | 706 | 35 | if (scale > precision) { Branch (706:9): [True: 1, False: 34]
| 707 | 1 | precision = scale; | 708 | 1 | } | 709 | | | 710 | | // Microbenchmarks show that beyond this point, returning on parse failure is slower | 711 | | // than just letting the function run out. | 712 | 35 | *result = StringParser::PARSE_SUCCESS; | 713 | 35 | if (UNLIKELY(precision - scale > type_precision - type_scale)) {Line | Count | Source | 36 | 35 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 6, False: 29]
|
| 714 | 6 | *result = StringParser::PARSE_OVERFLOW; | 715 | 6 | if constexpr (TYPE_DECIMALV2 != P) { Branch (715:23): [Folded - Ignored]
| 716 | | // decimalv3 overflow will return max min value for type precision | 717 | 6 | value = is_negative ? vectorized::min_decimal_value<DecimalType>(type_precision) Branch (717:21): [True: 0, False: 6]
| 718 | 6 | : vectorized::max_decimal_value<DecimalType>(type_precision); | 719 | 6 | return value; | 720 | 6 | } | 721 | 29 | } else if (UNLIKELY(scale > type_scale)) {Line | Count | Source | 36 | 29 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 29]
|
| 722 | 0 | *result = StringParser::PARSE_UNDERFLOW; | 723 | 0 | int shift = scale - type_scale; | 724 | 0 | T divisor = get_scale_multiplier<T>(shift); | 725 | 0 | if (UNLIKELY(divisor == std::numeric_limits<T>::max())) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| 726 | 0 | value = 0; | 727 | 0 | } else { | 728 | 0 | T remainder = value % divisor; | 729 | 0 | value /= divisor; | 730 | 0 | if ((remainder > 0 ? T(remainder) : T(-remainder)) >= (divisor >> 1)) { Branch (730:17): [True: 0, False: 0]
Branch (730:18): [True: 0, False: 0]
| 731 | 0 | value += 1; | 732 | 0 | } | 733 | 0 | } | 734 | 0 | DCHECK(value >= 0); // //DCHECK_GE doesn't work with __int128. | 735 | 29 | } else if (UNLIKELY(!found_value && !found_dot)) {Line | Count | Source | 36 | 30 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 1, False: 28]
Branch (36:44): [True: 1, False: 28]
Branch (36:44): [True: 1, False: 0]
|
| 736 | 1 | *result = StringParser::PARSE_FAILURE; | 737 | 1 | } | 738 | | | 739 | 29 | if (type_scale > scale) { Branch (739:9): [True: 6, False: 23]
| 740 | 6 | value *= get_scale_multiplier<T>(type_scale - scale); | 741 | 6 | } | 742 | | | 743 | 29 | return is_negative ? T(-value) : T(value); Branch (743:12): [True: 7, False: 22]
| 744 | 35 | } |
_ZN5doris12StringParser17string_to_decimalILNS_13PrimitiveTypeE30EnNS_10vectorized12Decimal128V3EEET0_PKciiiPNS0_11ParseResultE Line | Count | Source | 556 | 28 | int type_scale, ParseResult* result) { | 557 | 28 | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || | 558 | 28 | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, | 559 | 28 | "Cast string to decimal only support target type int32_t, int64_t, __int128 or " | 560 | 28 | "wide::Int256."); | 561 | | // Special cases: | 562 | | // 1) '' == Fail, an empty string fails to parse. | 563 | | // 2) ' # ' == #, leading and trailing white space is ignored. | 564 | | // 3) '.' == 0, a single dot parses as zero (for consistency with other types). | 565 | | // 4) '#.' == '#', a trailing dot is ignored. | 566 | | | 567 | | // Ignore leading and trailing spaces. | 568 | 28 | while (len > 0 && is_whitespace(*s)) { Branch (568:12): [True: 28, False: 0]
Branch (568:23): [True: 0, False: 28]
| 569 | 0 | ++s; | 570 | 0 | --len; | 571 | 0 | } | 572 | 28 | while (len > 0 && is_whitespace(s[len - 1])) { Branch (572:12): [True: 28, False: 0]
Branch (572:23): [True: 0, False: 28]
| 573 | 0 | --len; | 574 | 0 | } | 575 | | | 576 | 28 | bool is_negative = false; | 577 | 28 | if (len > 0) { Branch (577:9): [True: 28, False: 0]
| 578 | 28 | switch (*s) { Branch (578:17): [True: 27, False: 1]
| 579 | 1 | case '-': Branch (579:9): [True: 1, False: 27]
| 580 | 1 | is_negative = true; | 581 | 1 | [[fallthrough]]; | 582 | 1 | case '+': Branch (582:9): [True: 0, False: 28]
| 583 | 1 | ++s; | 584 | 1 | --len; | 585 | 28 | } | 586 | 28 | } | 587 | | | 588 | | // Ignore leading zeros. | 589 | 28 | bool found_value = false; | 590 | 32 | while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 32 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 4, False: 28]
|
Branch (590:12): [True: 32, False: 0]
| 591 | 4 | found_value = true; | 592 | 4 | ++s; | 593 | 4 | --len; | 594 | 4 | } | 595 | | | 596 | | // Ignore leading zeros even after a dot. This allows for differentiating between | 597 | | // cases like 0.01e2, which would fit in a DECIMAL(1, 0), and 0.10e2, which would | 598 | | // overflow. | 599 | 28 | int scale = 0; | 600 | 28 | int found_dot = 0; | 601 | 28 | if (len > 0 && *s == '.') { Branch (601:9): [True: 28, False: 0]
Branch (601:20): [True: 0, False: 28]
| 602 | 0 | found_dot = 1; | 603 | 0 | ++s; | 604 | 0 | --len; | 605 | 0 | while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
Branch (605:16): [True: 0, False: 0]
| 606 | 0 | found_value = true; | 607 | 0 | ++scale; | 608 | 0 | ++s; | 609 | 0 | --len; | 610 | 0 | } | 611 | 0 | } | 612 | | | 613 | 28 | int precision = 0; | 614 | 28 | int max_digit = type_precision - type_scale; | 615 | 28 | int cur_digit = 0; | 616 | 28 | bool found_exponent = false; | 617 | 28 | int8_t exponent = 0; | 618 | 28 | T value = 0; | 619 | 28 | bool has_round = false; | 620 | 1.07k | for (int i = 0; i < len; ++i) { Branch (620:21): [True: 1.04k, False: 28]
| 621 | 1.04k | const char& c = s[i]; | 622 | 1.04k | if (LIKELY('0' <= c && c <= '9')) {Line | Count | Source | 35 | 2.05k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.01k, False: 26]
Branch (35:42): [True: 1.01k, False: 26]
Branch (35:42): [True: 1.01k, False: 0]
|
| 623 | 1.01k | found_value = true; | 624 | | // Ignore digits once the type's precision limit is reached. This avoids | 625 | | // overflowing the underlying storage while handling a string like | 626 | | // 10000000000e-10 into a DECIMAL(1, 0). Adjustments for ignored digits and | 627 | | // an exponent will be made later. | 628 | 1.01k | if (LIKELY(type_precision > precision) && !has_round) {Line | Count | Source | 35 | 2.03k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.01k, False: 4]
|
Branch (628:55): [True: 1.01k, False: 0]
| 629 | 1.01k | value = (value * 10) + (c - '0'); // Benchmarks are faster with parenthesis... | 630 | 1.01k | ++precision; | 631 | 1.01k | scale += found_dot; | 632 | 1.01k | cur_digit = precision - scale; | 633 | 1.01k | } else if (!found_dot && max_digit < (precision - scale)) { Branch (633:24): [True: 0, False: 4]
Branch (633:38): [True: 0, False: 0]
| 634 | 0 | *result = StringParser::PARSE_OVERFLOW; | 635 | 0 | value = is_negative ? vectorized::min_decimal_value<DecimalType>(type_precision) Branch (635:25): [True: 0, False: 0]
| 636 | 0 | : vectorized::max_decimal_value<DecimalType>(type_precision); | 637 | 0 | return value; | 638 | 4 | } else if (found_dot && scale >= type_scale && !has_round) { Branch (638:24): [True: 4, False: 0]
Branch (638:37): [True: 4, False: 0]
Branch (638:60): [True: 4, False: 0]
| 639 | | // make rounding cases | 640 | 4 | if (c > '4') { Branch (640:21): [True: 4, False: 0]
| 641 | 4 | value += 1; | 642 | 4 | } | 643 | 4 | has_round = true; | 644 | 4 | continue; | 645 | 4 | } else if (!found_dot) { Branch (645:24): [True: 0, False: 0]
| 646 | 0 | ++cur_digit; | 647 | 0 | } | 648 | 1.01k | DCHECK(value >= 0); // For some reason //DCHECK_GE doesn't work with __int128. | 649 | 1.01k | } else if (c == '.' && LIKELY(!found_dot)) {Line | Count | Source | 35 | 26 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 26, False: 0]
|
Branch (649:20): [True: 26, False: 0]
| 650 | 26 | found_dot = 1; | 651 | 26 | } else if ((c == 'e' || c == 'E') && LIKELY(!found_exponent)) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
Branch (651:21): [True: 0, False: 0]
Branch (651:33): [True: 0, False: 0]
| 652 | 0 | found_exponent = true; | 653 | 0 | exponent = string_to_int_internal<int8_t>(s + i + 1, len - i - 1, result); | 654 | 0 | if (UNLIKELY(*result != StringParser::PARSE_SUCCESS)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| 655 | 0 | if (*result == StringParser::PARSE_OVERFLOW && exponent < 0) { Branch (655:21): [True: 0, False: 0]
Branch (655:64): [True: 0, False: 0]
| 656 | 0 | *result = StringParser::PARSE_UNDERFLOW; | 657 | 0 | } | 658 | 0 | return 0; | 659 | 0 | } | 660 | 0 | break; | 661 | 0 | } else { | 662 | 0 | if (value == 0) { Branch (662:17): [True: 0, False: 0]
| 663 | 0 | *result = StringParser::PARSE_FAILURE; | 664 | 0 | return 0; | 665 | 0 | } | 666 | | // here to handle | 667 | 0 | *result = StringParser::PARSE_SUCCESS; | 668 | 0 | if (type_scale >= scale) { Branch (668:17): [True: 0, False: 0]
| 669 | 0 | value *= get_scale_multiplier<T>(type_scale - scale); | 670 | | // here meet non-valid character, should return the value, keep going to meet | 671 | | // the E/e character because we make right user-given type_precision | 672 | | // not max number type_precision | 673 | 0 | if (!is_numeric_ascii(c)) { Branch (673:21): [True: 0, False: 0]
| 674 | 0 | if (cur_digit > type_precision) { Branch (674:25): [True: 0, False: 0]
| 675 | 0 | *result = StringParser::PARSE_OVERFLOW; | 676 | 0 | value = is_negative Branch (676:33): [True: 0, False: 0]
| 677 | 0 | ? vectorized::min_decimal_value<DecimalType>(type_precision) | 678 | 0 | : vectorized::max_decimal_value<DecimalType>( | 679 | 0 | type_precision); | 680 | 0 | return value; | 681 | 0 | } | 682 | 0 | return is_negative ? T(-value) : T(value); Branch (682:28): [True: 0, False: 0]
| 683 | 0 | } | 684 | 0 | } | 685 | | | 686 | 0 | return is_negative ? T(-value) : T(value); Branch (686:20): [True: 0, False: 0]
| 687 | 0 | } | 688 | 1.04k | } | 689 | | | 690 | | // Find the number of truncated digits before adjusting the precision for an exponent. | 691 | 28 | if (exponent > scale) { Branch (691:9): [True: 0, False: 28]
| 692 | | // Ex: 0.1e3 (which at this point would have precision == 1 and scale == 1), the | 693 | | // scale must be set to 0 and the value set to 100 which means a precision of 3. | 694 | 0 | precision += exponent - scale; | 695 | |
| 696 | 0 | value *= get_scale_multiplier<T>(exponent - scale); | 697 | 0 | scale = 0; | 698 | 28 | } else { | 699 | | // Ex: 100e-4, the scale must be set to 4 but no adjustment to the value is needed, | 700 | | // the precision must also be set to 4 but that will be done below for the | 701 | | // non-exponent case anyways. | 702 | 28 | scale -= exponent; | 703 | 28 | } | 704 | | // Ex: 0.001, at this point would have precision 1 and scale 3 since leading zeros | 705 | | // were ignored during previous parsing. | 706 | 28 | if (scale > precision) { Branch (706:9): [True: 0, False: 28]
| 707 | 0 | precision = scale; | 708 | 0 | } | 709 | | | 710 | | // Microbenchmarks show that beyond this point, returning on parse failure is slower | 711 | | // than just letting the function run out. | 712 | 28 | *result = StringParser::PARSE_SUCCESS; | 713 | 28 | if (UNLIKELY(precision - scale > type_precision - type_scale)) {Line | Count | Source | 36 | 28 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 2, False: 26]
|
| 714 | 2 | *result = StringParser::PARSE_OVERFLOW; | 715 | 2 | if constexpr (TYPE_DECIMALV2 != P) { Branch (715:23): [Folded - Ignored]
| 716 | | // decimalv3 overflow will return max min value for type precision | 717 | 2 | value = is_negative ? vectorized::min_decimal_value<DecimalType>(type_precision) Branch (717:21): [True: 0, False: 2]
| 718 | 2 | : vectorized::max_decimal_value<DecimalType>(type_precision); | 719 | 2 | return value; | 720 | 2 | } | 721 | 26 | } else if (UNLIKELY(scale > type_scale)) {Line | Count | Source | 36 | 26 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 8, False: 18]
|
| 722 | 8 | *result = StringParser::PARSE_UNDERFLOW; | 723 | 8 | int shift = scale - type_scale; | 724 | 8 | T divisor = get_scale_multiplier<T>(shift); | 725 | 8 | if (UNLIKELY(divisor == std::numeric_limits<T>::max())) {Line | Count | Source | 36 | 8 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 8]
|
| 726 | 0 | value = 0; | 727 | 8 | } else { | 728 | 8 | T remainder = value % divisor; | 729 | 8 | value /= divisor; | 730 | 8 | if ((remainder > 0 ? T(remainder) : T(-remainder)) >= (divisor >> 1)) { Branch (730:17): [True: 8, False: 0]
Branch (730:18): [True: 8, False: 0]
| 731 | 8 | value += 1; | 732 | 8 | } | 733 | 8 | } | 734 | 8 | DCHECK(value >= 0); // //DCHECK_GE doesn't work with __int128. | 735 | 18 | } else if (UNLIKELY(!found_value && !found_dot)) {Line | Count | Source | 36 | 18 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 18]
Branch (36:44): [True: 0, False: 18]
Branch (36:44): [True: 0, False: 0]
|
| 736 | 0 | *result = StringParser::PARSE_FAILURE; | 737 | 0 | } | 738 | | | 739 | 26 | if (type_scale > scale) { Branch (739:9): [True: 4, False: 22]
| 740 | 4 | value *= get_scale_multiplier<T>(type_scale - scale); | 741 | 4 | } | 742 | | | 743 | 26 | return is_negative ? T(-value) : T(value); Branch (743:12): [True: 1, False: 25]
| 744 | 28 | } |
_ZN5doris12StringParser17string_to_decimalILNS_13PrimitiveTypeE35EN4wide7integerILm256EiEENS_10vectorized7DecimalIS5_EEEET0_PKciiiPNS0_11ParseResultE Line | Count | Source | 556 | 1 | int type_scale, ParseResult* result) { | 557 | 1 | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || | 558 | 1 | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, | 559 | 1 | "Cast string to decimal only support target type int32_t, int64_t, __int128 or " | 560 | 1 | "wide::Int256."); | 561 | | // Special cases: | 562 | | // 1) '' == Fail, an empty string fails to parse. | 563 | | // 2) ' # ' == #, leading and trailing white space is ignored. | 564 | | // 3) '.' == 0, a single dot parses as zero (for consistency with other types). | 565 | | // 4) '#.' == '#', a trailing dot is ignored. | 566 | | | 567 | | // Ignore leading and trailing spaces. | 568 | 1 | while (len > 0 && is_whitespace(*s)) { Branch (568:12): [True: 1, False: 0]
Branch (568:23): [True: 0, False: 1]
| 569 | 0 | ++s; | 570 | 0 | --len; | 571 | 0 | } | 572 | 1 | while (len > 0 && is_whitespace(s[len - 1])) { Branch (572:12): [True: 1, False: 0]
Branch (572:23): [True: 0, False: 1]
| 573 | 0 | --len; | 574 | 0 | } | 575 | | | 576 | 1 | bool is_negative = false; | 577 | 1 | if (len > 0) { Branch (577:9): [True: 1, False: 0]
| 578 | 1 | switch (*s) { Branch (578:17): [True: 1, False: 0]
| 579 | 0 | case '-': Branch (579:9): [True: 0, False: 1]
| 580 | 0 | is_negative = true; | 581 | 0 | [[fallthrough]]; | 582 | 0 | case '+': Branch (582:9): [True: 0, False: 1]
| 583 | 0 | ++s; | 584 | 0 | --len; | 585 | 1 | } | 586 | 1 | } | 587 | | | 588 | | // Ignore leading zeros. | 589 | 1 | bool found_value = false; | 590 | 1 | while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1]
|
Branch (590:12): [True: 1, False: 0]
| 591 | 0 | found_value = true; | 592 | 0 | ++s; | 593 | 0 | --len; | 594 | 0 | } | 595 | | | 596 | | // Ignore leading zeros even after a dot. This allows for differentiating between | 597 | | // cases like 0.01e2, which would fit in a DECIMAL(1, 0), and 0.10e2, which would | 598 | | // overflow. | 599 | 1 | int scale = 0; | 600 | 1 | int found_dot = 0; | 601 | 1 | if (len > 0 && *s == '.') { Branch (601:9): [True: 1, False: 0]
Branch (601:20): [True: 0, False: 1]
| 602 | 0 | found_dot = 1; | 603 | 0 | ++s; | 604 | 0 | --len; | 605 | 0 | while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
Branch (605:16): [True: 0, False: 0]
| 606 | 0 | found_value = true; | 607 | 0 | ++scale; | 608 | 0 | ++s; | 609 | 0 | --len; | 610 | 0 | } | 611 | 0 | } | 612 | | | 613 | 1 | int precision = 0; | 614 | 1 | int max_digit = type_precision - type_scale; | 615 | 1 | int cur_digit = 0; | 616 | 1 | bool found_exponent = false; | 617 | 1 | int8_t exponent = 0; | 618 | 1 | T value = 0; | 619 | 1 | bool has_round = false; | 620 | 78 | for (int i = 0; i < len; ++i) { Branch (620:21): [True: 77, False: 1]
| 621 | 77 | const char& c = s[i]; | 622 | 77 | if (LIKELY('0' <= c && c <= '9')) {Line | Count | Source | 35 | 153 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 76, False: 1]
Branch (35:42): [True: 76, False: 1]
Branch (35:42): [True: 76, False: 0]
|
| 623 | 76 | found_value = true; | 624 | | // Ignore digits once the type's precision limit is reached. This avoids | 625 | | // overflowing the underlying storage while handling a string like | 626 | | // 10000000000e-10 into a DECIMAL(1, 0). Adjustments for ignored digits and | 627 | | // an exponent will be made later. | 628 | 76 | if (LIKELY(type_precision > precision) && !has_round) {Line | Count | Source | 35 | 152 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 76, False: 0]
|
Branch (628:55): [True: 76, False: 0]
| 629 | 76 | value = (value * 10) + (c - '0'); // Benchmarks are faster with parenthesis... | 630 | 76 | ++precision; | 631 | 76 | scale += found_dot; | 632 | 76 | cur_digit = precision - scale; | 633 | 76 | } else if (!found_dot && max_digit < (precision - scale)) { Branch (633:24): [True: 0, False: 0]
Branch (633:38): [True: 0, False: 0]
| 634 | 0 | *result = StringParser::PARSE_OVERFLOW; | 635 | 0 | value = is_negative ? vectorized::min_decimal_value<DecimalType>(type_precision) Branch (635:25): [True: 0, False: 0]
| 636 | 0 | : vectorized::max_decimal_value<DecimalType>(type_precision); | 637 | 0 | return value; | 638 | 0 | } else if (found_dot && scale >= type_scale && !has_round) { Branch (638:24): [True: 0, False: 0]
Branch (638:37): [True: 0, False: 0]
Branch (638:60): [True: 0, False: 0]
| 639 | | // make rounding cases | 640 | 0 | if (c > '4') { Branch (640:21): [True: 0, False: 0]
| 641 | 0 | value += 1; | 642 | 0 | } | 643 | 0 | has_round = true; | 644 | 0 | continue; | 645 | 0 | } else if (!found_dot) { Branch (645:24): [True: 0, False: 0]
| 646 | 0 | ++cur_digit; | 647 | 0 | } | 648 | 76 | DCHECK(value >= 0); // For some reason //DCHECK_GE doesn't work with __int128. | 649 | 76 | } else if (c == '.' && LIKELY(!found_dot)) {Line | Count | Source | 35 | 1 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1, False: 0]
|
Branch (649:20): [True: 1, False: 0]
| 650 | 1 | found_dot = 1; | 651 | 1 | } else if ((c == 'e' || c == 'E') && LIKELY(!found_exponent)) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
Branch (651:21): [True: 0, False: 0]
Branch (651:33): [True: 0, False: 0]
| 652 | 0 | found_exponent = true; | 653 | 0 | exponent = string_to_int_internal<int8_t>(s + i + 1, len - i - 1, result); | 654 | 0 | if (UNLIKELY(*result != StringParser::PARSE_SUCCESS)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| 655 | 0 | if (*result == StringParser::PARSE_OVERFLOW && exponent < 0) { Branch (655:21): [True: 0, False: 0]
Branch (655:64): [True: 0, False: 0]
| 656 | 0 | *result = StringParser::PARSE_UNDERFLOW; | 657 | 0 | } | 658 | 0 | return 0; | 659 | 0 | } | 660 | 0 | break; | 661 | 0 | } else { | 662 | 0 | if (value == 0) { Branch (662:17): [True: 0, False: 0]
| 663 | 0 | *result = StringParser::PARSE_FAILURE; | 664 | 0 | return 0; | 665 | 0 | } | 666 | | // here to handle | 667 | 0 | *result = StringParser::PARSE_SUCCESS; | 668 | 0 | if (type_scale >= scale) { Branch (668:17): [True: 0, False: 0]
| 669 | 0 | value *= get_scale_multiplier<T>(type_scale - scale); | 670 | | // here meet non-valid character, should return the value, keep going to meet | 671 | | // the E/e character because we make right user-given type_precision | 672 | | // not max number type_precision | 673 | 0 | if (!is_numeric_ascii(c)) { Branch (673:21): [True: 0, False: 0]
| 674 | 0 | if (cur_digit > type_precision) { Branch (674:25): [True: 0, False: 0]
| 675 | 0 | *result = StringParser::PARSE_OVERFLOW; | 676 | 0 | value = is_negative Branch (676:33): [True: 0, False: 0]
| 677 | 0 | ? vectorized::min_decimal_value<DecimalType>(type_precision) | 678 | 0 | : vectorized::max_decimal_value<DecimalType>( | 679 | 0 | type_precision); | 680 | 0 | return value; | 681 | 0 | } | 682 | 0 | return is_negative ? T(-value) : T(value); Branch (682:28): [True: 0, False: 0]
| 683 | 0 | } | 684 | 0 | } | 685 | | | 686 | 0 | return is_negative ? T(-value) : T(value); Branch (686:20): [True: 0, False: 0]
| 687 | 0 | } | 688 | 77 | } | 689 | | | 690 | | // Find the number of truncated digits before adjusting the precision for an exponent. | 691 | 1 | if (exponent > scale) { Branch (691:9): [True: 0, False: 1]
| 692 | | // Ex: 0.1e3 (which at this point would have precision == 1 and scale == 1), the | 693 | | // scale must be set to 0 and the value set to 100 which means a precision of 3. | 694 | 0 | precision += exponent - scale; | 695 | |
| 696 | 0 | value *= get_scale_multiplier<T>(exponent - scale); | 697 | 0 | scale = 0; | 698 | 1 | } else { | 699 | | // Ex: 100e-4, the scale must be set to 4 but no adjustment to the value is needed, | 700 | | // the precision must also be set to 4 but that will be done below for the | 701 | | // non-exponent case anyways. | 702 | 1 | scale -= exponent; | 703 | 1 | } | 704 | | // Ex: 0.001, at this point would have precision 1 and scale 3 since leading zeros | 705 | | // were ignored during previous parsing. | 706 | 1 | if (scale > precision) { Branch (706:9): [True: 0, False: 1]
| 707 | 0 | precision = scale; | 708 | 0 | } | 709 | | | 710 | | // Microbenchmarks show that beyond this point, returning on parse failure is slower | 711 | | // than just letting the function run out. | 712 | 1 | *result = StringParser::PARSE_SUCCESS; | 713 | 1 | if (UNLIKELY(precision - scale > type_precision - type_scale)) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1]
|
| 714 | 0 | *result = StringParser::PARSE_OVERFLOW; | 715 | 0 | if constexpr (TYPE_DECIMALV2 != P) { Branch (715:23): [Folded - Ignored]
| 716 | | // decimalv3 overflow will return max min value for type precision | 717 | 0 | value = is_negative ? vectorized::min_decimal_value<DecimalType>(type_precision) Branch (717:21): [True: 0, False: 0]
| 718 | 0 | : vectorized::max_decimal_value<DecimalType>(type_precision); | 719 | 0 | return value; | 720 | 0 | } | 721 | 1 | } else if (UNLIKELY(scale > type_scale)) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1]
|
| 722 | 0 | *result = StringParser::PARSE_UNDERFLOW; | 723 | 0 | int shift = scale - type_scale; | 724 | 0 | T divisor = get_scale_multiplier<T>(shift); | 725 | 0 | if (UNLIKELY(divisor == std::numeric_limits<T>::max())) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| 726 | 0 | value = 0; | 727 | 0 | } else { | 728 | 0 | T remainder = value % divisor; | 729 | 0 | value /= divisor; | 730 | 0 | if ((remainder > 0 ? T(remainder) : T(-remainder)) >= (divisor >> 1)) { Branch (730:17): [True: 0, False: 0]
Branch (730:18): [True: 0, False: 0]
| 731 | 0 | value += 1; | 732 | 0 | } | 733 | 0 | } | 734 | 0 | DCHECK(value >= 0); // //DCHECK_GE doesn't work with __int128. | 735 | 1 | } else if (UNLIKELY(!found_value && !found_dot)) {Line | Count | Source | 36 | 1 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 1]
Branch (36:44): [True: 0, False: 1]
Branch (36:44): [True: 0, False: 0]
|
| 736 | 0 | *result = StringParser::PARSE_FAILURE; | 737 | 0 | } | 738 | | | 739 | 1 | if (type_scale > scale) { Branch (739:9): [True: 0, False: 1]
| 740 | 0 | value *= get_scale_multiplier<T>(type_scale - scale); | 741 | 0 | } | 742 | | | 743 | 1 | return is_negative ? T(-value) : T(value); Branch (743:12): [True: 0, False: 1]
| 744 | 1 | } |
_ZN5doris12StringParser17string_to_decimalILNS_13PrimitiveTypeE20EnNS_10vectorized7DecimalInEEEET0_PKciiiPNS0_11ParseResultE Line | Count | Source | 556 | 138 | int type_scale, ParseResult* result) { | 557 | 138 | static_assert(std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t> || | 558 | 138 | std::is_same_v<T, __int128> || std::is_same_v<T, wide::Int256>, | 559 | 138 | "Cast string to decimal only support target type int32_t, int64_t, __int128 or " | 560 | 138 | "wide::Int256."); | 561 | | // Special cases: | 562 | | // 1) '' == Fail, an empty string fails to parse. | 563 | | // 2) ' # ' == #, leading and trailing white space is ignored. | 564 | | // 3) '.' == 0, a single dot parses as zero (for consistency with other types). | 565 | | // 4) '#.' == '#', a trailing dot is ignored. | 566 | | | 567 | | // Ignore leading and trailing spaces. | 568 | 138 | while (len > 0 && is_whitespace(*s)) { Branch (568:12): [True: 138, False: 0]
Branch (568:23): [True: 0, False: 138]
| 569 | 0 | ++s; | 570 | 0 | --len; | 571 | 0 | } | 572 | 138 | while (len > 0 && is_whitespace(s[len - 1])) { Branch (572:12): [True: 138, False: 0]
Branch (572:23): [True: 0, False: 138]
| 573 | 0 | --len; | 574 | 0 | } | 575 | | | 576 | 138 | bool is_negative = false; | 577 | 138 | if (len > 0) { Branch (577:9): [True: 138, False: 0]
| 578 | 138 | switch (*s) { Branch (578:17): [True: 113, False: 25]
| 579 | 25 | case '-': Branch (579:9): [True: 25, False: 113]
| 580 | 25 | is_negative = true; | 581 | 25 | [[fallthrough]]; | 582 | 25 | case '+': Branch (582:9): [True: 0, False: 138]
| 583 | 25 | ++s; | 584 | 25 | --len; | 585 | 138 | } | 586 | 138 | } | 587 | | | 588 | | // Ignore leading zeros. | 589 | 138 | bool found_value = false; | 590 | 160 | while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 155 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 22, False: 133]
|
Branch (590:12): [True: 155, False: 5]
| 591 | 22 | found_value = true; | 592 | 22 | ++s; | 593 | 22 | --len; | 594 | 22 | } | 595 | | | 596 | | // Ignore leading zeros even after a dot. This allows for differentiating between | 597 | | // cases like 0.01e2, which would fit in a DECIMAL(1, 0), and 0.10e2, which would | 598 | | // overflow. | 599 | 138 | int scale = 0; | 600 | 138 | int found_dot = 0; | 601 | 138 | if (len > 0 && *s == '.') { Branch (601:9): [True: 133, False: 5]
Branch (601:20): [True: 9, False: 124]
| 602 | 9 | found_dot = 1; | 603 | 9 | ++s; | 604 | 9 | --len; | 605 | 14 | while (len > 0 && UNLIKELY(*s == '0')) {Line | Count | Source | 36 | 12 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 5, False: 7]
|
Branch (605:16): [True: 12, False: 2]
| 606 | 5 | found_value = true; | 607 | 5 | ++scale; | 608 | 5 | ++s; | 609 | 5 | --len; | 610 | 5 | } | 611 | 9 | } | 612 | | | 613 | 138 | int precision = 0; | 614 | 138 | int max_digit = type_precision - type_scale; | 615 | 138 | int cur_digit = 0; | 616 | 138 | bool found_exponent = false; | 617 | 138 | int8_t exponent = 0; | 618 | 138 | T value = 0; | 619 | 138 | bool has_round = false; | 620 | 2.24k | for (int i = 0; i < len; ++i) { Branch (620:21): [True: 2.12k, False: 127]
| 621 | 2.12k | const char& c = s[i]; | 622 | 2.12k | if (LIKELY('0' <= c && c <= '9')) {Line | Count | Source | 35 | 4.12k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 2.00k, False: 118]
Branch (35:42): [True: 2.00k, False: 113]
Branch (35:42): [True: 2.00k, False: 5]
|
| 623 | 2.00k | found_value = true; | 624 | | // Ignore digits once the type's precision limit is reached. This avoids | 625 | | // overflowing the underlying storage while handling a string like | 626 | | // 10000000000e-10 into a DECIMAL(1, 0). Adjustments for ignored digits and | 627 | | // an exponent will be made later. | 628 | 2.00k | if (LIKELY(type_precision > precision) && !has_round) {Line | Count | Source | 35 | 4.00k | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 1.99k, False: 8]
|
Branch (628:55): [True: 1.99k, False: 0]
| 629 | 1.99k | value = (value * 10) + (c - '0'); // Benchmarks are faster with parenthesis... | 630 | 1.99k | ++precision; | 631 | 1.99k | scale += found_dot; | 632 | 1.99k | cur_digit = precision - scale; | 633 | 1.99k | } else if (!found_dot && max_digit < (precision - scale)) { Branch (633:24): [True: 0, False: 8]
Branch (633:38): [True: 0, False: 0]
| 634 | 0 | *result = StringParser::PARSE_OVERFLOW; | 635 | 0 | value = is_negative ? vectorized::min_decimal_value<DecimalType>(type_precision) Branch (635:25): [True: 0, False: 0]
| 636 | 0 | : vectorized::max_decimal_value<DecimalType>(type_precision); | 637 | 0 | return value; | 638 | 8 | } else if (found_dot && scale >= type_scale && !has_round) { Branch (638:24): [True: 8, False: 0]
Branch (638:37): [True: 8, False: 0]
Branch (638:60): [True: 8, False: 0]
| 639 | | // make rounding cases | 640 | 8 | if (c > '4') { Branch (640:21): [True: 0, False: 8]
| 641 | 0 | value += 1; | 642 | 0 | } | 643 | 8 | has_round = true; | 644 | 8 | continue; | 645 | 8 | } else if (!found_dot) { Branch (645:24): [True: 0, False: 0]
| 646 | 0 | ++cur_digit; | 647 | 0 | } | 648 | 1.99k | DCHECK(value >= 0); // For some reason //DCHECK_GE doesn't work with __int128. | 649 | 1.99k | } else if (c == '.' && LIKELY(!found_dot)) {Line | Count | Source | 35 | 107 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 107, False: 0]
|
Branch (649:20): [True: 107, False: 11]
| 650 | 107 | found_dot = 1; | 651 | 107 | } else if ((c == 'e' || c == 'E') && LIKELY(!found_exponent)) {Line | Count | Source | 35 | 0 | #define LIKELY(expr) __builtin_expect(!!(expr), 1) Branch (35:22): [True: 0, False: 0]
|
Branch (651:21): [True: 0, False: 11]
Branch (651:33): [True: 0, False: 11]
| 652 | 0 | found_exponent = true; | 653 | 0 | exponent = string_to_int_internal<int8_t>(s + i + 1, len - i - 1, result); | 654 | 0 | if (UNLIKELY(*result != StringParser::PARSE_SUCCESS)) {Line | Count | Source | 36 | 0 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 0]
|
| 655 | 0 | if (*result == StringParser::PARSE_OVERFLOW && exponent < 0) { Branch (655:21): [True: 0, False: 0]
Branch (655:64): [True: 0, False: 0]
| 656 | 0 | *result = StringParser::PARSE_UNDERFLOW; | 657 | 0 | } | 658 | 0 | return 0; | 659 | 0 | } | 660 | 0 | break; | 661 | 11 | } else { | 662 | 11 | if (value == 0) { Branch (662:17): [True: 9, False: 2]
| 663 | 9 | *result = StringParser::PARSE_FAILURE; | 664 | 9 | return 0; | 665 | 9 | } | 666 | | // here to handle | 667 | 2 | *result = StringParser::PARSE_SUCCESS; | 668 | 2 | if (type_scale >= scale) { Branch (668:17): [True: 2, False: 0]
| 669 | 2 | value *= get_scale_multiplier<T>(type_scale - scale); | 670 | | // here meet non-valid character, should return the value, keep going to meet | 671 | | // the E/e character because we make right user-given type_precision | 672 | | // not max number type_precision | 673 | 2 | if (!is_numeric_ascii(c)) { Branch (673:21): [True: 2, False: 0]
| 674 | 2 | if (cur_digit > type_precision) { Branch (674:25): [True: 0, False: 2]
| 675 | 0 | *result = StringParser::PARSE_OVERFLOW; | 676 | 0 | value = is_negative Branch (676:33): [True: 0, False: 0]
| 677 | 0 | ? vectorized::min_decimal_value<DecimalType>(type_precision) | 678 | 0 | : vectorized::max_decimal_value<DecimalType>( | 679 | 0 | type_precision); | 680 | 0 | return value; | 681 | 0 | } | 682 | 2 | return is_negative ? T(-value) : T(value); Branch (682:28): [True: 0, False: 2]
| 683 | 2 | } | 684 | 2 | } | 685 | | | 686 | 0 | return is_negative ? T(-value) : T(value); Branch (686:20): [True: 0, False: 0]
| 687 | 2 | } | 688 | 2.12k | } | 689 | | | 690 | | // Find the number of truncated digits before adjusting the precision for an exponent. | 691 | 127 | if (exponent > scale) { Branch (691:9): [True: 0, False: 127]
| 692 | | // Ex: 0.1e3 (which at this point would have precision == 1 and scale == 1), the | 693 | | // scale must be set to 0 and the value set to 100 which means a precision of 3. | 694 | 0 | precision += exponent - scale; | 695 | |
| 696 | 0 | value *= get_scale_multiplier<T>(exponent - scale); | 697 | 0 | scale = 0; | 698 | 127 | } else { | 699 | | // Ex: 100e-4, the scale must be set to 4 but no adjustment to the value is needed, | 700 | | // the precision must also be set to 4 but that will be done below for the | 701 | | // non-exponent case anyways. | 702 | 127 | scale -= exponent; | 703 | 127 | } | 704 | | // Ex: 0.001, at this point would have precision 1 and scale 3 since leading zeros | 705 | | // were ignored during previous parsing. | 706 | 127 | if (scale > precision) { Branch (706:9): [True: 3, False: 124]
| 707 | 3 | precision = scale; | 708 | 3 | } | 709 | | | 710 | | // Microbenchmarks show that beyond this point, returning on parse failure is slower | 711 | | // than just letting the function run out. | 712 | 127 | *result = StringParser::PARSE_SUCCESS; | 713 | 127 | if (UNLIKELY(precision - scale > type_precision - type_scale)) {Line | Count | Source | 36 | 127 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 9, False: 118]
|
| 714 | 9 | *result = StringParser::PARSE_OVERFLOW; | 715 | 9 | if constexpr (TYPE_DECIMALV2 != P) { Branch (715:23): [Folded - Ignored]
| 716 | | // decimalv3 overflow will return max min value for type precision | 717 | 9 | value = is_negative ? vectorized::min_decimal_value<DecimalType>(type_precision) | 718 | 9 | : vectorized::max_decimal_value<DecimalType>(type_precision); | 719 | 9 | return value; | 720 | 9 | } | 721 | 118 | } else if (UNLIKELY(scale > type_scale)) {Line | Count | Source | 36 | 118 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 17, False: 101]
|
| 722 | 17 | *result = StringParser::PARSE_UNDERFLOW; | 723 | 17 | int shift = scale - type_scale; | 724 | 17 | T divisor = get_scale_multiplier<T>(shift); | 725 | 17 | if (UNLIKELY(divisor == std::numeric_limits<T>::max())) {Line | Count | Source | 36 | 17 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 17]
|
| 726 | 0 | value = 0; | 727 | 17 | } else { | 728 | 17 | T remainder = value % divisor; | 729 | 17 | value /= divisor; | 730 | 17 | if ((remainder > 0 ? T(remainder) : T(-remainder)) >= (divisor >> 1)) { Branch (730:17): [True: 17, False: 0]
Branch (730:18): [True: 17, False: 0]
| 731 | 17 | value += 1; | 732 | 17 | } | 733 | 17 | } | 734 | 17 | DCHECK(value >= 0); // //DCHECK_GE doesn't work with __int128. | 735 | 101 | } else if (UNLIKELY(!found_value && !found_dot)) {Line | Count | Source | 36 | 101 | #define UNLIKELY(expr) __builtin_expect(!!(expr), 0) Branch (36:24): [True: 0, False: 101]
Branch (36:44): [True: 0, False: 101]
Branch (36:44): [True: 0, False: 0]
|
| 736 | 0 | *result = StringParser::PARSE_FAILURE; | 737 | 0 | } | 738 | | | 739 | 127 | if (type_scale > scale) { Branch (739:9): [True: 78, False: 49]
| 740 | 78 | value *= get_scale_multiplier<T>(type_scale - scale); | 741 | 78 | } | 742 | | | 743 | 127 | return is_negative ? T(-value) : T(value); Branch (743:12): [True: 25, False: 102]
| 744 | 138 | } |
|
745 | | |
746 | | } // end namespace doris |