Branch data Line data Source code
1 : : // Copyright (c) 2019-2022 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 <span.h>
9 : :
10 : : #include <array>
11 : : #include <cstdint>
12 : : #include <cstring>
13 : : #include <locale>
14 : : #include <sstream>
15 : : #include <string> // IWYU pragma: export
16 : : #include <string_view> // IWYU pragma: export
17 : : #include <vector>
18 : :
19 : : namespace util {
20 : : void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute);
21 : :
22 : : /** Split a string on any char found in separators, returning a vector.
23 : : *
24 : : * If sep does not occur in sp, a singleton with the entirety of sp is returned.
25 : : *
26 : : * Note that this function does not care about braces, so splitting
27 : : * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}.
28 : : */
29 : : template <typename T = Span<const char>>
30 : 24168 : std::vector<T> Split(const Span<const char>& sp, std::string_view separators)
31 : : {
32 : 24168 : std::vector<T> ret;
33 : 24168 : auto it = sp.begin();
34 : 24168 : auto start = it;
35 [ + + ]: 598723 : while (it != sp.end()) {
36 [ + + ]: 574555 : if (separators.find(*it) != std::string::npos) {
37 [ + - ]: 12790 : ret.emplace_back(start, it);
38 : 12790 : start = it + 1;
39 : : }
40 : 574555 : ++it;
41 : : }
42 [ + - ]: 24168 : ret.emplace_back(start, it);
43 : 24168 : return ret;
44 : 0 : }
45 : :
46 : : /** Split a string on every instance of sep, returning a vector.
47 : : *
48 : : * If sep does not occur in sp, a singleton with the entirety of sp is returned.
49 : : *
50 : : * Note that this function does not care about braces, so splitting
51 : : * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}.
52 : : */
53 : : template <typename T = Span<const char>>
54 : 21415 : std::vector<T> Split(const Span<const char>& sp, char sep)
55 : : {
56 : 21415 : return Split<T>(sp, std::string_view{&sep, 1});
57 : : }
58 : :
59 : 19114 : [[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, char sep)
60 : : {
61 [ # # # # : 19114 : return Split<std::string>(str, sep);
# # # # ]
[ + - ][ - -
- - + - +
- ]
62 : : }
63 : :
64 : 2752 : [[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, std::string_view separators)
65 : : {
66 [ + - ][ + - : 2752 : return Split<std::string>(str, separators);
+ - + - +
- + - + -
+ - ]
67 : : }
68 : :
69 : 669206 : [[nodiscard]] inline std::string_view TrimStringView(std::string_view str, std::string_view pattern = " \f\n\r\t\v")
70 : : {
71 : 669206 : std::string::size_type front = str.find_first_not_of(pattern);
72 [ + + ]: 669206 : if (front == std::string::npos) {
73 : 38 : return {};
74 : : }
75 : 669168 : std::string::size_type end = str.find_last_not_of(pattern);
76 : 669168 : return str.substr(front, end - front + 1);
77 : : }
78 : :
79 : 370774 : [[nodiscard]] inline std::string TrimString(std::string_view str, std::string_view pattern = " \f\n\r\t\v")
80 : : {
81 : 370774 : return std::string(TrimStringView(str, pattern));
82 : : }
83 : :
84 : 5 : [[nodiscard]] inline std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix)
85 : : {
86 [ + - ]: 5 : if (str.ends_with(suffix)) {
87 : 5 : return str.substr(0, str.size() - suffix.size());
88 : : }
89 : 0 : return str;
90 : : }
91 : :
92 : 304966 : [[nodiscard]] inline std::string_view RemovePrefixView(std::string_view str, std::string_view prefix)
93 : : {
94 [ + + ]: 304966 : if (str.substr(0, prefix.size()) == prefix) {
95 : 1219 : return str.substr(prefix.size());
96 : : }
97 : 303747 : return str;
98 : : }
99 : :
100 : 5 : [[nodiscard]] inline std::string RemovePrefix(std::string_view str, std::string_view prefix)
101 : : {
102 : 5 : return std::string(RemovePrefixView(str, prefix));
103 : : }
104 : :
105 : : /**
106 : : * Join all container items. Typically used to concatenate strings but accepts
107 : : * containers with elements of any type.
108 : : *
109 : : * @param container The items to join
110 : : * @param separator The separator
111 : : * @param unary_op Apply this operator to each item
112 : : */
113 : : template <typename C, typename S, typename UnaryOp>
114 : : // NOLINTNEXTLINE(misc-no-recursion)
115 : 13415 : auto Join(const C& container, const S& separator, UnaryOp unary_op)
116 : : {
117 : 13415 : decltype(unary_op(*container.begin())) ret;
118 : 13415 : bool first{true};
119 [ + + ]: 71283 : for (const auto& item : container) {
120 [ + + ]: 91865 : if (!first) ret += separator;
[ + + + - ]
121 [ + - ]: 115736 : ret += unary_op(item);
[ + - + - ]
122 : 57868 : first = false;
123 : : }
124 : 13415 : return ret;
125 : 0 : }
126 : :
127 : : template <typename C, typename S>
128 : 11210 : auto Join(const C& container, const S& separator)
129 : : {
130 [ + - ]: 31320 : return Join(container, separator, [](const auto& i) { return i; });
131 : : }
132 : :
133 : : /**
134 : : * Create an unordered multi-line list of items.
135 : : */
136 : 78 : inline std::string MakeUnorderedList(const std::vector<std::string>& items)
137 : : {
138 [ + - + - ]: 546 : return Join(items, "\n", [](const std::string& item) { return "- " + item; });
139 : : }
140 : :
141 : : /**
142 : : * Check if a string does not contain any embedded NUL (\0) characters
143 : : */
144 : 45977 : [[nodiscard]] inline bool ContainsNoNUL(std::string_view str) noexcept
145 : : {
146 [ + + + + ]: 958094 : for (auto c : str) {
[ + + # # ]
[ + + + +
+ + + + +
+ ]
147 [ + + + + ]: 912139 : if (c == 0) return false;
[ + + # # ]
[ + + + -
+ + + + +
- ]
148 : : }
149 : : return true;
150 : : }
151 : :
152 : : /**
153 : : * Locale-independent version of std::to_string
154 : : */
155 : : template <typename T>
156 : 226248 : std::string ToString(const T& t)
157 : : {
158 : 226248 : std::ostringstream oss;
159 [ + - + - ]: 226248 : oss.imbue(std::locale::classic());
160 [ # # # # ]: 226248 : oss << t;
[ + - + - ]
161 : 226248 : return oss.str();
162 : 226248 : }
163 : :
164 : : /**
165 : : * Check whether a container begins with the given prefix.
166 : : */
167 : : template <typename T1, size_t PREFIX_LEN>
168 [ + + ]: 718901 : [[nodiscard]] inline bool HasPrefix(const T1& obj,
169 : : const std::array<uint8_t, PREFIX_LEN>& prefix)
170 : : {
171 [ + - + + ]: 1436259 : return obj.size() >= PREFIX_LEN &&
172 [ + + ]: 718901 : std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
173 : : }
174 : : } // namespace util
175 : :
176 : : #endif // BITCOIN_UTIL_STRING_H
|