Bitcoin Core 32.99.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 <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
23namespace util {
24namespace detail {
25template <unsigned num_params>
26constexpr void CheckNumFormatSpecifiers(const char* str)
27{
28 unsigned count_normal{0}; // Number of "normal" specifiers, like %s
29 unsigned count_pos{0}; // Max number in positional specifier, like %8$s
30 for (auto it{str}; *it != '\0'; ++it) {
31 if (*it != '%' || *++it == '%') continue; // Skip escaped %%
32
33 auto add_arg = [&] {
34 unsigned maybe_num{0};
35 while ('0' <= *it && *it <= '9') {
36 maybe_num *= 10;
37 maybe_num += *it - '0';
38 ++it;
39 }
40
41 if (*it == '$') {
42 ++it;
43 // Positional specifier, like %8$s
44 if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45 count_pos = std::max(count_pos, maybe_num);
46 } else {
47 // Non-positional specifier, like %s
48 ++count_normal;
49 }
50 };
51
52 // Increase argument count and consume positional specifier, if present.
53 add_arg();
54
55 // Consume flags.
56 while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it;
57
58 auto parse_size = [&] {
59 if (*it == '*') {
60 ++it;
61 add_arg();
62 } else {
63 while ('0' <= *it && *it <= '9') ++it;
64 }
65 };
66
67 // Consume dynamic or static width value.
68 parse_size();
69
70 // Consume dynamic or static precision value.
71 if (*it == '.') {
72 ++it;
73 parse_size();
74 }
75
76 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 }
81 if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!";
82 unsigned count{count_normal | count_pos};
83 if (num_params != count) throw "Format specifier count must match the argument count!";
84}
85} // namespace detail
86
95template <unsigned num_params>
97 const char* const fmt;
98 consteval ConstevalFormatString(const char* str) : fmt{str} { detail::CheckNumFormatSpecifiers<num_params>(fmt); }
99};
100
102void ReplaceAll(std::string& in_out, std::string_view search, std::string_view substitute);
103
119template <typename T = std::span<const char>>
120std::vector<T> Split(std::span<const char> sp LIFETIMEBOUND, std::string_view separators, bool include_sep = false)
121{
122 std::vector<T> ret;
123 auto it = sp.begin();
124 auto start = it;
125 while (it != sp.end()) {
126 if (separators.find(*it) != std::string::npos) {
127 if (include_sep) {
128 ret.emplace_back(start, it + 1);
129 } else {
130 ret.emplace_back(start, it);
131 }
132 start = it + 1;
133 }
134 ++it;
135 }
136 ret.emplace_back(start, it);
137 return ret;
138}
139
147template <typename T = std::span<const char>>
148std::vector<T> Split(std::span<const char> sp LIFETIMEBOUND, char sep, bool include_sep = false)
149{
150 return Split<T>(sp, std::string_view{&sep, 1}, include_sep);
151}
152
153[[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, char sep)
154{
155 return Split<std::string>(str, sep);
156}
157
158[[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, std::string_view separators)
159{
160 return Split<std::string>(str, separators);
161}
162
163[[nodiscard]] inline std::string_view TrimStringView(std::string_view str LIFETIMEBOUND, std::string_view pattern = " \f\n\r\t\v")
164{
165 std::string::size_type front = str.find_first_not_of(pattern);
166 if (front == std::string::npos) {
167 return {};
168 }
169 std::string::size_type end = str.find_last_not_of(pattern);
170 return str.substr(front, end - front + 1);
171}
172
173[[nodiscard]] inline std::string TrimString(std::string_view str, std::string_view pattern = " \f\n\r\t\v")
174{
175 return std::string(TrimStringView(str, pattern));
176}
177
178[[nodiscard]] inline std::string_view RemoveSuffixView(std::string_view str LIFETIMEBOUND, std::string_view suffix)
179{
180 if (str.ends_with(suffix)) {
181 return str.substr(0, str.size() - suffix.size());
182 }
183 return str;
184}
185
186[[nodiscard]] inline std::string_view RemovePrefixView(std::string_view str LIFETIMEBOUND, std::string_view prefix)
187{
188 if (str.starts_with(prefix)) {
189 return str.substr(prefix.size());
190 }
191 return str;
192}
193
194[[nodiscard]] inline std::string RemovePrefix(std::string_view str, std::string_view prefix)
195{
196 return std::string(RemovePrefixView(str, prefix));
197}
198
207template <typename C, typename S, typename UnaryOp>
208// NOLINTNEXTLINE(misc-no-recursion)
209auto Join(const C& container, const S& separator, UnaryOp unary_op)
210{
211 decltype(unary_op(*container.begin())) ret;
212 bool first{true};
213 for (const auto& item : container) {
214 if (!first) ret += separator;
215 ret += unary_op(item);
216 first = false;
217 }
218 return ret;
219}
220
221template <typename C, typename S>
222auto Join(const C& container, const S& separator)
223{
224 return Join(container, separator, [](const auto& i) { return i; });
225}
226
230inline std::string MakeUnorderedList(const std::vector<std::string>& items)
231{
232 return Join(items, "\n", [](const std::string& item) { return "- " + item; });
233}
234
238[[nodiscard]] inline bool ContainsNUL(std::string_view str) noexcept
239{
240 for (auto c : str) {
241 if (c == 0) return true;
242 }
243 return false;
244}
245
249template <typename T>
250std::string ToString(const T& t)
251{
252 std::ostringstream oss;
253 oss.imbue(std::locale::classic());
254 oss << t;
255 return oss.str();
256}
257
261template <typename T1, size_t PREFIX_LEN>
262[[nodiscard]] inline bool HasPrefix(const T1& obj,
263 const std::array<uint8_t, PREFIX_LEN>& prefix)
264{
265 return obj.size() >= PREFIX_LEN &&
266 std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
267}
268
270{
271 const std::string_view m_str;
272 const size_t m_max_line_length;
273 std::string_view::iterator m_it;
274
275public:
276 explicit LineReader(std::string_view str LIFETIMEBOUND, size_t max_line_length);
277
286 std::optional<std::string_view> ReadLine() LIFETIMEBOUND;
287
296 std::string_view ReadLength(size_t len) LIFETIMEBOUND;
297
301 size_t Remaining() const;
302
306 size_t Consumed() const;
307};
308} // namespace util
309
310#endif // BITCOIN_UTIL_STRING_H
#define LIFETIMEBOUND
Definition: attributes.h:16
int ret
const size_t m_max_line_length
Definition: string.h:272
size_t Consumed() const
Returns number of bytes already read from buffer.
Definition: string.cpp:85
std::optional< std::string_view > ReadLine() LIFETIMEBOUND
Returns a string from current iterator position up to (but not including) next and advances iterator...
Definition: string.cpp:35
size_t Remaining() const
Returns remaining size of bytes in buffer.
Definition: string.cpp:80
const std::string_view m_str
Definition: string.h:271
LineReader(std::string_view str LIFETIMEBOUND, size_t max_line_length)
Definition: string.cpp:32
std::string_view ReadLength(size_t len) LIFETIMEBOUND
Returns string from current iterator position of specified length if possible and advances iterator o...
Definition: string.cpp:71
std::string_view::iterator m_it
Definition: string.h:273
constexpr void CheckNumFormatSpecifiers(const char *str)
Definition: string.h:26
std::vector< std::string > SplitString(std::string_view str, char sep)
Definition: string.h:153
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:262
std::string MakeUnorderedList(const std::vector< std::string > &items)
Create an unordered multi-line list of items.
Definition: string.h:230
std::string_view RemoveSuffixView(std::string_view str LIFETIMEBOUND, std::string_view suffix)
Definition: string.h:178
std::vector< T > Split(std::span< const char > sp LIFETIMEBOUND, std::string_view separators, bool include_sep=false)
Split a string on any char found in separators, returning a vector.
Definition: string.h:120
std::string_view TrimStringView(std::string_view str LIFETIMEBOUND, std::string_view pattern=" \f\n\r\t\v")
Definition: string.h:163
void ReplaceAll(std::string &in_out, std::string_view search, std::string_view substitute)
Replace every non-overlapping occurrence of search with substitute, treating both literally; the repl...
Definition: string.cpp:14
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:250
std::string TrimString(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
Definition: string.h:173
std::string RemovePrefix(std::string_view str, std::string_view prefix)
Definition: string.h:194
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
Definition: string.h:209
bool ContainsNUL(std::string_view str) noexcept
Check if a string contains any embedded NUL (\0) characters.
Definition: string.h:238
std::string_view RemovePrefixView(std::string_view str LIFETIMEBOUND, std::string_view prefix)
Definition: string.h:186
#define S(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
const char * prefix
Definition: rest.cpp:1197
A wrapper for a compile-time partially validated format string.
Definition: string.h:96
consteval ConstevalFormatString(const char *str)
Definition: string.h:98
const char *const fmt
Definition: string.h:97
static int count