/root/doris/be/src/util/to_string.h
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | |
19 | | #pragma once |
20 | | |
21 | | #include <absl/strings/ascii.h> |
22 | | #include <fmt/compile.h> |
23 | | #include <fmt/format.h> |
24 | | #include <glog/logging.h> |
25 | | |
26 | | #include <cfloat> |
27 | | #include <map> |
28 | | #include <set> |
29 | | #include <string> |
30 | | #include <type_traits> |
31 | | #include <vector> |
32 | | |
33 | | namespace doris { |
34 | | |
35 | | template <typename T> |
36 | 137 | std::string to_string(const T& t) { |
37 | 137 | return fmt::format("{}", t); |
38 | 137 | } _ZN5doris9to_stringISt6atomicINS_19TWgSlotMemoryPolicy4typeEEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_ Line | Count | Source | 36 | 137 | std::string to_string(const T& t) { | 37 | 137 | return fmt::format("{}", t); | 38 | 137 | } |
Unexecuted instantiation: _ZN5doris9to_stringINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEES6_RKT_ |
39 | | |
40 | | template <typename K, typename V> |
41 | | std::string to_string(const std::map<K, V>& m); |
42 | | |
43 | | template <typename T> |
44 | | std::string to_string(const std::set<T>& s); |
45 | | |
46 | | template <typename T> |
47 | | std::string to_string(const std::vector<T>& t); |
48 | | |
49 | | template <typename K, typename V> |
50 | | std::string to_string(const typename std::pair<K, V>& v) { |
51 | | return fmt::format("{}: {}", to_string(v.first), to_string(v.second)); |
52 | | } |
53 | | |
54 | | template <typename T> |
55 | 0 | std::string to_string(const T& beg, const T& end) { |
56 | 0 | std::string out; |
57 | 0 | for (T it = beg; it != end; ++it) { |
58 | 0 | if (it != beg) out += ", "; |
59 | 0 | out += to_string(*it); |
60 | 0 | } |
61 | 0 | return out; |
62 | 0 | } |
63 | | |
64 | | template <typename T> |
65 | 0 | std::string to_string(const std::vector<T>& t) { |
66 | 0 | return "[" + to_string(t.begin(), t.end()) + "]"; |
67 | 0 | } |
68 | | |
69 | | template <typename K, typename V> |
70 | | std::string to_string(const std::map<K, V>& m) { |
71 | | return "{" + to_string(m.begin(), m.end()) + "}"; |
72 | | } |
73 | | |
74 | | template <typename T> |
75 | | std::string to_string(const std::set<T>& s) { |
76 | | return "{" + to_string(s.begin(), s.end()) + "}"; |
77 | | } |
78 | | |
79 | | // refer to: https://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10.html |
80 | | template <typename T> |
81 | 1.62k | inline int fast_to_buffer(T value, char* buffer) { |
82 | 1.62k | char* end = nullptr; |
83 | | // output NaN and Infinity to be compatible with most of the implementations |
84 | 1.62k | if (std::isnan(value)) { |
85 | 3 | static constexpr char nan_str[] = "NaN"; |
86 | 3 | static constexpr int nan_str_len = sizeof(nan_str) - 1; |
87 | 3 | memcpy(buffer, nan_str, nan_str_len); |
88 | 3 | end = buffer + nan_str_len; |
89 | 1.62k | } else if (std::isinf(value)) { |
90 | 5 | static constexpr char inf_str[] = "Infinity"; |
91 | 5 | static constexpr int inf_str_len = sizeof(inf_str) - 1; |
92 | 5 | static constexpr char neg_inf_str[] = "-Infinity"; |
93 | 5 | static constexpr int neg_inf_str_len = sizeof(neg_inf_str) - 1; |
94 | 5 | if (value > 0) { |
95 | 3 | memcpy(buffer, inf_str, inf_str_len); |
96 | 3 | end = buffer + inf_str_len; |
97 | 3 | } else { |
98 | 2 | memcpy(buffer, neg_inf_str, neg_inf_str_len); |
99 | 2 | end = buffer + neg_inf_str_len; |
100 | 2 | } |
101 | 1.62k | } else { |
102 | 1.62k | end = fmt::format_to(buffer, FMT_COMPILE("{}"), value); Unexecuted instantiation: _ZZZN5doris14fast_to_bufferIfEEiT_PcENKUlvE_clEvENK18FMT_COMPILE_STRINGcvN3fmt2v717basic_string_viewIcEEEv Unexecuted instantiation: _ZZZN5doris14fast_to_bufferIdEEiT_PcENKUlvE_clEvENK18FMT_COMPILE_STRINGcvN3fmt2v717basic_string_viewIcEEEv |
103 | 1.62k | } |
104 | 1.62k | *end = '\0'; |
105 | 1.62k | return end - buffer; |
106 | 1.62k | } _ZN5doris14fast_to_bufferIfEEiT_Pc Line | Count | Source | 81 | 764 | inline int fast_to_buffer(T value, char* buffer) { | 82 | 764 | char* end = nullptr; | 83 | | // output NaN and Infinity to be compatible with most of the implementations | 84 | 764 | if (std::isnan(value)) { | 85 | 1 | static constexpr char nan_str[] = "NaN"; | 86 | 1 | static constexpr int nan_str_len = sizeof(nan_str) - 1; | 87 | 1 | memcpy(buffer, nan_str, nan_str_len); | 88 | 1 | end = buffer + nan_str_len; | 89 | 763 | } else if (std::isinf(value)) { | 90 | 2 | static constexpr char inf_str[] = "Infinity"; | 91 | 2 | static constexpr int inf_str_len = sizeof(inf_str) - 1; | 92 | 2 | static constexpr char neg_inf_str[] = "-Infinity"; | 93 | 2 | static constexpr int neg_inf_str_len = sizeof(neg_inf_str) - 1; | 94 | 2 | if (value > 0) { | 95 | 1 | memcpy(buffer, inf_str, inf_str_len); | 96 | 1 | end = buffer + inf_str_len; | 97 | 1 | } else { | 98 | 1 | memcpy(buffer, neg_inf_str, neg_inf_str_len); | 99 | 1 | end = buffer + neg_inf_str_len; | 100 | 1 | } | 101 | 761 | } else { | 102 | | end = fmt::format_to(buffer, FMT_COMPILE("{}"), value); | 103 | 761 | } | 104 | 764 | *end = '\0'; | 105 | 764 | return end - buffer; | 106 | 764 | } |
_ZN5doris14fast_to_bufferIdEEiT_Pc Line | Count | Source | 81 | 865 | inline int fast_to_buffer(T value, char* buffer) { | 82 | 865 | char* end = nullptr; | 83 | | // output NaN and Infinity to be compatible with most of the implementations | 84 | 865 | if (std::isnan(value)) { | 85 | 2 | static constexpr char nan_str[] = "NaN"; | 86 | 2 | static constexpr int nan_str_len = sizeof(nan_str) - 1; | 87 | 2 | memcpy(buffer, nan_str, nan_str_len); | 88 | 2 | end = buffer + nan_str_len; | 89 | 863 | } else if (std::isinf(value)) { | 90 | 3 | static constexpr char inf_str[] = "Infinity"; | 91 | 3 | static constexpr int inf_str_len = sizeof(inf_str) - 1; | 92 | 3 | static constexpr char neg_inf_str[] = "-Infinity"; | 93 | 3 | static constexpr int neg_inf_str_len = sizeof(neg_inf_str) - 1; | 94 | 3 | if (value > 0) { | 95 | 2 | memcpy(buffer, inf_str, inf_str_len); | 96 | 2 | end = buffer + inf_str_len; | 97 | 2 | } else { | 98 | 1 | memcpy(buffer, neg_inf_str, neg_inf_str_len); | 99 | 1 | end = buffer + neg_inf_str_len; | 100 | 1 | } | 101 | 860 | } else { | 102 | | end = fmt::format_to(buffer, FMT_COMPILE("{}"), value); | 103 | 860 | } | 104 | 865 | *end = '\0'; | 105 | 865 | return end - buffer; | 106 | 865 | } |
|
107 | | |
108 | | template <typename T> |
109 | 18.0M | int to_buffer(const T& value, int width, char* buffer) { |
110 | 18.0M | constexpr int DIG = (std::is_same_v<T, double> ? DBL_DIG : FLT_DIG); |
111 | 18.0M | int snprintf_result = snprintf(buffer, width, "%.*g", DIG, value); |
112 | | // The snprintf should never overflow because the buffer is significantly |
113 | | // larger than the precision we asked for. |
114 | 18.0M | DCHECK(snprintf_result > 0 && snprintf_result < width); |
115 | | |
116 | 18.0M | bool need_reformat = false; |
117 | 18.0M | if constexpr (std::is_same_v<T, double>) { |
118 | 11 | need_reformat = (strtod(buffer, nullptr) != value); |
119 | 18.0M | } else { |
120 | 18.0M | auto safe_strtof = [](const char* str, float* value) { |
121 | 18.0M | char* endptr; |
122 | 18.0M | *value = strtof(str, &endptr); |
123 | 18.0M | if (endptr != str) { |
124 | 18.0M | while (absl::ascii_isspace(*endptr)) { |
125 | 0 | ++endptr; |
126 | 0 | } |
127 | 18.0M | } |
128 | | // Ignore range errors from strtod/strtof. |
129 | | // The values it returns on underflow and |
130 | | // overflow are the right fallback in a |
131 | | // robust setting. |
132 | 18.0M | return *str != '\0' && *endptr == '\0'; |
133 | 18.0M | }; |
134 | | |
135 | 18.0M | if (float parsed_value; !safe_strtof(buffer, &parsed_value) || parsed_value != value) { |
136 | 12 | need_reformat = true; |
137 | 12 | } |
138 | 18.0M | } |
139 | | |
140 | 18.0M | if (need_reformat) { |
141 | 15 | snprintf_result = snprintf(buffer, width, "%.*g", DIG + 2, value); |
142 | | // Should never overflow; see above. |
143 | | DCHECK(snprintf_result > 0 && snprintf_result < width); |
144 | 15 | } |
145 | 18.0M | return snprintf_result; |
146 | 18.0M | } _ZN5doris9to_bufferIfEEiRKT_iPc Line | Count | Source | 109 | 18.0M | int to_buffer(const T& value, int width, char* buffer) { | 110 | 18.0M | constexpr int DIG = (std::is_same_v<T, double> ? DBL_DIG : FLT_DIG); | 111 | 18.0M | int snprintf_result = snprintf(buffer, width, "%.*g", DIG, value); | 112 | | // The snprintf should never overflow because the buffer is significantly | 113 | | // larger than the precision we asked for. | 114 | 18.0M | DCHECK(snprintf_result > 0 && snprintf_result < width); | 115 | | | 116 | 18.0M | bool need_reformat = false; | 117 | | if constexpr (std::is_same_v<T, double>) { | 118 | | need_reformat = (strtod(buffer, nullptr) != value); | 119 | 18.0M | } else { | 120 | 18.0M | auto safe_strtof = [](const char* str, float* value) { | 121 | 18.0M | char* endptr; | 122 | 18.0M | *value = strtof(str, &endptr); | 123 | 18.0M | if (endptr != str) { | 124 | 18.0M | while (absl::ascii_isspace(*endptr)) { | 125 | 18.0M | ++endptr; | 126 | 18.0M | } | 127 | 18.0M | } | 128 | | // Ignore range errors from strtod/strtof. | 129 | | // The values it returns on underflow and | 130 | | // overflow are the right fallback in a | 131 | | // robust setting. | 132 | 18.0M | return *str != '\0' && *endptr == '\0'; | 133 | 18.0M | }; | 134 | | | 135 | 18.0M | if (float parsed_value; !safe_strtof(buffer, &parsed_value) || parsed_value != value) { | 136 | 12 | need_reformat = true; | 137 | 12 | } | 138 | 18.0M | } | 139 | | | 140 | 18.0M | if (need_reformat) { | 141 | 12 | snprintf_result = snprintf(buffer, width, "%.*g", DIG + 2, value); | 142 | | // Should never overflow; see above. | 143 | | DCHECK(snprintf_result > 0 && snprintf_result < width); | 144 | 12 | } | 145 | 18.0M | return snprintf_result; | 146 | 18.0M | } |
_ZN5doris9to_bufferIdEEiRKT_iPc Line | Count | Source | 109 | 11 | int to_buffer(const T& value, int width, char* buffer) { | 110 | 11 | constexpr int DIG = (std::is_same_v<T, double> ? DBL_DIG : FLT_DIG); | 111 | 11 | int snprintf_result = snprintf(buffer, width, "%.*g", DIG, value); | 112 | | // The snprintf should never overflow because the buffer is significantly | 113 | | // larger than the precision we asked for. | 114 | 11 | DCHECK(snprintf_result > 0 && snprintf_result < width); | 115 | | | 116 | 11 | bool need_reformat = false; | 117 | 11 | if constexpr (std::is_same_v<T, double>) { | 118 | 11 | need_reformat = (strtod(buffer, nullptr) != value); | 119 | | } else { | 120 | | auto safe_strtof = [](const char* str, float* value) { | 121 | | char* endptr; | 122 | | *value = strtof(str, &endptr); | 123 | | if (endptr != str) { | 124 | | while (absl::ascii_isspace(*endptr)) { | 125 | | ++endptr; | 126 | | } | 127 | | } | 128 | | // Ignore range errors from strtod/strtof. | 129 | | // The values it returns on underflow and | 130 | | // overflow are the right fallback in a | 131 | | // robust setting. | 132 | | return *str != '\0' && *endptr == '\0'; | 133 | | }; | 134 | | | 135 | | if (float parsed_value; !safe_strtof(buffer, &parsed_value) || parsed_value != value) { | 136 | | need_reformat = true; | 137 | | } | 138 | | } | 139 | | | 140 | 11 | if (need_reformat) { | 141 | 3 | snprintf_result = snprintf(buffer, width, "%.*g", DIG + 2, value); | 142 | | // Should never overflow; see above. | 143 | | DCHECK(snprintf_result > 0 && snprintf_result < width); | 144 | 3 | } | 145 | 11 | return snprintf_result; | 146 | 11 | } |
|
147 | | } // namespace doris |