/root/bitcoin/src/util/string.h
Line | Count | Source |
1 | | // Copyright (c) 2019-present The Bitcoin Core developers |
2 | | // Distributed under the MIT software license, see the accompanying |
3 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
4 | | |
5 | | #ifndef BITCOIN_UTIL_STRING_H |
6 | | #define BITCOIN_UTIL_STRING_H |
7 | | |
8 | | #include <algorithm> |
9 | | #include <array> |
10 | | #include <cstddef> |
11 | | #include <cstdint> |
12 | | #include <initializer_list> |
13 | | #include <locale> |
14 | | #include <optional> |
15 | | #include <span> |
16 | | #include <sstream> |
17 | | #include <string> |
18 | | #include <string_view> |
19 | | #include <vector> |
20 | | |
21 | | #include <attributes.h> |
22 | | |
23 | | namespace util { |
24 | | namespace detail { |
25 | | template <unsigned num_params> |
26 | | constexpr void CheckNumFormatSpecifiers(const char* str) |
27 | 0 | { |
28 | 0 | unsigned count_normal{0}; // Number of "normal" specifiers, like %s |
29 | 0 | unsigned count_pos{0}; // Max number in positional specifier, like %8$s |
30 | 0 | for (auto it{str}; *it != '\0'; ++it) { |
31 | 0 | if (*it != '%' || *++it == '%') continue; // Skip escaped %% |
32 | 0 |
|
33 | 0 | auto add_arg = [&] { |
34 | 0 | unsigned maybe_num{0}; |
35 | 0 | while ('0' <= *it && *it <= '9') { |
36 | 0 | maybe_num *= 10; |
37 | 0 | maybe_num += *it - '0'; |
38 | 0 | ++it; |
39 | 0 | } |
40 | 0 |
|
41 | 0 | if (*it == '$') { |
42 | 0 | ++it; |
43 | 0 | // Positional specifier, like %8$s |
44 | 0 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; |
45 | 0 | count_pos = std::max(count_pos, maybe_num); |
46 | 0 | } else { |
47 | 0 | // Non-positional specifier, like %s |
48 | 0 | ++count_normal; |
49 | 0 | } |
50 | 0 | }; |
51 | 0 |
|
52 | 0 | // Increase argument count and consume positional specifier, if present. |
53 | 0 | add_arg(); |
54 | 0 |
|
55 | 0 | // Consume flags. |
56 | 0 | while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it; |
57 | 0 |
|
58 | 0 | auto parse_size = [&] { |
59 | 0 | if (*it == '*') { |
60 | 0 | ++it; |
61 | 0 | add_arg(); |
62 | 0 | } else { |
63 | 0 | while ('0' <= *it && *it <= '9') ++it; |
64 | 0 | } |
65 | 0 | }; |
66 | 0 |
|
67 | 0 | // Consume dynamic or static width value. |
68 | 0 | parse_size(); |
69 | 0 |
|
70 | 0 | // Consume dynamic or static precision value. |
71 | 0 | if (*it == '.') { |
72 | 0 | ++it; |
73 | 0 | parse_size(); |
74 | 0 | } |
75 | 0 |
|
76 | 0 | if (*it == '\0') throw "Format specifier incorrectly terminated by end of string"; |
77 | 0 |
|
78 | 0 | // Length and type in "[flags][width][.precision][length]type" |
79 | 0 | // is not checked. Parsing continues with the next '%'. |
80 | 0 | } |
81 | 0 | if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!"; |
82 | 0 | unsigned count{count_normal | count_pos}; |
83 | 0 | if (num_params != count) throw "Format specifier count must match the argument count!"; |
84 | 0 | } Unexecuted instantiation: _ZN4util6detail24CheckNumFormatSpecifiersILj1EEEvPKc Unexecuted instantiation: _ZN4util6detail24CheckNumFormatSpecifiersILj2EEEvPKc Unexecuted instantiation: _ZN4util6detail24CheckNumFormatSpecifiersILj3EEEvPKc Unexecuted instantiation: _ZN4util6detail24CheckNumFormatSpecifiersILj5EEEvPKc Unexecuted instantiation: _ZN4util6detail24CheckNumFormatSpecifiersILj6EEEvPKc Unexecuted instantiation: _ZN4util6detail24CheckNumFormatSpecifiersILj0EEEvPKc Unexecuted instantiation: _ZN4util6detail24CheckNumFormatSpecifiersILj4EEEvPKc Unexecuted instantiation: _ZN4util6detail24CheckNumFormatSpecifiersILj7EEEvPKc Unexecuted instantiation: _ZN4util6detail24CheckNumFormatSpecifiersILj18EEEvPKc Unexecuted instantiation: _ZN4util6detail24CheckNumFormatSpecifiersILj19EEEvPKc Unexecuted instantiation: _ZN4util6detail24CheckNumFormatSpecifiersILj12EEEvPKc Unexecuted instantiation: _ZN4util6detail24CheckNumFormatSpecifiersILj8EEEvPKc |
85 | | } // namespace detail |
86 | | |
87 | | /** |
88 | | * @brief A wrapper for a compile-time partially validated format string |
89 | | * |
90 | | * This struct can be used to enforce partial compile-time validation of format |
91 | | * strings, to reduce the likelihood of tinyformat throwing exceptions at |
92 | | * run-time. Validation is partial to try and prevent the most common errors |
93 | | * while avoiding re-implementing the entire parsing logic. |
94 | | */ |
95 | | template <unsigned num_params> |
96 | | struct ConstevalFormatString { |
97 | | const char* const fmt; |
98 | | consteval ConstevalFormatString(const char* str) : fmt{str} { detail::CheckNumFormatSpecifiers<num_params>(fmt); } |
99 | | }; |
100 | | |
101 | | void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute); |
102 | | |
103 | | /** Split a string on any char found in separators, returning a vector. |
104 | | * |
105 | | * If sep does not occur in sp, a singleton with the entirety of sp is returned. |
106 | | * |
107 | | * @param[in] include_sep Whether to include the separator at the end of the left side of the splits. |
108 | | * |
109 | | * Note that this function does not care about braces, so splitting |
110 | | * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}. |
111 | | * |
112 | | * If include_sep == true, splitting "foo(bar(1),2),3) on ',' |
113 | | * will return: |
114 | | * - foo(bar(1), |
115 | | * - 2), |
116 | | * - 3) |
117 | | */ |
118 | | template <typename T = std::span<const char>> |
119 | | std::vector<T> Split(const std::span<const char>& sp, std::string_view separators, bool include_sep = false) |
120 | 1.56M | { |
121 | 1.56M | std::vector<T> ret; |
122 | 1.56M | auto it = sp.begin(); |
123 | 1.56M | auto start = it; |
124 | 253M | while (it != sp.end()) { Branch (124:12): [True: 18.9M, False: 59.7k]
Branch (124:12): [True: 232M, False: 1.50M]
Branch (124:12): [True: 21.8k, False: 479]
|
125 | 251M | if (separators.find(*it) != std::string::npos) { Branch (125:13): [True: 1.00M, False: 17.9M]
Branch (125:13): [True: 972k, False: 231M]
Branch (125:13): [True: 7.93k, False: 13.8k]
|
126 | 1.98M | if (include_sep) { Branch (126:17): [True: 0, False: 1.00M]
Branch (126:17): [True: 27.3k, False: 945k]
Branch (126:17): [True: 0, False: 7.93k]
|
127 | 27.3k | ret.emplace_back(start, it + 1); |
128 | 1.96M | } else { |
129 | 1.96M | ret.emplace_back(start, it); |
130 | 1.96M | } |
131 | 1.98M | start = it + 1; |
132 | 1.98M | } |
133 | 251M | ++it; |
134 | 251M | } |
135 | 1.56M | ret.emplace_back(start, it); |
136 | 1.56M | return ret; |
137 | 1.56M | } _ZN4util5SplitINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEESt6vectorIT_SaIS8_EERKSt4spanIKcLm18446744073709551615EESt17basic_string_viewIcS4_Eb Line | Count | Source | 120 | 59.7k | { | 121 | 59.7k | std::vector<T> ret; | 122 | 59.7k | auto it = sp.begin(); | 123 | 59.7k | auto start = it; | 124 | 19.0M | while (it != sp.end()) { Branch (124:12): [True: 18.9M, False: 59.7k]
| 125 | 18.9M | if (separators.find(*it) != std::string::npos) { Branch (125:13): [True: 1.00M, False: 17.9M]
| 126 | 1.00M | if (include_sep) { Branch (126:17): [True: 0, False: 1.00M]
| 127 | 0 | ret.emplace_back(start, it + 1); | 128 | 1.00M | } else { | 129 | 1.00M | ret.emplace_back(start, it); | 130 | 1.00M | } | 131 | 1.00M | start = it + 1; | 132 | 1.00M | } | 133 | 18.9M | ++it; | 134 | 18.9M | } | 135 | 59.7k | ret.emplace_back(start, it); | 136 | 59.7k | return ret; | 137 | 59.7k | } |
_ZN4util5SplitISt4spanIKcLm18446744073709551615EEEESt6vectorIT_SaIS5_EERKS3_St17basic_string_viewIcSt11char_traitsIcEEb Line | Count | Source | 120 | 1.50M | { | 121 | 1.50M | std::vector<T> ret; | 122 | 1.50M | auto it = sp.begin(); | 123 | 1.50M | auto start = it; | 124 | 234M | while (it != sp.end()) { Branch (124:12): [True: 232M, False: 1.50M]
| 125 | 232M | if (separators.find(*it) != std::string::npos) { Branch (125:13): [True: 972k, False: 231M]
| 126 | 972k | if (include_sep) { Branch (126:17): [True: 27.3k, False: 945k]
| 127 | 27.3k | ret.emplace_back(start, it + 1); | 128 | 945k | } else { | 129 | 945k | ret.emplace_back(start, it); | 130 | 945k | } | 131 | 972k | start = it + 1; | 132 | 972k | } | 133 | 232M | ++it; | 134 | 232M | } | 135 | 1.50M | ret.emplace_back(start, it); | 136 | 1.50M | return ret; | 137 | 1.50M | } |
_ZN4util5SplitISt17basic_string_viewIcSt11char_traitsIcEEEESt6vectorIT_SaIS6_EERKSt4spanIKcLm18446744073709551615EES4_b Line | Count | Source | 120 | 479 | { | 121 | 479 | std::vector<T> ret; | 122 | 479 | auto it = sp.begin(); | 123 | 479 | auto start = it; | 124 | 22.3k | while (it != sp.end()) { Branch (124:12): [True: 21.8k, False: 479]
| 125 | 21.8k | if (separators.find(*it) != std::string::npos) { Branch (125:13): [True: 7.93k, False: 13.8k]
| 126 | 7.93k | if (include_sep) { Branch (126:17): [True: 0, False: 7.93k]
| 127 | 0 | ret.emplace_back(start, it + 1); | 128 | 7.93k | } else { | 129 | 7.93k | ret.emplace_back(start, it); | 130 | 7.93k | } | 131 | 7.93k | start = it + 1; | 132 | 7.93k | } | 133 | 21.8k | ++it; | 134 | 21.8k | } | 135 | 479 | ret.emplace_back(start, it); | 136 | 479 | return ret; | 137 | 479 | } |
|
138 | | |
139 | | /** Split a string on every instance of sep, returning a vector. |
140 | | * |
141 | | * If sep does not occur in sp, a singleton with the entirety of sp is returned. |
142 | | * |
143 | | * Note that this function does not care about braces, so splitting |
144 | | * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}. |
145 | | */ |
146 | | template <typename T = std::span<const char>> |
147 | | std::vector<T> Split(const std::span<const char>& sp, char sep, bool include_sep = false) |
148 | 1.54M | { |
149 | 1.54M | return Split<T>(sp, std::string_view{&sep, 1}, include_sep); |
150 | 1.54M | } _ZN4util5SplitINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEESt6vectorIT_SaIS8_EERKSt4spanIKcLm18446744073709551615EEcb Line | Count | Source | 148 | 57.7k | { | 149 | 57.7k | return Split<T>(sp, std::string_view{&sep, 1}, include_sep); | 150 | 57.7k | } |
_ZN4util5SplitISt4spanIKcLm18446744073709551615EEEESt6vectorIT_SaIS5_EERKS3_cb Line | Count | Source | 148 | 1.48M | { | 149 | 1.48M | return Split<T>(sp, std::string_view{&sep, 1}, include_sep); | 150 | 1.48M | } |
Unexecuted instantiation: _ZN4util5SplitISt17basic_string_viewIcSt11char_traitsIcEEEESt6vectorIT_SaIS6_EERKSt4spanIKcLm18446744073709551615EEcb |
151 | | |
152 | | [[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, char sep) |
153 | 57.7k | { |
154 | 57.7k | return Split<std::string>(str, sep); |
155 | 57.7k | } |
156 | | |
157 | | [[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, std::string_view separators) |
158 | 2.04k | { |
159 | 2.04k | return Split<std::string>(str, separators); |
160 | 2.04k | } |
161 | | |
162 | | [[nodiscard]] inline std::string_view TrimStringView(std::string_view str, std::string_view pattern = " \f\n\r\t\v") |
163 | 90.6k | { |
164 | 90.6k | std::string::size_type front = str.find_first_not_of(pattern); |
165 | 90.6k | if (front == std::string::npos) { Branch (165:9): [True: 3.33k, False: 87.2k]
|
166 | 3.33k | return {}; |
167 | 3.33k | } |
168 | 87.2k | std::string::size_type end = str.find_last_not_of(pattern); |
169 | 87.2k | return str.substr(front, end - front + 1); |
170 | 90.6k | } |
171 | | |
172 | | [[nodiscard]] inline std::string TrimString(std::string_view str, std::string_view pattern = " \f\n\r\t\v") |
173 | 14.9k | { |
174 | 14.9k | return std::string(TrimStringView(str, pattern)); |
175 | 14.9k | } |
176 | | |
177 | | [[nodiscard]] inline std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix) |
178 | 0 | { |
179 | 0 | if (str.ends_with(suffix)) { Branch (179:9): [True: 0, False: 0]
|
180 | 0 | return str.substr(0, str.size() - suffix.size()); |
181 | 0 | } |
182 | 0 | return str; |
183 | 0 | } |
184 | | |
185 | | [[nodiscard]] inline std::string_view RemovePrefixView(std::string_view str, std::string_view prefix) |
186 | 6.89M | { |
187 | 6.89M | if (str.starts_with(prefix)) { Branch (187:9): [True: 1.35k, False: 6.89M]
|
188 | 1.35k | return str.substr(prefix.size()); |
189 | 1.35k | } |
190 | 6.89M | return str; |
191 | 6.89M | } |
192 | | |
193 | | [[nodiscard]] inline std::string RemovePrefix(std::string_view str, std::string_view prefix) |
194 | 1.61k | { |
195 | 1.61k | return std::string(RemovePrefixView(str, prefix)); |
196 | 1.61k | } |
197 | | |
198 | | /** |
199 | | * Join all container items. Typically used to concatenate strings but accepts |
200 | | * containers with elements of any type. |
201 | | * |
202 | | * @param container The items to join |
203 | | * @param separator The separator |
204 | | * @param unary_op Apply this operator to each item |
205 | | */ |
206 | | template <typename C, typename S, typename UnaryOp> |
207 | | // NOLINTNEXTLINE(misc-no-recursion) |
208 | | auto Join(const C& container, const S& separator, UnaryOp unary_op) |
209 | 558k | { |
210 | 558k | decltype(unary_op(*container.begin())) ret; |
211 | 558k | bool first{true}; |
212 | 558k | for (const auto& item : container) { Branch (212:27): [True: 204, False: 34]
Branch (212:27): [True: 126k, False: 4.36k]
Branch (212:27): [True: 13.8k, False: 1.61k]
Branch (212:27): [True: 110k, False: 14.5k]
Branch (212:27): [True: 153, False: 51]
Branch (212:27): [True: 16.3k, False: 4.08k]
Branch (212:27): [True: 2.42k, False: 873]
Branch (212:27): [True: 6.12k, False: 2.04k]
Branch (212:27): [True: 0, False: 530k]
Branch (212:27): [True: 1, False: 1]
Branch (212:27): [True: 780, False: 260]
Branch (212:27): [True: 0, False: 0]
|
213 | 277k | if (!first) ret += separator; Branch (213:13): [True: 170, False: 34]
Branch (213:13): [True: 122k, False: 4.36k]
Branch (213:13): [True: 12.6k, False: 1.23k]
Branch (213:13): [True: 96.1k, False: 14.5k]
Branch (213:13): [True: 102, False: 51]
Branch (213:13): [True: 12.2k, False: 4.08k]
Branch (213:13): [True: 1.54k, False: 873]
Branch (213:13): [True: 4.08k, False: 2.04k]
Branch (213:13): [True: 0, False: 0]
Branch (213:13): [True: 0, False: 1]
Branch (213:13): [True: 520, False: 260]
Branch (213:13): [True: 0, False: 0]
|
214 | 277k | ret += unary_op(item); |
215 | 277k | first = false; |
216 | 277k | } |
217 | 558k | return ret; |
218 | 558k | } _ZN4util4JoinISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EEA2_cZNS_17MakeUnorderedListERKS9_EUlRKS7_E_EEDaRKT_RKT0_T1_ Line | Count | Source | 209 | 34 | { | 210 | 34 | decltype(unary_op(*container.begin())) ret; | 211 | 34 | bool first{true}; | 212 | 204 | for (const auto& item : container) { Branch (212:27): [True: 204, False: 34]
| 213 | 204 | if (!first) ret += separator; Branch (213:13): [True: 170, False: 34]
| 214 | 204 | ret += unary_op(item); | 215 | 204 | first = false; | 216 | 204 | } | 217 | 34 | return ret; | 218 | 34 | } |
_ZN4util4JoinISt6vectorI11LogCategorySaIS2_EEA3_cZNK5BCLog6Logger19LogCategoriesStringB5cxx11EvEUlRKS2_E_EEDaRKT_RKT0_T1_ Line | Count | Source | 209 | 4.36k | { | 210 | 4.36k | decltype(unary_op(*container.begin())) ret; | 211 | 4.36k | bool first{true}; | 212 | 126k | for (const auto& item : container) { Branch (212:27): [True: 126k, False: 4.36k]
| 213 | 126k | if (!first) ret += separator; Branch (213:13): [True: 122k, False: 4.36k]
| 214 | 126k | ret += unary_op(item); | 215 | 126k | first = false; | 216 | 126k | } | 217 | 4.36k | return ret; | 218 | 4.36k | } |
_ZN4util4JoinISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EES7_ZNS_4JoinIS9_S7_EEDaRKT_RKT0_EUlSD_E_EEDaSD_SG_T1_ Line | Count | Source | 209 | 1.61k | { | 210 | 1.61k | decltype(unary_op(*container.begin())) ret; | 211 | 1.61k | bool first{true}; | 212 | 13.8k | for (const auto& item : container) { Branch (212:27): [True: 13.8k, False: 1.61k]
| 213 | 13.8k | if (!first) ret += separator; Branch (213:13): [True: 12.6k, False: 1.23k]
| 214 | 13.8k | ret += unary_op(item); | 215 | 13.8k | first = false; | 216 | 13.8k | } | 217 | 1.61k | return ret; | 218 | 1.61k | } |
_ZN4util4JoinISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EEA3_cZNS_4JoinIS9_SA_EEDaRKT_RKT0_EUlSE_E_EEDaSE_SH_T1_ Line | Count | Source | 209 | 14.5k | { | 210 | 14.5k | decltype(unary_op(*container.begin())) ret; | 211 | 14.5k | bool first{true}; | 212 | 110k | for (const auto& item : container) { Branch (212:27): [True: 110k, False: 14.5k]
| 213 | 110k | if (!first) ret += separator; Branch (213:13): [True: 96.1k, False: 14.5k]
| 214 | 110k | ret += unary_op(item); | 215 | 110k | first = false; | 216 | 110k | } | 217 | 14.5k | return ret; | 218 | 14.5k | } |
messages.cpp:_ZN4util4JoinISt6vectorISt4pairINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE15FeeEstimateModeESaISA_EES8_ZN6common8FeeModesERKS8_E3$_0EEDaRKT_RKT0_T1_ Line | Count | Source | 209 | 51 | { | 210 | 51 | decltype(unary_op(*container.begin())) ret; | 211 | 51 | bool first{true}; | 212 | 153 | for (const auto& item : container) { Branch (212:27): [True: 153, False: 51]
| 213 | 153 | if (!first) ret += separator; Branch (213:13): [True: 102, False: 51]
| 214 | 153 | ret += unary_op(item); | 215 | 153 | first = false; | 216 | 153 | } | 217 | 51 | return ret; | 218 | 51 | } |
outputtype.cpp:_ZN4util4JoinISt5arrayI10OutputTypeLm4EEA3_cZ20FormatAllOutputTypesB5cxx11vE3$_0EEDaRKT_RKT0_T1_ Line | Count | Source | 209 | 4.08k | { | 210 | 4.08k | decltype(unary_op(*container.begin())) ret; | 211 | 4.08k | bool first{true}; | 212 | 16.3k | for (const auto& item : container) { Branch (212:27): [True: 16.3k, False: 4.08k]
| 213 | 16.3k | if (!first) ret += separator; Branch (213:13): [True: 12.2k, False: 4.08k]
| 214 | 16.3k | ret += unary_op(item); | 215 | 16.3k | first = false; | 216 | 16.3k | } | 217 | 4.08k | return ret; | 218 | 4.08k | } |
util.cpp:_ZN4util4JoinISt6vectorI6RPCArgSaIS2_EEA2_cZNKS2_8ToStringB5cxx11EbE3$_0EEDaRKT_RKT0_T1_ Line | Count | Source | 209 | 873 | { | 210 | 873 | decltype(unary_op(*container.begin())) ret; | 211 | 873 | bool first{true}; | 212 | 2.42k | for (const auto& item : container) { Branch (212:27): [True: 2.42k, False: 873]
| 213 | 2.42k | if (!first) ret += separator; Branch (213:13): [True: 1.54k, False: 873]
| 214 | 2.42k | ret += unary_op(item); | 215 | 2.42k | first = false; | 216 | 2.42k | } | 217 | 873 | return ret; | 218 | 873 | } |
logging.cpp:_ZN4util4JoinISt6vectorINS_3log5LevelESaIS3_EEA3_cZNK5BCLog6Logger15LogLevelsStringB5cxx11EvE3$_0EEDaRKT_RKT0_T1_ Line | Count | Source | 209 | 2.04k | { | 210 | 2.04k | decltype(unary_op(*container.begin())) ret; | 211 | 2.04k | bool first{true}; | 212 | 6.12k | for (const auto& item : container) { Branch (212:27): [True: 6.12k, False: 2.04k]
| 213 | 6.12k | if (!first) ret += separator; Branch (213:13): [True: 4.08k, False: 2.04k]
| 214 | 6.12k | ret += unary_op(item); | 215 | 6.12k | first = false; | 216 | 6.12k | } | 217 | 2.04k | return ret; | 218 | 2.04k | } |
_ZN4util4JoinISt6vectorI13bilingual_strSaIS2_EES2_ZNS_4JoinIS4_S2_EEDaRKT_RKT0_EUlS8_E_EEDaS8_SB_T1_ Line | Count | Source | 209 | 530k | { | 210 | 530k | decltype(unary_op(*container.begin())) ret; | 211 | 530k | bool first{true}; | 212 | 530k | for (const auto& item : container) { Branch (212:27): [True: 0, False: 530k]
| 213 | 0 | if (!first) ret += separator; Branch (213:13): [True: 0, False: 0]
| 214 | 0 | ret += unary_op(item); | 215 | 0 | first = false; | 216 | 0 | } | 217 | 530k | return ret; | 218 | 530k | } |
blockfilter.cpp:_ZN4util4JoinISt3mapI15BlockFilterTypeNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4lessIS2_ESaISt4pairIKS2_S8_EEEA3_cZ20ListBlockFilterTypesvE3$_0EEDaRKT_RKT0_T1_ Line | Count | Source | 209 | 1 | { | 210 | 1 | decltype(unary_op(*container.begin())) ret; | 211 | 1 | bool first{true}; | 212 | 1 | for (const auto& item : container) { Branch (212:27): [True: 1, False: 1]
| 213 | 1 | if (!first) ret += separator; Branch (213:13): [True: 0, False: 1]
| 214 | 1 | ret += unary_op(item); | 215 | 1 | first = false; | 216 | 1 | } | 217 | 1 | return ret; | 218 | 1 | } |
validation.cpp:_ZN4util4JoinISt6vectorIiSaIiEEA3_cZN17ChainstateManager16ActivateSnapshotER8AutoFileRKN4node16SnapshotMetadataEbE3$_0EEDaRKT_RKT0_T1_ Line | Count | Source | 209 | 260 | { | 210 | 260 | decltype(unary_op(*container.begin())) ret; | 211 | 260 | bool first{true}; | 212 | 780 | for (const auto& item : container) { Branch (212:27): [True: 780, False: 260]
| 213 | 780 | if (!first) ret += separator; Branch (213:13): [True: 520, False: 260]
| 214 | 780 | ret += unary_op(item); | 215 | 780 | first = false; | 216 | 780 | } | 217 | 260 | return ret; | 218 | 260 | } |
Unexecuted instantiation: _ZN4util4JoinISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EEA2_cZNS_4JoinIS9_SA_EEDaRKT_RKT0_EUlSE_E_EEDaSE_SH_T1_ |
219 | | |
220 | | template <typename C, typename S> |
221 | | auto Join(const C& container, const S& separator) |
222 | 546k | { |
223 | 546k | return Join(container, separator, [](const auto& i) { return i; });_ZZN4util4JoinISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EES7_EEDaRKT_RKT0_ENKUlSC_E_clIS7_EEDaSC_ Line | Count | Source | 223 | 13.8k | return Join(container, separator, [](const auto& i) { return i; }); |
_ZZN4util4JoinISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EEA3_cEEDaRKT_RKT0_ENKUlSD_E_clIS7_EEDaSD_ Line | Count | Source | 223 | 110k | return Join(container, separator, [](const auto& i) { return i; }); |
Unexecuted instantiation: _ZZN4util4JoinISt6vectorI13bilingual_strSaIS2_EES2_EEDaRKT_RKT0_ENKUlS7_E_clIS2_EEDaS7_ Unexecuted instantiation: _ZZN4util4JoinISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EEA2_cEEDaRKT_RKT0_ENKUlSD_E_clIS7_EEDaSD_ |
224 | 546k | } _ZN4util4JoinISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EES7_EEDaRKT_RKT0_ Line | Count | Source | 222 | 1.61k | { | 223 | 1.61k | return Join(container, separator, [](const auto& i) { return i; }); | 224 | 1.61k | } |
_ZN4util4JoinISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EEA3_cEEDaRKT_RKT0_ Line | Count | Source | 222 | 14.5k | { | 223 | 14.5k | return Join(container, separator, [](const auto& i) { return i; }); | 224 | 14.5k | } |
_ZN4util4JoinISt6vectorI13bilingual_strSaIS2_EES2_EEDaRKT_RKT0_ Line | Count | Source | 222 | 530k | { | 223 | 530k | return Join(container, separator, [](const auto& i) { return i; }); | 224 | 530k | } |
Unexecuted instantiation: _ZN4util4JoinISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS7_EEA2_cEEDaRKT_RKT0_ |
225 | | |
226 | | /** |
227 | | * Create an unordered multi-line list of items. |
228 | | */ |
229 | | inline std::string MakeUnorderedList(const std::vector<std::string>& items) |
230 | 34 | { |
231 | 204 | return Join(items, "\n", [](const std::string& item) { return "- " + item; }); |
232 | 34 | } |
233 | | |
234 | | /** |
235 | | * Check if a string does not contain any embedded NUL (\0) characters |
236 | | */ |
237 | | [[nodiscard]] inline bool ContainsNoNUL(std::string_view str) noexcept |
238 | 1.69M | { |
239 | 108M | for (auto c : str) { Branch (239:17): [True: 108M, False: 1.48M]
|
240 | 108M | if (c == 0) return false; Branch (240:13): [True: 204k, False: 107M]
|
241 | 108M | } |
242 | 1.48M | return true; |
243 | 1.69M | } |
244 | | |
245 | | /** |
246 | | * Locale-independent version of std::to_string |
247 | | */ |
248 | | template <typename T> |
249 | | std::string ToString(const T& t) |
250 | 220k | { |
251 | 220k | std::ostringstream oss; |
252 | 220k | oss.imbue(std::locale::classic()); |
253 | 220k | oss << t; |
254 | 220k | return oss.str(); |
255 | 220k | } _ZN4util8ToStringIlEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_ Line | Count | Source | 250 | 2.75k | { | 251 | 2.75k | std::ostringstream oss; | 252 | 2.75k | oss.imbue(std::locale::classic()); | 253 | 2.75k | oss << t; | 254 | 2.75k | return oss.str(); | 255 | 2.75k | } |
_ZN4util8ToStringIjEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_ Line | Count | Source | 250 | 207k | { | 251 | 207k | std::ostringstream oss; | 252 | 207k | oss.imbue(std::locale::classic()); | 253 | 207k | oss << t; | 254 | 207k | return oss.str(); | 255 | 207k | } |
_ZN4util8ToStringImEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_ Line | Count | Source | 250 | 7.77k | { | 251 | 7.77k | std::ostringstream oss; | 252 | 7.77k | oss.imbue(std::locale::classic()); | 253 | 7.77k | oss << t; | 254 | 7.77k | return oss.str(); | 255 | 7.77k | } |
_ZN4util8ToStringIiEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_ Line | Count | Source | 250 | 2.83k | { | 251 | 2.83k | std::ostringstream oss; | 252 | 2.83k | oss.imbue(std::locale::classic()); | 253 | 2.83k | oss << t; | 254 | 2.83k | return oss.str(); | 255 | 2.83k | } |
|
256 | | |
257 | | /** |
258 | | * Check whether a container begins with the given prefix. |
259 | | */ |
260 | | template <typename T1, size_t PREFIX_LEN> |
261 | | [[nodiscard]] inline bool HasPrefix(const T1& obj, |
262 | | const std::array<uint8_t, PREFIX_LEN>& prefix) |
263 | 1.53G | { |
264 | 1.53G | return obj.size() >= PREFIX_LEN && Branch (264:12): [True: 25.5M, False: 0]
Branch (264:12): [True: 157M, False: 0]
Branch (264:12): [True: 1.09M, False: 0]
Branch (264:12): [True: 2.17M, False: 0]
Branch (264:12): [True: 186M, False: 0]
Branch (264:12): [True: 701M, False: 0]
Branch (264:12): [True: 283M, False: 0]
Branch (264:12): [True: 181M, False: 0]
|
265 | 1.53G | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); Branch (265:12): [True: 37.1k, False: 25.4M]
Branch (265:12): [True: 148k, False: 157M]
Branch (265:12): [True: 5.88k, False: 1.09M]
Branch (265:12): [True: 9.67k, False: 2.16M]
Branch (265:12): [True: 76.2k, False: 186M]
Branch (265:12): [True: 2.10M, False: 699M]
Branch (265:12): [True: 107k, False: 283M]
Branch (265:12): [True: 27.5k, False: 181M]
|
266 | 1.53G | } _ZN4util9HasPrefixI9prevectorILj16EhjiELm6EEEbRKT_RKSt5arrayIhXT0_EE Line | Count | Source | 263 | 25.5M | { | 264 | 25.5M | return obj.size() >= PREFIX_LEN && Branch (264:12): [True: 25.5M, False: 0]
| 265 | 25.5M | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); Branch (265:12): [True: 37.1k, False: 25.4M]
| 266 | 25.5M | } |
_ZN4util9HasPrefixI9prevectorILj16EhjiELm12EEEbRKT_RKSt5arrayIhXT0_EE Line | Count | Source | 263 | 157M | { | 264 | 157M | return obj.size() >= PREFIX_LEN && Branch (264:12): [True: 157M, False: 0]
| 265 | 157M | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); Branch (265:12): [True: 148k, False: 157M]
| 266 | 157M | } |
_ZN4util9HasPrefixISt4spanIKhLm18446744073709551615EELm12EEEbRKT_RKSt5arrayIhXT0_EE Line | Count | Source | 263 | 1.09M | { | 264 | 1.09M | return obj.size() >= PREFIX_LEN && Branch (264:12): [True: 1.09M, False: 0]
| 265 | 1.09M | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); Branch (265:12): [True: 5.88k, False: 1.09M]
| 266 | 1.09M | } |
_ZN4util9HasPrefixISt4spanIKhLm18446744073709551615EELm6EEEbRKT_RKSt5arrayIhXT0_EE Line | Count | Source | 263 | 2.17M | { | 264 | 2.17M | return obj.size() >= PREFIX_LEN && Branch (264:12): [True: 2.17M, False: 0]
| 265 | 2.17M | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); Branch (265:12): [True: 9.67k, False: 2.16M]
| 266 | 2.17M | } |
_ZN4util9HasPrefixI9prevectorILj16EhjiELm2EEEbRKT_RKSt5arrayIhXT0_EE Line | Count | Source | 263 | 186M | { | 264 | 186M | return obj.size() >= PREFIX_LEN && Branch (264:12): [True: 186M, False: 0]
| 265 | 186M | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); Branch (265:12): [True: 76.2k, False: 186M]
| 266 | 186M | } |
_ZN4util9HasPrefixI9prevectorILj16EhjiELm3EEEbRKT_RKSt5arrayIhXT0_EE Line | Count | Source | 263 | 701M | { | 264 | 701M | return obj.size() >= PREFIX_LEN && Branch (264:12): [True: 701M, False: 0]
| 265 | 701M | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); Branch (265:12): [True: 2.10M, False: 699M]
| 266 | 701M | } |
_ZN4util9HasPrefixI9prevectorILj16EhjiELm4EEEbRKT_RKSt5arrayIhXT0_EE Line | Count | Source | 263 | 283M | { | 264 | 283M | return obj.size() >= PREFIX_LEN && Branch (264:12): [True: 283M, False: 0]
| 265 | 283M | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); Branch (265:12): [True: 107k, False: 283M]
| 266 | 283M | } |
_ZN4util9HasPrefixI9prevectorILj16EhjiELm8EEEbRKT_RKSt5arrayIhXT0_EE Line | Count | Source | 263 | 181M | { | 264 | 181M | return obj.size() >= PREFIX_LEN && Branch (264:12): [True: 181M, False: 0]
| 265 | 181M | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); Branch (265:12): [True: 27.5k, False: 181M]
| 266 | 181M | } |
|
267 | | |
268 | | class LineReader |
269 | | { |
270 | | const std::string_view m_str; |
271 | | const size_t m_max_line_length; |
272 | | std::string_view::iterator m_it; |
273 | | |
274 | | public: |
275 | | explicit LineReader(std::string_view str, size_t max_line_length); |
276 | | |
277 | | /** |
278 | | * Returns a string from current iterator position up to (but not including) next \n |
279 | | * and advances iterator to the character following the \n on success. |
280 | | * Will not return a line longer than max_line_length. |
281 | | * @returns the next string from the buffer. |
282 | | * std::nullopt if end of buffer is reached without finding a \n. |
283 | | * @throws a std::runtime_error if max_line_length + 1 bytes are read without finding \n. |
284 | | */ |
285 | | std::optional<std::string_view> ReadLine() LIFETIMEBOUND; |
286 | | |
287 | | /** |
288 | | * Returns string from current iterator position of specified length |
289 | | * if possible and advances iterator on success. |
290 | | * May exceed max_line_length but will not read past end of buffer. |
291 | | * @param[in] len The number of bytes to read from the buffer |
292 | | * @returns a string of the expected length. |
293 | | * @throws a std::runtime_error if there is not enough data in the buffer. |
294 | | */ |
295 | | std::string_view ReadLength(size_t len) LIFETIMEBOUND; |
296 | | |
297 | | /** |
298 | | * Returns remaining size of bytes in buffer |
299 | | */ |
300 | | size_t Remaining() const; |
301 | | |
302 | | /** |
303 | | * Returns number of bytes already read from buffer |
304 | | */ |
305 | | size_t Consumed() const; |
306 | | }; |
307 | | } // namespace util |
308 | | |
309 | | #endif // BITCOIN_UTIL_STRING_H |