/tmp/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 | 72 | { |
28 | 72 | unsigned count_normal{0}; // Number of "normal" specifiers, like %s |
29 | 72 | unsigned count_pos{0}; // Max number in positional specifier, like %8$s |
30 | 157 | for (auto it{str}; *it != '\0'; ++it) { |
31 | 98 | if (*it != '%' || *++it == '%') continue; // Skip escaped %% |
32 | | |
33 | 104 | auto add_arg = [&] { |
34 | 104 | unsigned maybe_num{0}; |
35 | 172 | while ('0' <= *it && *it <= '9') { |
36 | 68 | maybe_num *= 10; |
37 | 68 | maybe_num += *it - '0'; |
38 | 68 | ++it; |
39 | 68 | } |
40 | | |
41 | 104 | if (*it == '$') { |
42 | 56 | ++it; |
43 | | // Positional specifier, like %8$s |
44 | 56 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; |
45 | 48 | count_pos = std::max(count_pos, maybe_num); |
46 | 48 | } else { |
47 | | // Non-positional specifier, like %s |
48 | 48 | ++count_normal; |
49 | 48 | } |
50 | 104 | }; void util::detail::CheckNumFormatSpecifiers<0u>(char const*)::'lambda'()::operator()() const Line | Count | Source | 33 | 4 | auto add_arg = [&] { | 34 | 4 | unsigned maybe_num{0}; | 35 | 7 | while ('0' <= *it && *it <= '9') { | 36 | 3 | maybe_num *= 10; | 37 | 3 | maybe_num += *it - '0'; | 38 | 3 | ++it; | 39 | 3 | } | 40 | | | 41 | 4 | if (*it == '$') { | 42 | 3 | ++it; | 43 | | // Positional specifier, like %8$s | 44 | 3 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; | 45 | 1 | count_pos = std::max(count_pos, maybe_num); | 46 | 1 | } else { | 47 | | // Non-positional specifier, like %s | 48 | 1 | ++count_normal; | 49 | 1 | } | 50 | 4 | }; |
void util::detail::CheckNumFormatSpecifiers<1u>(char const*)::'lambda'()::operator()() const Line | Count | Source | 33 | 41 | auto add_arg = [&] { | 34 | 41 | unsigned maybe_num{0}; | 35 | 64 | while ('0' <= *it && *it <= '9') { | 36 | 23 | maybe_num *= 10; | 37 | 23 | maybe_num += *it - '0'; | 38 | 23 | ++it; | 39 | 23 | } | 40 | | | 41 | 41 | if (*it == '$') { | 42 | 11 | ++it; | 43 | | // Positional specifier, like %8$s | 44 | 11 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; | 45 | 9 | count_pos = std::max(count_pos, maybe_num); | 46 | 30 | } else { | 47 | | // Non-positional specifier, like %s | 48 | 30 | ++count_normal; | 49 | 30 | } | 50 | 41 | }; |
void util::detail::CheckNumFormatSpecifiers<2u>(char const*)::'lambda'()::operator()() const Line | Count | Source | 33 | 29 | auto add_arg = [&] { | 34 | 29 | unsigned maybe_num{0}; | 35 | 46 | while ('0' <= *it && *it <= '9') { | 36 | 17 | maybe_num *= 10; | 37 | 17 | maybe_num += *it - '0'; | 38 | 17 | ++it; | 39 | 17 | } | 40 | | | 41 | 29 | if (*it == '$') { | 42 | 18 | ++it; | 43 | | // Positional specifier, like %8$s | 44 | 18 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; | 45 | 16 | count_pos = std::max(count_pos, maybe_num); | 46 | 16 | } else { | 47 | | // Non-positional specifier, like %s | 48 | 11 | ++count_normal; | 49 | 11 | } | 50 | 29 | }; |
void util::detail::CheckNumFormatSpecifiers<129u>(char const*)::'lambda'()::operator()() const Line | Count | Source | 33 | 2 | auto add_arg = [&] { | 34 | 2 | unsigned maybe_num{0}; | 35 | 6 | while ('0' <= *it && *it <= '9') { | 36 | 4 | maybe_num *= 10; | 37 | 4 | maybe_num += *it - '0'; | 38 | 4 | ++it; | 39 | 4 | } | 40 | | | 41 | 2 | if (*it == '$') { | 42 | 2 | ++it; | 43 | | // Positional specifier, like %8$s | 44 | 2 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; | 45 | 2 | count_pos = std::max(count_pos, maybe_num); | 46 | 2 | } else { | 47 | | // Non-positional specifier, like %s | 48 | 0 | ++count_normal; | 49 | 0 | } | 50 | 2 | }; |
void util::detail::CheckNumFormatSpecifiers<3u>(char const*)::'lambda'()::operator()() const Line | Count | Source | 33 | 25 | auto add_arg = [&] { | 34 | 25 | unsigned maybe_num{0}; | 35 | 43 | while ('0' <= *it && *it <= '9') { | 36 | 18 | maybe_num *= 10; | 37 | 18 | maybe_num += *it - '0'; | 38 | 18 | ++it; | 39 | 18 | } | 40 | | | 41 | 25 | if (*it == '$') { | 42 | 19 | ++it; | 43 | | // Positional specifier, like %8$s | 44 | 19 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; | 45 | 17 | count_pos = std::max(count_pos, maybe_num); | 46 | 17 | } else { | 47 | | // Non-positional specifier, like %s | 48 | 6 | ++count_normal; | 49 | 6 | } | 50 | 25 | }; |
void util::detail::CheckNumFormatSpecifiers<4u>(char const*)::'lambda'()::operator()() const Line | Count | Source | 33 | 3 | auto add_arg = [&] { | 34 | 3 | unsigned maybe_num{0}; | 35 | 6 | while ('0' <= *it && *it <= '9') { | 36 | 3 | maybe_num *= 10; | 37 | 3 | maybe_num += *it - '0'; | 38 | 3 | ++it; | 39 | 3 | } | 40 | | | 41 | 3 | if (*it == '$') { | 42 | 3 | ++it; | 43 | | // Positional specifier, like %8$s | 44 | 3 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; | 45 | 3 | count_pos = std::max(count_pos, maybe_num); | 46 | 3 | } else { | 47 | | // Non-positional specifier, like %s | 48 | 0 | ++count_normal; | 49 | 0 | } | 50 | 3 | }; |
|
51 | | |
52 | | // Increase argument count and consume positional specifier, if present. |
53 | 70 | add_arg(); |
54 | | |
55 | | // Consume flags. |
56 | 84 | while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it; |
57 | | |
58 | 90 | auto parse_size = [&] { |
59 | 90 | if (*it == '*') { |
60 | 34 | ++it; |
61 | 34 | add_arg(); |
62 | 56 | } else { |
63 | 68 | while ('0' <= *it && *it <= '9') ++it; |
64 | 56 | } |
65 | 90 | }; void util::detail::CheckNumFormatSpecifiers<0u>(char const*)::'lambda0'()::operator()() const Line | Count | Source | 58 | 2 | auto parse_size = [&] { | 59 | 2 | if (*it == '*') { | 60 | 0 | ++it; | 61 | 0 | add_arg(); | 62 | 2 | } else { | 63 | 2 | while ('0' <= *it && *it <= '9') ++it; | 64 | 2 | } | 65 | 2 | }; |
void util::detail::CheckNumFormatSpecifiers<1u>(char const*)::'lambda0'()::operator()() const Line | Count | Source | 58 | 43 | auto parse_size = [&] { | 59 | 43 | if (*it == '*') { | 60 | 5 | ++it; | 61 | 5 | add_arg(); | 62 | 38 | } else { | 63 | 46 | while ('0' <= *it && *it <= '9') ++it; | 64 | 38 | } | 65 | 43 | }; |
void util::detail::CheckNumFormatSpecifiers<2u>(char const*)::'lambda0'()::operator()() const Line | Count | Source | 58 | 22 | auto parse_size = [&] { | 59 | 22 | if (*it == '*') { | 60 | 12 | ++it; | 61 | 12 | add_arg(); | 62 | 12 | } else { | 63 | 11 | while ('0' <= *it && *it <= '9') ++it; | 64 | 10 | } | 65 | 22 | }; |
void util::detail::CheckNumFormatSpecifiers<129u>(char const*)::'lambda0'()::operator()() const Line | Count | Source | 58 | 2 | auto parse_size = [&] { | 59 | 2 | if (*it == '*') { | 60 | 0 | ++it; | 61 | 0 | add_arg(); | 62 | 2 | } else { | 63 | 2 | while ('0' <= *it && *it <= '9') ++it; | 64 | 2 | } | 65 | 2 | }; |
void util::detail::CheckNumFormatSpecifiers<3u>(char const*)::'lambda0'()::operator()() const Line | Count | Source | 58 | 19 | auto parse_size = [&] { | 59 | 19 | if (*it == '*') { | 60 | 15 | ++it; | 61 | 15 | add_arg(); | 62 | 15 | } else { | 63 | 7 | while ('0' <= *it && *it <= '9') ++it; | 64 | 4 | } | 65 | 19 | }; |
void util::detail::CheckNumFormatSpecifiers<4u>(char const*)::'lambda0'()::operator()() const Line | Count | Source | 58 | 2 | auto parse_size = [&] { | 59 | 2 | if (*it == '*') { | 60 | 2 | ++it; | 61 | 2 | add_arg(); | 62 | 2 | } else { | 63 | 0 | while ('0' <= *it && *it <= '9') ++it; | 64 | 0 | } | 65 | 2 | }; |
|
66 | | |
67 | | // Consume dynamic or static width value. |
68 | 70 | parse_size(); |
69 | | |
70 | | // Consume dynamic or static precision value. |
71 | 70 | if (*it == '.') { |
72 | 24 | ++it; |
73 | 24 | parse_size(); |
74 | 24 | } |
75 | | |
76 | 70 | if (*it == '\0') throw "Format specifier incorrectly terminated by end of string"; |
77 | | |
78 | | // Length and type in "[flags][width][.precision][length]type" |
79 | | // is not checked. Parsing continues with the next '%'. |
80 | 70 | } |
81 | 59 | if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!"; |
82 | 54 | unsigned count{count_normal | count_pos}; |
83 | 54 | if (num_params != count) throw "Format specifier count must match the argument count!"; |
84 | 54 | } void util::detail::CheckNumFormatSpecifiers<2u>(char const*) Line | Count | Source | 27 | 16 | { | 28 | 16 | unsigned count_normal{0}; // Number of "normal" specifiers, like %s | 29 | 16 | unsigned count_pos{0}; // Max number in positional specifier, like %8$s | 30 | 35 | for (auto it{str}; *it != '\0'; ++it) { | 31 | 22 | if (*it != '%' || *++it == '%') continue; // Skip escaped %% | 32 | | | 33 | 17 | auto add_arg = [&] { | 34 | 17 | unsigned maybe_num{0}; | 35 | 17 | while ('0' <= *it && *it <= '9') { | 36 | 17 | maybe_num *= 10; | 37 | 17 | maybe_num += *it - '0'; | 38 | 17 | ++it; | 39 | 17 | } | 40 | | | 41 | 17 | if (*it == '$') { | 42 | 17 | ++it; | 43 | | // Positional specifier, like %8$s | 44 | 17 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; | 45 | 17 | count_pos = std::max(count_pos, maybe_num); | 46 | 17 | } else { | 47 | | // Non-positional specifier, like %s | 48 | 17 | ++count_normal; | 49 | 17 | } | 50 | 17 | }; | 51 | | | 52 | | // Increase argument count and consume positional specifier, if present. | 53 | 17 | add_arg(); | 54 | | | 55 | | // Consume flags. | 56 | 18 | while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it; | 57 | | | 58 | 17 | auto parse_size = [&] { | 59 | 17 | if (*it == '*') { | 60 | 17 | ++it; | 61 | 17 | add_arg(); | 62 | 17 | } else { | 63 | 17 | while ('0' <= *it && *it <= '9') ++it; | 64 | 17 | } | 65 | 17 | }; | 66 | | | 67 | | // Consume dynamic or static width value. | 68 | 17 | parse_size(); | 69 | | | 70 | | // Consume dynamic or static precision value. | 71 | 17 | if (*it == '.') { | 72 | 5 | ++it; | 73 | 5 | parse_size(); | 74 | 5 | } | 75 | | | 76 | 17 | if (*it == '\0') throw "Format specifier incorrectly terminated by end of string"; | 77 | | | 78 | | // Length and type in "[flags][width][.precision][length]type" | 79 | | // is not checked. Parsing continues with the next '%'. | 80 | 17 | } | 81 | 13 | if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!"; | 82 | 9 | unsigned count{count_normal | count_pos}; | 83 | 9 | if (num_params != count) throw "Format specifier count must match the argument count!"; | 84 | 9 | } |
void util::detail::CheckNumFormatSpecifiers<1u>(char const*) Line | Count | Source | 27 | 35 | { | 28 | 35 | unsigned count_normal{0}; // Number of "normal" specifiers, like %s | 29 | 35 | unsigned count_pos{0}; // Max number in positional specifier, like %8$s | 30 | 64 | for (auto it{str}; *it != '\0'; ++it) { | 31 | 39 | if (*it != '%' || *++it == '%') continue; // Skip escaped %% | 32 | | | 33 | 36 | auto add_arg = [&] { | 34 | 36 | unsigned maybe_num{0}; | 35 | 36 | while ('0' <= *it && *it <= '9') { | 36 | 36 | maybe_num *= 10; | 37 | 36 | maybe_num += *it - '0'; | 38 | 36 | ++it; | 39 | 36 | } | 40 | | | 41 | 36 | if (*it == '$') { | 42 | 36 | ++it; | 43 | | // Positional specifier, like %8$s | 44 | 36 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; | 45 | 36 | count_pos = std::max(count_pos, maybe_num); | 46 | 36 | } else { | 47 | | // Non-positional specifier, like %s | 48 | 36 | ++count_normal; | 49 | 36 | } | 50 | 36 | }; | 51 | | | 52 | | // Increase argument count and consume positional specifier, if present. | 53 | 36 | add_arg(); | 54 | | | 55 | | // Consume flags. | 56 | 40 | while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it; | 57 | | | 58 | 36 | auto parse_size = [&] { | 59 | 36 | if (*it == '*') { | 60 | 36 | ++it; | 61 | 36 | add_arg(); | 62 | 36 | } else { | 63 | 36 | while ('0' <= *it && *it <= '9') ++it; | 64 | 36 | } | 65 | 36 | }; | 66 | | | 67 | | // Consume dynamic or static width value. | 68 | 36 | parse_size(); | 69 | | | 70 | | // Consume dynamic or static precision value. | 71 | 36 | if (*it == '.') { | 72 | 9 | ++it; | 73 | 9 | parse_size(); | 74 | 9 | } | 75 | | | 76 | 36 | if (*it == '\0') throw "Format specifier incorrectly terminated by end of string"; | 77 | | | 78 | | // Length and type in "[flags][width][.precision][length]type" | 79 | | // is not checked. Parsing continues with the next '%'. | 80 | 36 | } | 81 | 25 | if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!"; | 82 | 24 | unsigned count{count_normal | count_pos}; | 83 | 24 | if (num_params != count) throw "Format specifier count must match the argument count!"; | 84 | 24 | } |
void util::detail::CheckNumFormatSpecifiers<3u>(char const*) Line | Count | Source | 27 | 10 | { | 28 | 10 | unsigned count_normal{0}; // Number of "normal" specifiers, like %s | 29 | 10 | unsigned count_pos{0}; // Max number in positional specifier, like %8$s | 30 | 24 | for (auto it{str}; *it != '\0'; ++it) { | 31 | 14 | if (*it != '%' || *++it == '%') continue; // Skip escaped %% | 32 | | | 33 | 10 | auto add_arg = [&] { | 34 | 10 | unsigned maybe_num{0}; | 35 | 10 | while ('0' <= *it && *it <= '9') { | 36 | 10 | maybe_num *= 10; | 37 | 10 | maybe_num += *it - '0'; | 38 | 10 | ++it; | 39 | 10 | } | 40 | | | 41 | 10 | if (*it == '$') { | 42 | 10 | ++it; | 43 | | // Positional specifier, like %8$s | 44 | 10 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; | 45 | 10 | count_pos = std::max(count_pos, maybe_num); | 46 | 10 | } else { | 47 | | // Non-positional specifier, like %s | 48 | 10 | ++count_normal; | 49 | 10 | } | 50 | 10 | }; | 51 | | | 52 | | // Increase argument count and consume positional specifier, if present. | 53 | 10 | add_arg(); | 54 | | | 55 | | // Consume flags. | 56 | 19 | while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it; | 57 | | | 58 | 10 | auto parse_size = [&] { | 59 | 10 | if (*it == '*') { | 60 | 10 | ++it; | 61 | 10 | add_arg(); | 62 | 10 | } else { | 63 | 10 | while ('0' <= *it && *it <= '9') ++it; | 64 | 10 | } | 65 | 10 | }; | 66 | | | 67 | | // Consume dynamic or static width value. | 68 | 10 | parse_size(); | 69 | | | 70 | | // Consume dynamic or static precision value. | 71 | 10 | if (*it == '.') { | 72 | 9 | ++it; | 73 | 9 | parse_size(); | 74 | 9 | } | 75 | | | 76 | 10 | if (*it == '\0') throw "Format specifier incorrectly terminated by end of string"; | 77 | | | 78 | | // Length and type in "[flags][width][.precision][length]type" | 79 | | // is not checked. Parsing continues with the next '%'. | 80 | 10 | } | 81 | 10 | if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!"; | 82 | 10 | unsigned count{count_normal | count_pos}; | 83 | 10 | if (num_params != count) throw "Format specifier count must match the argument count!"; | 84 | 10 | } |
Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<5u>(char const*) void util::detail::CheckNumFormatSpecifiers<0u>(char const*) Line | Count | Source | 27 | 9 | { | 28 | 9 | unsigned count_normal{0}; // Number of "normal" specifiers, like %s | 29 | 9 | unsigned count_pos{0}; // Max number in positional specifier, like %8$s | 30 | 22 | for (auto it{str}; *it != '\0'; ++it) { | 31 | 13 | if (*it != '%' || *++it == '%') continue; // Skip escaped %% | 32 | | | 33 | 4 | auto add_arg = [&] { | 34 | 4 | unsigned maybe_num{0}; | 35 | 4 | while ('0' <= *it && *it <= '9') { | 36 | 4 | maybe_num *= 10; | 37 | 4 | maybe_num += *it - '0'; | 38 | 4 | ++it; | 39 | 4 | } | 40 | | | 41 | 4 | if (*it == '$') { | 42 | 4 | ++it; | 43 | | // Positional specifier, like %8$s | 44 | 4 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; | 45 | 4 | count_pos = std::max(count_pos, maybe_num); | 46 | 4 | } else { | 47 | | // Non-positional specifier, like %s | 48 | 4 | ++count_normal; | 49 | 4 | } | 50 | 4 | }; | 51 | | | 52 | | // Increase argument count and consume positional specifier, if present. | 53 | 4 | add_arg(); | 54 | | | 55 | | // Consume flags. | 56 | 4 | while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it; | 57 | | | 58 | 4 | auto parse_size = [&] { | 59 | 4 | if (*it == '*') { | 60 | 4 | ++it; | 61 | 4 | add_arg(); | 62 | 4 | } else { | 63 | 4 | while ('0' <= *it && *it <= '9') ++it; | 64 | 4 | } | 65 | 4 | }; | 66 | | | 67 | | // Consume dynamic or static width value. | 68 | 4 | parse_size(); | 69 | | | 70 | | // Consume dynamic or static precision value. | 71 | 4 | if (*it == '.') { | 72 | 0 | ++it; | 73 | 0 | parse_size(); | 74 | 0 | } | 75 | | | 76 | 4 | if (*it == '\0') throw "Format specifier incorrectly terminated by end of string"; | 77 | | | 78 | | // Length and type in "[flags][width][.precision][length]type" | 79 | | // is not checked. Parsing continues with the next '%'. | 80 | 4 | } | 81 | 9 | if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!"; | 82 | 9 | unsigned count{count_normal | count_pos}; | 83 | 9 | if (num_params != count) throw "Format specifier count must match the argument count!"; | 84 | 9 | } |
Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<6u>(char const*) void util::detail::CheckNumFormatSpecifiers<4u>(char const*) Line | Count | Source | 27 | 1 | { | 28 | 1 | unsigned count_normal{0}; // Number of "normal" specifiers, like %s | 29 | 1 | unsigned count_pos{0}; // Max number in positional specifier, like %8$s | 30 | 2 | for (auto it{str}; *it != '\0'; ++it) { | 31 | 1 | if (*it != '%' || *++it == '%') continue; // Skip escaped %% | 32 | | | 33 | 1 | auto add_arg = [&] { | 34 | 1 | unsigned maybe_num{0}; | 35 | 1 | while ('0' <= *it && *it <= '9') { | 36 | 1 | maybe_num *= 10; | 37 | 1 | maybe_num += *it - '0'; | 38 | 1 | ++it; | 39 | 1 | } | 40 | | | 41 | 1 | if (*it == '$') { | 42 | 1 | ++it; | 43 | | // Positional specifier, like %8$s | 44 | 1 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; | 45 | 1 | count_pos = std::max(count_pos, maybe_num); | 46 | 1 | } else { | 47 | | // Non-positional specifier, like %s | 48 | 1 | ++count_normal; | 49 | 1 | } | 50 | 1 | }; | 51 | | | 52 | | // Increase argument count and consume positional specifier, if present. | 53 | 1 | add_arg(); | 54 | | | 55 | | // Consume flags. | 56 | 1 | while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it; | 57 | | | 58 | 1 | auto parse_size = [&] { | 59 | 1 | if (*it == '*') { | 60 | 1 | ++it; | 61 | 1 | add_arg(); | 62 | 1 | } else { | 63 | 1 | while ('0' <= *it && *it <= '9') ++it; | 64 | 1 | } | 65 | 1 | }; | 66 | | | 67 | | // Consume dynamic or static width value. | 68 | 1 | parse_size(); | 69 | | | 70 | | // Consume dynamic or static precision value. | 71 | 1 | if (*it == '.') { | 72 | 1 | ++it; | 73 | 1 | parse_size(); | 74 | 1 | } | 75 | | | 76 | 1 | if (*it == '\0') throw "Format specifier incorrectly terminated by end of string"; | 77 | | | 78 | | // Length and type in "[flags][width][.precision][length]type" | 79 | | // is not checked. Parsing continues with the next '%'. | 80 | 1 | } | 81 | 1 | if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!"; | 82 | 1 | unsigned count{count_normal | count_pos}; | 83 | 1 | if (num_params != count) throw "Format specifier count must match the argument count!"; | 84 | 1 | } |
void util::detail::CheckNumFormatSpecifiers<129u>(char const*) Line | Count | Source | 27 | 1 | { | 28 | 1 | unsigned count_normal{0}; // Number of "normal" specifiers, like %s | 29 | 1 | unsigned count_pos{0}; // Max number in positional specifier, like %8$s | 30 | 10 | for (auto it{str}; *it != '\0'; ++it) { | 31 | 9 | if (*it != '%' || *++it == '%') continue; // Skip escaped %% | 32 | | | 33 | 2 | auto add_arg = [&] { | 34 | 2 | unsigned maybe_num{0}; | 35 | 2 | while ('0' <= *it && *it <= '9') { | 36 | 2 | maybe_num *= 10; | 37 | 2 | maybe_num += *it - '0'; | 38 | 2 | ++it; | 39 | 2 | } | 40 | | | 41 | 2 | if (*it == '$') { | 42 | 2 | ++it; | 43 | | // Positional specifier, like %8$s | 44 | 2 | if (maybe_num == 0) throw "Positional format specifier must have position of at least 1"; | 45 | 2 | count_pos = std::max(count_pos, maybe_num); | 46 | 2 | } else { | 47 | | // Non-positional specifier, like %s | 48 | 2 | ++count_normal; | 49 | 2 | } | 50 | 2 | }; | 51 | | | 52 | | // Increase argument count and consume positional specifier, if present. | 53 | 2 | add_arg(); | 54 | | | 55 | | // Consume flags. | 56 | 2 | while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it; | 57 | | | 58 | 2 | auto parse_size = [&] { | 59 | 2 | if (*it == '*') { | 60 | 2 | ++it; | 61 | 2 | add_arg(); | 62 | 2 | } else { | 63 | 2 | while ('0' <= *it && *it <= '9') ++it; | 64 | 2 | } | 65 | 2 | }; | 66 | | | 67 | | // Consume dynamic or static width value. | 68 | 2 | parse_size(); | 69 | | | 70 | | // Consume dynamic or static precision value. | 71 | 2 | if (*it == '.') { | 72 | 0 | ++it; | 73 | 0 | parse_size(); | 74 | 0 | } | 75 | | | 76 | 2 | if (*it == '\0') throw "Format specifier incorrectly terminated by end of string"; | 77 | | | 78 | | // Length and type in "[flags][width][.precision][length]type" | 79 | | // is not checked. Parsing continues with the next '%'. | 80 | 2 | } | 81 | 1 | if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!"; | 82 | 1 | unsigned count{count_normal | count_pos}; | 83 | 1 | if (num_params != count) throw "Format specifier count must match the argument count!"; | 84 | 1 | } |
Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<7u>(char const*) Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<18u>(char const*) Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<19u>(char const*) Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<12u>(char const*) Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<8u>(char const*) |
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 | | /// Replace every non-overlapping occurrence of `search` with `substitute`, treating both literally; the replacement text is not searched again. |
102 | | void ReplaceAll(std::string& in_out, std::string_view search, std::string_view substitute); |
103 | | |
104 | | /** Split a string on any char found in separators, returning a vector. |
105 | | * |
106 | | * If sep does not occur in sp, a singleton with the entirety of sp is returned. |
107 | | * |
108 | | * @param[in] include_sep Whether to include the separator at the end of the left side of the splits. |
109 | | * |
110 | | * Note that this function does not care about braces, so splitting |
111 | | * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}. |
112 | | * |
113 | | * If include_sep == true, splitting "foo(bar(1),2),3) on ',' |
114 | | * will return: |
115 | | * - foo(bar(1), |
116 | | * - 2), |
117 | | * - 3) |
118 | | */ |
119 | | template <typename T = std::span<const char>> |
120 | | std::vector<T> Split(std::span<const char> sp LIFETIMEBOUND, std::string_view separators, bool include_sep = false) |
121 | 1.74M | { |
122 | 1.74M | std::vector<T> ret; |
123 | 1.74M | auto it = sp.begin(); |
124 | 1.74M | auto start = it; |
125 | 26.0M | while (it != sp.end()) { |
126 | 24.2M | if (separators.find(*it) != std::string::npos) { |
127 | 651k | if (include_sep) { |
128 | 189 | ret.emplace_back(start, it + 1); |
129 | 650k | } else { |
130 | 650k | ret.emplace_back(start, it); |
131 | 650k | } |
132 | 651k | start = it + 1; |
133 | 651k | } |
134 | 24.2M | ++it; |
135 | 24.2M | } |
136 | 1.74M | ret.emplace_back(start, it); |
137 | 1.74M | return ret; |
138 | 1.74M | } std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> util::Split<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>(std::span<char const, 18446744073709551615ul>, std::basic_string_view<char, std::char_traits<char>>, bool) Line | Count | Source | 121 | 1.29M | { | 122 | 1.29M | std::vector<T> ret; | 123 | 1.29M | auto it = sp.begin(); | 124 | 1.29M | auto start = it; | 125 | 12.9M | while (it != sp.end()) { | 126 | 11.6M | if (separators.find(*it) != std::string::npos) { | 127 | 39.4k | if (include_sep) { | 128 | 0 | ret.emplace_back(start, it + 1); | 129 | 39.4k | } else { | 130 | 39.4k | ret.emplace_back(start, it); | 131 | 39.4k | } | 132 | 39.4k | start = it + 1; | 133 | 39.4k | } | 134 | 11.6M | ++it; | 135 | 11.6M | } | 136 | 1.29M | ret.emplace_back(start, it); | 137 | 1.29M | return ret; | 138 | 1.29M | } |
std::vector<std::span<char const, 18446744073709551615ul>, std::allocator<std::span<char const, 18446744073709551615ul>>> util::Split<std::span<char const, 18446744073709551615ul>>(std::span<char const, 18446744073709551615ul>, std::basic_string_view<char, std::char_traits<char>>, bool) Line | Count | Source | 121 | 77.0k | { | 122 | 77.0k | std::vector<T> ret; | 123 | 77.0k | auto it = sp.begin(); | 124 | 77.0k | auto start = it; | 125 | 8.95M | while (it != sp.end()) { | 126 | 8.87M | if (separators.find(*it) != std::string::npos) { | 127 | 52.7k | if (include_sep) { | 128 | 189 | ret.emplace_back(start, it + 1); | 129 | 52.5k | } else { | 130 | 52.5k | ret.emplace_back(start, it); | 131 | 52.5k | } | 132 | 52.7k | start = it + 1; | 133 | 52.7k | } | 134 | 8.87M | ++it; | 135 | 8.87M | } | 136 | 77.0k | ret.emplace_back(start, it); | 137 | 77.0k | return ret; | 138 | 77.0k | } |
std::vector<std::basic_string_view<char, std::char_traits<char>>, std::allocator<std::basic_string_view<char, std::char_traits<char>>>> util::Split<std::basic_string_view<char, std::char_traits<char>>>(std::span<char const, 18446744073709551615ul>, std::basic_string_view<char, std::char_traits<char>>, bool) Line | Count | Source | 121 | 372k | { | 122 | 372k | std::vector<T> ret; | 123 | 372k | auto it = sp.begin(); | 124 | 372k | auto start = it; | 125 | 4.14M | while (it != sp.end()) { | 126 | 3.77M | if (separators.find(*it) != std::string::npos) { | 127 | 558k | if (include_sep) { | 128 | 0 | ret.emplace_back(start, it + 1); | 129 | 558k | } else { | 130 | 558k | ret.emplace_back(start, it); | 131 | 558k | } | 132 | 558k | start = it + 1; | 133 | 558k | } | 134 | 3.77M | ++it; | 135 | 3.77M | } | 136 | 372k | ret.emplace_back(start, it); | 137 | 372k | return ret; | 138 | 372k | } |
|
139 | | |
140 | | /** Split a string on every instance of sep, returning a vector. |
141 | | * |
142 | | * If sep does not occur in sp, a singleton with the entirety of sp is returned. |
143 | | * |
144 | | * Note that this function does not care about braces, so splitting |
145 | | * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}. |
146 | | */ |
147 | | template <typename T = std::span<const char>> |
148 | | std::vector<T> Split(std::span<const char> sp LIFETIMEBOUND, char sep, bool include_sep = false) |
149 | 1.36M | { |
150 | 1.36M | return Split<T>(sp, std::string_view{&sep, 1}, include_sep); |
151 | 1.36M | } std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> util::Split<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>(std::span<char const, 18446744073709551615ul>, char, bool) Line | Count | Source | 149 | 1.28M | { | 150 | 1.28M | return Split<T>(sp, std::string_view{&sep, 1}, include_sep); | 151 | 1.28M | } |
std::vector<std::span<char const, 18446744073709551615ul>, std::allocator<std::span<char const, 18446744073709551615ul>>> util::Split<std::span<char const, 18446744073709551615ul>>(std::span<char const, 18446744073709551615ul>, char, bool) Line | Count | Source | 149 | 76.6k | { | 150 | 76.6k | return Split<T>(sp, std::string_view{&sep, 1}, include_sep); | 151 | 76.6k | } |
std::vector<std::basic_string_view<char, std::char_traits<char>>, std::allocator<std::basic_string_view<char, std::char_traits<char>>>> util::Split<std::basic_string_view<char, std::char_traits<char>>>(std::span<char const, 18446744073709551615ul>, char, bool) Line | Count | Source | 149 | 53 | { | 150 | 53 | return Split<T>(sp, std::string_view{&sep, 1}, include_sep); | 151 | 53 | } |
|
152 | | |
153 | | [[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, char sep) |
154 | 1.28M | { |
155 | 1.28M | return Split<std::string>(str, sep); |
156 | 1.28M | } |
157 | | |
158 | | [[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, std::string_view separators) |
159 | 2.83k | { |
160 | 2.83k | return Split<std::string>(str, separators); |
161 | 2.83k | } |
162 | | |
163 | | [[nodiscard]] inline std::string_view TrimStringView(std::string_view str LIFETIMEBOUND, std::string_view pattern = " \f\n\r\t\v") |
164 | 2.39M | { |
165 | 2.39M | std::string::size_type front = str.find_first_not_of(pattern); |
166 | 2.39M | if (front == std::string::npos) { |
167 | 103 | return {}; |
168 | 103 | } |
169 | 2.39M | std::string::size_type end = str.find_last_not_of(pattern); |
170 | 2.39M | return str.substr(front, end - front + 1); |
171 | 2.39M | } |
172 | | |
173 | | [[nodiscard]] inline std::string TrimString(std::string_view str, std::string_view pattern = " \f\n\r\t\v") |
174 | 1.60M | { |
175 | 1.60M | return std::string(TrimStringView(str, pattern)); |
176 | 1.60M | } |
177 | | |
178 | | [[nodiscard]] inline std::string_view RemoveSuffixView(std::string_view str LIFETIMEBOUND, std::string_view suffix) |
179 | 1.61k | { |
180 | 1.61k | if (str.ends_with(suffix)) { |
181 | 1.61k | return str.substr(0, str.size() - suffix.size()); |
182 | 1.61k | } |
183 | 0 | return str; |
184 | 1.61k | } |
185 | | |
186 | | [[nodiscard]] inline std::string_view RemovePrefixView(std::string_view str LIFETIMEBOUND, std::string_view prefix) |
187 | 5.74M | { |
188 | 5.74M | if (str.starts_with(prefix)) { |
189 | 72 | return str.substr(prefix.size()); |
190 | 72 | } |
191 | 5.74M | return str; |
192 | 5.74M | } |
193 | | |
194 | | [[nodiscard]] inline std::string RemovePrefix(std::string_view str, std::string_view prefix) |
195 | 11 | { |
196 | 11 | return std::string(RemovePrefixView(str, prefix)); |
197 | 11 | } |
198 | | |
199 | | /** |
200 | | * Join all container items. Typically used to concatenate strings but accepts |
201 | | * containers with elements of any type. |
202 | | * |
203 | | * @param container The items to join |
204 | | * @param separator The separator |
205 | | * @param unary_op Apply this operator to each item |
206 | | */ |
207 | | template <typename C, typename S, typename UnaryOp> |
208 | | // NOLINTNEXTLINE(misc-no-recursion) |
209 | | auto Join(const C& container, const S& separator, UnaryOp unary_op) |
210 | 283k | { |
211 | 283k | decltype(unary_op(*container.begin())) ret; |
212 | 283k | bool first{true}; |
213 | 1.30M | for (const auto& item : container) { |
214 | 1.30M | if (!first) ret += separator; |
215 | 1.30M | ret += unary_op(item); |
216 | 1.30M | first = false; |
217 | 1.30M | } |
218 | 283k | return ret; |
219 | 283k | } auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [2], util::MakeUnorderedList(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)::'lambda'(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&)>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [2], util::MakeUnorderedList(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)::'lambda'(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&)) Line | Count | Source | 210 | 2.47k | { | 211 | 2.47k | decltype(unary_op(*container.begin())) ret; | 212 | 2.47k | bool first{true}; | 213 | 14.8k | for (const auto& item : container) { | 214 | 14.8k | if (!first) ret += separator; | 215 | 14.8k | ret += unary_op(item); | 216 | 14.8k | first = false; | 217 | 14.8k | } | 218 | 2.47k | return ret; | 219 | 2.47k | } |
auto util::Join<std::vector<LogCategory, std::allocator<LogCategory>>, char [3], BCLog::Logger::LogCategoriesString[abi:cxx11]() const::'lambda'(LogCategory const&)>(std::vector<LogCategory, std::allocator<LogCategory>> const&, char const (&) [3], BCLog::Logger::LogCategoriesString[abi:cxx11]() const::'lambda'(LogCategory const&)) Line | Count | Source | 210 | 6.48k | { | 211 | 6.48k | decltype(unary_op(*container.begin())) ret; | 212 | 6.48k | bool first{true}; | 213 | 194k | for (const auto& item : container) { | 214 | 194k | if (!first) ret += separator; | 215 | 194k | ret += unary_op(item); | 216 | 194k | first = false; | 217 | 194k | } | 218 | 6.48k | return ret; | 219 | 6.48k | } |
auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [2], auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [2]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [2])::'lambda'(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [2], auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [2]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [2])::'lambda'(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)) Line | Count | Source | 210 | 184 | { | 211 | 184 | decltype(unary_op(*container.begin())) ret; | 212 | 184 | bool first{true}; | 213 | 226 | for (const auto& item : container) { | 214 | 226 | if (!first) ret += separator; | 215 | 226 | ret += unary_op(item); | 216 | 226 | first = false; | 217 | 226 | } | 218 | 184 | return ret; | 219 | 184 | } |
auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [3], auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [3]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [3])::'lambda'(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [3], auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [3]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [3])::'lambda'(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)) Line | Count | Source | 210 | 119k | { | 211 | 119k | decltype(unary_op(*container.begin())) ret; | 212 | 119k | bool first{true}; | 213 | 958k | for (const auto& item : container) { | 214 | 958k | if (!first) ret += separator; | 215 | 958k | ret += unary_op(item); | 216 | 958k | first = false; | 217 | 958k | } | 218 | 119k | return ret; | 219 | 119k | } |
util_tests.cpp:auto util::Join<std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [3], util_tests::util_Join::test_method()::$_0>(std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [3], util_tests::util_Join::test_method()::$_0) Line | Count | Source | 210 | 6 | { | 211 | 6 | decltype(unary_op(*container.begin())) ret; | 212 | 6 | bool first{true}; | 213 | 6 | for (const auto& item : container) { | 214 | 6 | if (!first) ret += separator; | 215 | 6 | ret += unary_op(item); | 216 | 6 | first = false; | 217 | 6 | } | 218 | 6 | return ret; | 219 | 6 | } |
coinselection_tests.cpp:auto util::Join<std::set<std::shared_ptr<wallet::COutput>, wallet::OutputPtrComparator, std::allocator<std::shared_ptr<wallet::COutput>>>, char [2], wallet::coinselection_tests::InputAmountsToString[abi:cxx11](wallet::SelectionResult const&)::$_0>(std::set<std::shared_ptr<wallet::COutput>, wallet::OutputPtrComparator, std::allocator<std::shared_ptr<wallet::COutput>>> const&, char const (&) [2], wallet::coinselection_tests::InputAmountsToString[abi:cxx11](wallet::SelectionResult const&)::$_0) Line | Count | Source | 210 | 208 | { | 211 | 208 | decltype(unary_op(*container.begin())) ret; | 212 | 208 | bool first{true}; | 213 | 636 | for (const auto& item : container) { | 214 | 636 | if (!first) ret += separator; | 215 | 636 | ret += unary_op(item); | 216 | 636 | first = false; | 217 | 636 | } | 218 | 208 | return ret; | 219 | 208 | } |
blockfilter.cpp:auto util::Join<std::map<BlockFilterType, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::less<BlockFilterType>, std::allocator<std::pair<BlockFilterType const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>>, char [3], ListBlockFilterTypes()::$_0>(std::map<BlockFilterType, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::less<BlockFilterType>, std::allocator<std::pair<BlockFilterType const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>> const&, char const (&) [3], ListBlockFilterTypes()::$_0) Line | Count | Source | 210 | 1.37k | { | 211 | 1.37k | decltype(unary_op(*container.begin())) ret; | 212 | 1.37k | bool first{true}; | 213 | 1.37k | for (const auto& item : container) { | 214 | 1.37k | if (!first) ret += separator; | 215 | 1.37k | ret += unary_op(item); | 216 | 1.37k | first = false; | 217 | 1.37k | } | 218 | 1.37k | return ret; | 219 | 1.37k | } |
auto util::Join<std::vector<bilingual_str, std::allocator<bilingual_str>>, bilingual_str, auto util::Join<std::vector<bilingual_str, std::allocator<bilingual_str>>, bilingual_str>(std::vector<bilingual_str, std::allocator<bilingual_str>> const&, bilingual_str const&)::'lambda'(std::vector<bilingual_str, std::allocator<bilingual_str>> const&)>(std::vector<bilingual_str, std::allocator<bilingual_str>> const&, bilingual_str const&, auto util::Join<std::vector<bilingual_str, std::allocator<bilingual_str>>, bilingual_str>(std::vector<bilingual_str, std::allocator<bilingual_str>> const&, bilingual_str const&)::'lambda'(std::vector<bilingual_str, std::allocator<bilingual_str>> const&)) Line | Count | Source | 210 | 114k | { | 211 | 114k | decltype(unary_op(*container.begin())) ret; | 212 | 114k | bool first{true}; | 213 | 114k | for (const auto& item : container) { | 214 | 146 | if (!first) ret += separator; | 215 | 146 | ret += unary_op(item); | 216 | 146 | first = false; | 217 | 146 | } | 218 | 114k | return ret; | 219 | 114k | } |
validation.cpp:auto util::Join<std::vector<int, std::allocator<int>>, char [3], ChainstateManager::ActivateSnapshot(AutoFile&, node::SnapshotMetadata const&, bool)::$_0>(std::vector<int, std::allocator<int>> const&, char const (&) [3], ChainstateManager::ActivateSnapshot(AutoFile&, node::SnapshotMetadata const&, bool)::$_0) Line | Count | Source | 210 | 14 | { | 211 | 14 | decltype(unary_op(*container.begin())) ret; | 212 | 14 | bool first{true}; | 213 | 42 | for (const auto& item : container) { | 214 | 42 | if (!first) ret += separator; | 215 | 42 | ret += unary_op(item); | 216 | 42 | first = false; | 217 | 42 | } | 218 | 14 | return ret; | 219 | 14 | } |
messages.cpp:auto util::Join<std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, FeeEstimateMode>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, FeeEstimateMode>>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, common::FeeModes(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&)::$_0>(std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, FeeEstimateMode>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, FeeEstimateMode>>> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, common::FeeModes(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&)::$_0) Line | Count | Source | 210 | 13.9k | { | 211 | 13.9k | decltype(unary_op(*container.begin())) ret; | 212 | 13.9k | bool first{true}; | 213 | 41.9k | for (const auto& item : container) { | 214 | 41.9k | if (!first) ret += separator; | 215 | 41.9k | ret += unary_op(item); | 216 | 41.9k | first = false; | 217 | 41.9k | } | 218 | 13.9k | return ret; | 219 | 13.9k | } |
outputtype.cpp:auto util::Join<std::array<OutputType, 4ul>, char [3], FormatAllOutputTypes[abi:cxx11]()::$_0>(std::array<OutputType, 4ul> const&, char const (&) [3], FormatAllOutputTypes[abi:cxx11]()::$_0) Line | Count | Source | 210 | 22.1k | { | 211 | 22.1k | decltype(unary_op(*container.begin())) ret; | 212 | 22.1k | bool first{true}; | 213 | 88.7k | for (const auto& item : container) { | 214 | 88.7k | if (!first) ret += separator; | 215 | 88.7k | ret += unary_op(item); | 216 | 88.7k | first = false; | 217 | 88.7k | } | 218 | 22.1k | return ret; | 219 | 22.1k | } |
util.cpp:auto util::Join<std::vector<RPCArg, std::allocator<RPCArg>>, char [2], RPCArg::ToString[abi:cxx11](bool) const::$_0>(std::vector<RPCArg, std::allocator<RPCArg>> const&, char const (&) [2], RPCArg::ToString[abi:cxx11](bool) const::$_0) Line | Count | Source | 210 | 180 | { | 211 | 180 | decltype(unary_op(*container.begin())) ret; | 212 | 180 | bool first{true}; | 213 | 398 | for (const auto& item : container) { | 214 | 398 | if (!first) ret += separator; | 215 | 398 | ret += unary_op(item); | 216 | 398 | first = false; | 217 | 398 | } | 218 | 180 | return ret; | 219 | 180 | } |
logging.cpp:auto util::Join<std::vector<util::log::Level, std::allocator<util::log::Level>>, char [3], BCLog::Logger::LogLevelsString[abi:cxx11]() const::$_0>(std::vector<util::log::Level, std::allocator<util::log::Level>> const&, char const (&) [3], BCLog::Logger::LogLevelsString[abi:cxx11]() const::$_0) Line | Count | Source | 210 | 2.00k | { | 211 | 2.00k | decltype(unary_op(*container.begin())) ret; | 212 | 2.00k | bool first{true}; | 213 | 6.00k | for (const auto& item : container) { | 214 | 6.00k | if (!first) ret += separator; | 215 | 6.00k | ret += unary_op(item); | 216 | 6.00k | first = false; | 217 | 6.00k | } | 218 | 2.00k | return ret; | 219 | 2.00k | } |
|
220 | | |
221 | | template <typename C, typename S> |
222 | | auto Join(const C& container, const S& separator) |
223 | 234k | { |
224 | 959k | return Join(container, separator, [](const auto& i) { return i; });auto auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [2]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [2])::'lambda'(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)::operator()<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&) const Line | Count | Source | 224 | 226 | return Join(container, separator, [](const auto& i) { return i; }); |
auto auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [3]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [3])::'lambda'(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)::operator()<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&) const Line | Count | Source | 224 | 958k | return Join(container, separator, [](const auto& i) { return i; }); |
auto auto util::Join<std::vector<bilingual_str, std::allocator<bilingual_str>>, bilingual_str>(std::vector<bilingual_str, std::allocator<bilingual_str>> const&, bilingual_str const&)::'lambda'(std::vector<bilingual_str, std::allocator<bilingual_str>> const&)::operator()<bilingual_str>(std::vector<bilingual_str, std::allocator<bilingual_str>> const&) const Line | Count | Source | 224 | 146 | return Join(container, separator, [](const auto& i) { return i; }); |
|
225 | 234k | } auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [2]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [2]) Line | Count | Source | 223 | 184 | { | 224 | 184 | return Join(container, separator, [](const auto& i) { return i; }); | 225 | 184 | } |
auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [3]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [3]) Line | Count | Source | 223 | 119k | { | 224 | 119k | return Join(container, separator, [](const auto& i) { return i; }); | 225 | 119k | } |
auto util::Join<std::vector<bilingual_str, std::allocator<bilingual_str>>, bilingual_str>(std::vector<bilingual_str, std::allocator<bilingual_str>> const&, bilingual_str const&) Line | Count | Source | 223 | 114k | { | 224 | 114k | return Join(container, separator, [](const auto& i) { return i; }); | 225 | 114k | } |
|
226 | | |
227 | | /** |
228 | | * Create an unordered multi-line list of items. |
229 | | */ |
230 | | inline std::string MakeUnorderedList(const std::vector<std::string>& items) |
231 | 2.47k | { |
232 | 14.8k | return Join(items, "\n", [](const std::string& item) { return "- " + item; }); |
233 | 2.47k | } |
234 | | |
235 | | /** |
236 | | * Check if a string contains any embedded NUL (\0) characters |
237 | | */ |
238 | | [[nodiscard]] inline bool ContainsNUL(std::string_view str) noexcept |
239 | 200k | { |
240 | 4.08M | for (auto c : str) { |
241 | 4.08M | if (c == 0) return true; |
242 | 4.08M | } |
243 | 200k | return false; |
244 | 200k | } |
245 | | |
246 | | /** |
247 | | * Locale-independent version of std::to_string |
248 | | */ |
249 | | template <typename T> |
250 | | std::string ToString(const T& t) |
251 | 444k | { |
252 | 444k | std::ostringstream oss; |
253 | 444k | oss.imbue(std::locale::classic()); |
254 | 444k | oss << t; |
255 | 444k | return oss.str(); |
256 | 444k | } std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> util::ToString<unsigned int>(unsigned int const&) Line | Count | Source | 251 | 8.20k | { | 252 | 8.20k | std::ostringstream oss; | 253 | 8.20k | oss.imbue(std::locale::classic()); | 254 | 8.20k | oss << t; | 255 | 8.20k | return oss.str(); | 256 | 8.20k | } |
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> util::ToString<int>(int const&) Line | Count | Source | 251 | 223k | { | 252 | 223k | std::ostringstream oss; | 253 | 223k | oss.imbue(std::locale::classic()); | 254 | 223k | oss << t; | 255 | 223k | return oss.str(); | 256 | 223k | } |
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> util::ToString<double>(double const&) Line | Count | Source | 251 | 10 | { | 252 | 10 | std::ostringstream oss; | 253 | 10 | oss.imbue(std::locale::classic()); | 254 | 10 | oss << t; | 255 | 10 | return oss.str(); | 256 | 10 | } |
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> util::ToString<unsigned long>(unsigned long const&) Line | Count | Source | 251 | 188k | { | 252 | 188k | std::ostringstream oss; | 253 | 188k | oss.imbue(std::locale::classic()); | 254 | 188k | oss << t; | 255 | 188k | return oss.str(); | 256 | 188k | } |
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> util::ToString<unsigned short>(unsigned short const&) Line | Count | Source | 251 | 1 | { | 252 | 1 | std::ostringstream oss; | 253 | 1 | oss.imbue(std::locale::classic()); | 254 | 1 | oss << t; | 255 | 1 | return oss.str(); | 256 | 1 | } |
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> util::ToString<long>(long const&) Line | Count | Source | 251 | 24.9k | { | 252 | 24.9k | std::ostringstream oss; | 253 | 24.9k | oss.imbue(std::locale::classic()); | 254 | 24.9k | oss << t; | 255 | 24.9k | return oss.str(); | 256 | 24.9k | } |
|
257 | | |
258 | | /** |
259 | | * Check whether a container begins with the given prefix. |
260 | | */ |
261 | | template <typename T1, size_t PREFIX_LEN> |
262 | | [[nodiscard]] inline bool HasPrefix(const T1& obj, |
263 | | const std::array<uint8_t, PREFIX_LEN>& prefix) |
264 | 4.03M | { |
265 | 4.03M | return obj.size() >= PREFIX_LEN && |
266 | 4.03M | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); |
267 | 4.03M | } bool util::HasPrefix<prevector<16u, unsigned char, unsigned int, int>, 6ul>(prevector<16u, unsigned char, unsigned int, int> const&, std::array<unsigned char, 6ul> const&) Line | Count | Source | 264 | 118 | { | 265 | 118 | return obj.size() >= PREFIX_LEN && | 266 | 118 | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); | 267 | 118 | } |
bool util::HasPrefix<prevector<16u, unsigned char, unsigned int, int>, 12ul>(prevector<16u, unsigned char, unsigned int, int> const&, std::array<unsigned char, 12ul> const&) Line | Count | Source | 264 | 1.74k | { | 265 | 1.74k | return obj.size() >= PREFIX_LEN && | 266 | 1.74k | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); | 267 | 1.74k | } |
bool util::HasPrefix<std::span<unsigned char const, 18446744073709551615ul>, 12ul>(std::span<unsigned char const, 18446744073709551615ul> const&, std::array<unsigned char, 12ul> const&) Line | Count | Source | 264 | 10.1k | { | 265 | 10.1k | return obj.size() >= PREFIX_LEN && | 266 | 10.1k | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); | 267 | 10.1k | } |
bool util::HasPrefix<std::span<unsigned char const, 18446744073709551615ul>, 6ul>(std::span<unsigned char const, 18446744073709551615ul> const&, std::array<unsigned char, 6ul> const&) Line | Count | Source | 264 | 6.82k | { | 265 | 6.82k | return obj.size() >= PREFIX_LEN && | 266 | 6.82k | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); | 267 | 6.82k | } |
bool util::HasPrefix<prevector<16u, unsigned char, unsigned int, int>, 2ul>(prevector<16u, unsigned char, unsigned int, int> const&, std::array<unsigned char, 2ul> const&) Line | Count | Source | 264 | 1.00M | { | 265 | 1.00M | return obj.size() >= PREFIX_LEN && | 266 | 1.00M | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); | 267 | 1.00M | } |
bool util::HasPrefix<prevector<16u, unsigned char, unsigned int, int>, 3ul>(prevector<16u, unsigned char, unsigned int, int> const&, std::array<unsigned char, 3ul> const&) Line | Count | Source | 264 | 3.00M | { | 265 | 3.00M | return obj.size() >= PREFIX_LEN && | 266 | 3.00M | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); | 267 | 3.00M | } |
bool util::HasPrefix<prevector<16u, unsigned char, unsigned int, int>, 4ul>(prevector<16u, unsigned char, unsigned int, int> const&, std::array<unsigned char, 4ul> const&) Line | Count | Source | 264 | 3.40k | { | 265 | 3.40k | return obj.size() >= PREFIX_LEN && | 266 | 3.40k | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); | 267 | 3.40k | } |
bool util::HasPrefix<prevector<16u, unsigned char, unsigned int, int>, 8ul>(prevector<16u, unsigned char, unsigned int, int> const&, std::array<unsigned char, 8ul> const&) Line | Count | Source | 264 | 2.24k | { | 265 | 2.24k | return obj.size() >= PREFIX_LEN && | 266 | 2.24k | std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); | 267 | 2.24k | } |
|
268 | | |
269 | | class LineReader |
270 | | { |
271 | | const std::string_view m_str; |
272 | | const size_t m_max_line_length; |
273 | | std::string_view::iterator m_it; |
274 | | |
275 | | public: |
276 | | explicit LineReader(std::string_view str LIFETIMEBOUND, size_t max_line_length); |
277 | | |
278 | | /** |
279 | | * Returns a string from current iterator position up to (but not including) next \n |
280 | | * and advances iterator to the character following the \n on success. |
281 | | * Will not return a line longer than max_line_length. |
282 | | * @returns the next string from the buffer. |
283 | | * std::nullopt if end of buffer is reached without finding a \n. |
284 | | * @throws a std::runtime_error if max_line_length + 1 bytes are read without finding \n. |
285 | | */ |
286 | | std::optional<std::string_view> ReadLine() LIFETIMEBOUND; |
287 | | |
288 | | /** |
289 | | * Returns string from current iterator position of specified length |
290 | | * if possible and advances iterator on success. |
291 | | * May exceed max_line_length but will not read past end of buffer. |
292 | | * @param[in] len The number of bytes to read from the buffer |
293 | | * @returns a string of the expected length. |
294 | | * @throws a std::runtime_error if there is not enough data in the buffer. |
295 | | */ |
296 | | std::string_view ReadLength(size_t len) LIFETIMEBOUND; |
297 | | |
298 | | /** |
299 | | * Returns remaining size of bytes in buffer |
300 | | */ |
301 | | size_t Remaining() const; |
302 | | |
303 | | /** |
304 | | * Returns number of bytes already read from buffer |
305 | | */ |
306 | | size_t Consumed() const; |
307 | | }; |
308 | | } // namespace util |
309 | | |
310 | | #endif // BITCOIN_UTIL_STRING_H |