Bitcoin Core  31.0.0
P2P Digital Currency
string.h
Go to the documentation of this file.
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 <span.h>
9 
10 #include <array>
11 #include <cstdint>
12 #include <cstring>
13 #include <locale>
14 #include <optional>
15 #include <sstream>
16 #include <string>
17 #include <string_view>
18 #include <vector>
19 
20 namespace util {
21 namespace detail {
22 template <unsigned num_params>
23 constexpr static void CheckNumFormatSpecifiers(const char* str)
24 {
25  unsigned count_normal{0}; // Number of "normal" specifiers, like %s
26  unsigned count_pos{0}; // Max number in positional specifier, like %8$s
27  for (auto it{str}; *it != '\0'; ++it) {
28  if (*it != '%' || *++it == '%') continue; // Skip escaped %%
29 
30  auto add_arg = [&] {
31  unsigned maybe_num{0};
32  while ('0' <= *it && *it <= '9') {
33  maybe_num *= 10;
34  maybe_num += *it - '0';
35  ++it;
36  }
37 
38  if (*it == '$') {
39  ++it;
40  // Positional specifier, like %8$s
41  if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
42  count_pos = std::max(count_pos, maybe_num);
43  } else {
44  // Non-positional specifier, like %s
45  ++count_normal;
46  }
47  };
48 
49  // Increase argument count and consume positional specifier, if present.
50  add_arg();
51 
52  // Consume flags.
53  while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it;
54 
55  auto parse_size = [&] {
56  if (*it == '*') {
57  ++it;
58  add_arg();
59  } else {
60  while ('0' <= *it && *it <= '9') ++it;
61  }
62  };
63 
64  // Consume dynamic or static width value.
65  parse_size();
66 
67  // Consume dynamic or static precision value.
68  if (*it == '.') {
69  ++it;
70  parse_size();
71  }
72 
73  if (*it == '\0') throw "Format specifier incorrectly terminated by end of string";
74 
75  // Length and type in "[flags][width][.precision][length]type"
76  // is not checked. Parsing continues with the next '%'.
77  }
78  if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!";
79  unsigned count{count_normal | count_pos};
80  if (num_params != count) throw "Format specifier count must match the argument count!";
81 }
82 } // namespace detail
83 
92 template <unsigned num_params>
93 struct ConstevalFormatString {
94  const char* const fmt;
95  consteval ConstevalFormatString(const char* str) : fmt{str} { detail::CheckNumFormatSpecifiers<num_params>(fmt); }
96 };
97 
98 void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute);
99 
115 template <typename T = std::span<const char>>
116 std::vector<T> Split(const std::span<const char>& sp, std::string_view separators, bool include_sep = false)
117 {
118  std::vector<T> ret;
119  auto it = sp.begin();
120  auto start = it;
121  while (it != sp.end()) {
122  if (separators.find(*it) != std::string::npos) {
123  if (include_sep) {
124  ret.emplace_back(start, it + 1);
125  } else {
126  ret.emplace_back(start, it);
127  }
128  start = it + 1;
129  }
130  ++it;
131  }
132  ret.emplace_back(start, it);
133  return ret;
134 }
135 
143 template <typename T = std::span<const char>>
144 std::vector<T> Split(const std::span<const char>& sp, char sep, bool include_sep = false)
145 {
146  return Split<T>(sp, std::string_view{&sep, 1}, include_sep);
147 }
148 
149 [[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, char sep)
150 {
151  return Split<std::string>(str, sep);
152 }
153 
154 [[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, std::string_view separators)
155 {
156  return Split<std::string>(str, separators);
157 }
158 
159 [[nodiscard]] inline std::string_view TrimStringView(std::string_view str, std::string_view pattern = " \f\n\r\t\v")
160 {
161  std::string::size_type front = str.find_first_not_of(pattern);
162  if (front == std::string::npos) {
163  return {};
164  }
165  std::string::size_type end = str.find_last_not_of(pattern);
166  return str.substr(front, end - front + 1);
167 }
168 
169 [[nodiscard]] inline std::string TrimString(std::string_view str, std::string_view pattern = " \f\n\r\t\v")
170 {
171  return std::string(TrimStringView(str, pattern));
172 }
173 
174 [[nodiscard]] inline std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix)
175 {
176  if (str.ends_with(suffix)) {
177  return str.substr(0, str.size() - suffix.size());
178  }
179  return str;
180 }
181 
182 [[nodiscard]] inline std::string_view RemovePrefixView(std::string_view str, std::string_view prefix)
183 {
184  if (str.starts_with(prefix)) {
185  return str.substr(prefix.size());
186  }
187  return str;
188 }
189 
190 [[nodiscard]] inline std::string RemovePrefix(std::string_view str, std::string_view prefix)
191 {
192  return std::string(RemovePrefixView(str, prefix));
193 }
194 
203 template <typename C, typename S, typename UnaryOp>
204 // NOLINTNEXTLINE(misc-no-recursion)
205 auto Join(const C& container, const S& separator, UnaryOp unary_op)
206 {
207  decltype(unary_op(*container.begin())) ret;
208  bool first{true};
209  for (const auto& item : container) {
210  if (!first) ret += separator;
211  ret += unary_op(item);
212  first = false;
213  }
214  return ret;
215 }
216 
217 template <typename C, typename S>
218 auto Join(const C& container, const S& separator)
219 {
220  return Join(container, separator, [](const auto& i) { return i; });
221 }
222 
226 inline std::string MakeUnorderedList(const std::vector<std::string>& items)
227 {
228  return Join(items, "\n", [](const std::string& item) { return "- " + item; });
229 }
230 
234 [[nodiscard]] inline bool ContainsNoNUL(std::string_view str) noexcept
235 {
236  for (auto c : str) {
237  if (c == 0) return false;
238  }
239  return true;
240 }
241 
245 template <typename T>
246 std::string ToString(const T& t)
247 {
248  std::ostringstream oss;
249  oss.imbue(std::locale::classic());
250  oss << t;
251  return oss.str();
252 }
253 
257 template <typename T1, size_t PREFIX_LEN>
258 [[nodiscard]] inline bool HasPrefix(const T1& obj,
259  const std::array<uint8_t, PREFIX_LEN>& prefix)
260 {
261  return obj.size() >= PREFIX_LEN &&
262  std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
263 }
264 
265 struct LineReader {
266  const std::span<const std::byte>::iterator start;
267  const std::span<const std::byte>::iterator end;
268  const size_t max_line_length;
269  std::span<const std::byte>::iterator it;
270 
271  explicit LineReader(std::span<const std::byte> buffer, size_t max_line_length);
272 
281  std::optional<std::string> ReadLine();
282 
291  std::string ReadLength(size_t len);
292 
296  size_t Remaining() const;
297 };
298 } // namespace util
299 
300 #endif // BITCOIN_UTIL_STRING_H
void ReplaceAll(std::string &in_out, const std::string &search, const std::string &substitute)
Definition: string.cpp:11
int ret
std::vector< std::string > SplitString(std::string_view str, char sep)
Definition: string.h:149
std::string TrimString(std::string_view str, std::string_view pattern=" \\\)
Definition: string.h:169
LineReader(std::span< const std::byte > buffer, size_t max_line_length)
Definition: string.cpp:17
const char * prefix
Definition: rest.cpp:1141
static constexpr void CheckNumFormatSpecifiers(const char *str)
Definition: string.h:23
const std::span< const std::byte >::iterator end
Definition: string.h:267
std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix)
Definition: string.h:174
std::string RemovePrefix(std::string_view str, std::string_view prefix)
Definition: string.h:190
#define S(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
const std::span< const std::byte >::iterator start
Definition: string.h:266
bool ContainsNoNUL(std::string_view str) noexcept
Check if a string does not contain any embedded NUL (\0) characters.
Definition: string.h:234
std::span< const std::byte >::iterator it
Definition: string.h:269
std::string_view RemovePrefixView(std::string_view str, std::string_view prefix)
Definition: string.h:182
std::string_view TrimStringView(std::string_view str, std::string_view pattern=" \\\)
Definition: string.h:159
consteval ConstevalFormatString(const char *str)
Definition: string.h:95
size_t Remaining() const
Returns remaining size of bytes in buffer.
Definition: string.cpp:66
std::string MakeUnorderedList(const std::vector< std::string > &items)
Create an unordered multi-line list of items.
Definition: string.h:226
const char *const fmt
Definition: string.h:94
bool HasPrefix(const T1 &obj, const std::array< uint8_t, PREFIX_LEN > &prefix)
Check whether a container begins with the given prefix.
Definition: string.h:258
std::optional< std::string > ReadLine()
Returns a string from current iterator position up to (but not including) next and advances iterator...
Definition: string.cpp:20
const size_t max_line_length
Definition: string.h:268
static int count
std::string ReadLength(size_t len)
Returns string from current iterator position of specified length if possible and advances iterator o...
Definition: string.cpp:57
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
Definition: string.h:205
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:246
std::vector< T > Split(const std::span< const char > &sp, std::string_view separators, bool include_sep=false)
Split a string on any char found in separators, returning a vector.
Definition: string.h:116