Toolbox snapshot
The Reactive C++ Toolbox
Loading...
Searching...
No Matches
String.hpp
Go to the documentation of this file.
1// The Reactive C++ Toolbox.
2// Copyright (C) 2013-2019 Swirly Cloud Limited
3// Copyright (C) 2023 Reactive Markets Limited
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#ifndef TOOLBOX_UTIL_STRING_HPP
18#define TOOLBOX_UTIL_STRING_HPP
19
23
24#include <charconv>
25#include <cstring>
26#include <sstream>
27#include <string_view>
28
29namespace toolbox {
30inline namespace util {
31
32template <typename ValueT>
33constexpr ValueT from_string(std::string_view sv)
34{
36 return Traits::from_string(sv);
37}
38static_assert(from_string<int>(std::string_view{"-123"}) == -123);
39
40template <typename ValueT>
41constexpr ValueT from_string(const std::string& s)
42{
44 return Traits::from_string(s);
45}
46
47template <typename ValueT>
48constexpr ValueT from_string(const char* s)
49{
51 return Traits::from_string(std::string_view{s});
52}
53static_assert(from_string<int>("-123") == -123);
54
55template <typename ValueT>
56std::string to_string(ValueT&& val)
57{
58 std::stringstream ss;
59 ss << val;
60 return ss.str();
61}
62
63template <typename ValueT>
64// clang-format off
65requires Arithmetic<ValueT>
66std::string to_string(ValueT&& val)
67// clang-format on
68{
69 return std::to_string(val);
70}
71
72template <typename PolicyT>
73// clang-format off
76// clang-format on
77{
78 return std::to_string(val.count());
79}
80
81template <std::size_t SizeN>
82constexpr std::string_view to_string_view(const char (&val)[SizeN]) noexcept
83{
84 return {val, strnlen(val, SizeN)};
85}
86
87TOOLBOX_API void ltrim(std::string_view& s) noexcept;
88
89TOOLBOX_API void ltrim(std::string& s) noexcept;
90
91TOOLBOX_API void rtrim(std::string_view& s) noexcept;
92
93TOOLBOX_API void rtrim(std::string& s) noexcept;
94
95inline void trim(std::string_view& s) noexcept
96{
97 ltrim(s);
98 rtrim(s);
99}
100
101inline void trim(std::string& s) noexcept
102{
103 ltrim(s);
104 rtrim(s);
105}
106
107inline std::string_view ltrim_copy(std::string_view s) noexcept
108{
109 ltrim(s);
110 return s;
111}
112
113inline std::string ltrim_copy(std::string s) noexcept
114{
115 ltrim(s);
116 return s;
117}
118
119inline std::string_view rtrim_copy(std::string_view s) noexcept
120{
121 rtrim(s);
122 return s;
123}
124
125inline std::string rtrim_copy(std::string s) noexcept
126{
127 rtrim(s);
128 return s;
129}
130
131inline std::string_view trim_copy(std::string_view s) noexcept
132{
133 trim(s);
134 return s;
135}
136
137inline std::string trim_copy(std::string s) noexcept
138{
139 trim(s);
140 return s;
141}
142
143TOOLBOX_API std::pair<std::string_view, std::string_view>
144split_pair(std::string_view s, std::string_view delim) noexcept;
145
146TOOLBOX_API std::pair<std::string, std::string> split_pair(const std::string& s,
147 std::string_view delim);
148
149TOOLBOX_API std::pair<std::string_view, std::string_view> split_pair(std::string_view s,
150 char delim) noexcept;
151
152TOOLBOX_API std::pair<std::string, std::string> split_pair(const std::string& s, char delim);
153
154template <typename F>
155void for_each_csv_item(std::string_view csv,
156 F f) noexcept(noexcept(split_pair(std::declval<std::string_view>(), ','))
157 && noexcept(f(std::declval<std::string_view>())))
158{
159 bool trailing_comma;
160 do {
161 std::string_view v;
162 trailing_comma = (!csv.empty() && csv.back() == ',');
163 std::tie(v, csv) = split_pair(csv, ',');
164 f(v);
165 } while (!csv.empty() || trailing_comma);
166}
167
168static_assert(noexcept(for_each_csv_item(std::string_view{"a,b"},
169 [](std::string_view) noexcept {})),
170 "for_each_csv_item is noexcept(true)");
171static_assert(!noexcept(for_each_csv_item(std::string_view{"a,b"}, [](std::string_view) {})),
172 "for_each_csv_item is noexcept(false)");
173
179template <char PadC>
180constexpr std::size_t pstrlen(const char* src, std::size_t n) noexcept
181{
182 if constexpr (PadC == '\0') {
183 // Optimised case.
184 return strnlen(src, n);
185 } else {
186 std::size_t i{0};
187 while (i < n && src[i] != PadC) {
188 ++i;
189 }
190 return i;
191 }
192}
193
199template <char PadC, std::size_t SizeN>
200constexpr std::size_t pstrlen(const char (&src)[SizeN]) noexcept
201{
202 return pstrlen<PadC>(src, SizeN);
203}
204
211template <char PadC>
212constexpr std::size_t pstrcpy(char* dst, const char* src, std::size_t n) noexcept
213{
214 if constexpr (PadC == '\0') {
215#ifndef __clang__
216#pragma GCC diagnostic push
217#pragma GCC diagnostic ignored "-Wstringop-truncation"
218#endif
219 // Optimised case.
220 return stpncpy(dst, src, n) - dst;
221#ifndef __clang__
222#pragma GCC diagnostic pop
223#endif
224 } else {
225 std::size_t i{0};
226 for (; i < n && src[i] != '\0'; ++i) {
227 dst[i] = src[i];
228 }
229 if (i < n) {
230 std::memset(dst + i, PadC, n - i);
231 }
232 return i;
233 }
234}
235
242template <char PadC, std::size_t SizeN>
243constexpr std::size_t pstrcpy(char (&dst)[SizeN], const char* src) noexcept
244{
245 return pstrcpy<PadC>(dst, src, SizeN);
246}
247
254template <char PadC>
255constexpr std::size_t pstrcpy(char* dst, std::string_view src, std::size_t n) noexcept
256{
257 const std::size_t len{std::min(n, src.size())};
258 if (len > 0) {
259 std::memcpy(dst, src.data(), len);
260 }
261 if (len < n) {
262 std::memset(dst + len, PadC, n - len);
263 }
264 return len;
265}
266
273template <char PadC, std::size_t SizeN>
274constexpr std::size_t pstrcpy(char (&dst)[SizeN], std::string_view src) noexcept
275{
276 return pstrcpy<PadC>(dst, src, SizeN);
277}
278
279template <char PadC>
280constexpr std::size_t pstrcpyid(char* dst, std::int64_t id, std::size_t n) noexcept
281{
282 auto* end = dst + n;
283 const auto [eptr, ec] = std::to_chars(dst, end, id);
284 if (ec == std::errc::value_too_large) {
285 return 0;
286 }
287 if (eptr < end) {
288 std::memset(eptr, PadC, end - eptr);
289 }
290 return eptr - dst;
291}
292
293template <char PadC, std::size_t SizeN>
294constexpr std::size_t pstrcpyid(char (&dst)[SizeN], std::int64_t id) noexcept
295{
296 return pstrcpyid<PadC>(dst, id, SizeN);
297}
298
304template <char PadC>
305constexpr std::size_t lpstrlen(const char* src, std::size_t n) noexcept
306{
307 std::size_t i{0};
308 while (i < n && src[i] == PadC) {
309 ++i;
310 }
311 return n - i;
312}
313
319template <char PadC, std::size_t SizeN>
320constexpr std::size_t lpstrlen(const char (&src)[SizeN]) noexcept
321{
322 return lpstrlen<PadC>(src, SizeN);
323}
324
331template <char PadC>
332constexpr std::size_t lpstrcpy(char* dst, const char* src, std::size_t n) noexcept
333{
334 const std::size_t len{strnlen(src, n)};
335 if (len < n) {
336 std::memset(dst, PadC, n - len);
337 }
338 if (len > 0) {
339 std::memcpy(dst + (n - len), src, len);
340 }
341 return len;
342}
343
350template <char PadC, std::size_t SizeN>
351constexpr std::size_t lpstrcpy(char (&dst)[SizeN], const char* src) noexcept
352{
353 return lpstrcpy<PadC>(dst, src, SizeN);
354}
355
362template <char PadC>
363constexpr std::size_t lpstrcpy(char* dst, std::string_view src, std::size_t n) noexcept
364{
365 const std::size_t len{std::min(n, src.size())};
366 if (len < n) {
367 std::memset(dst, PadC, n - len);
368 }
369 if (len > 0) {
370 std::memcpy(dst + (n - len), src.data(), len);
371 }
372 return len;
373}
374
381template <char PadC, std::size_t SizeN>
382constexpr std::size_t lpstrcpy(char (&dst)[SizeN], std::string_view src) noexcept
383{
384 return lpstrcpy<PadC>(dst, src, SizeN);
385}
386
387template <typename... ArgsT>
388std::string make_string(ArgsT&&... args)
389{
390 std::stringstream os;
391 (os << ... << args);
392 return os.str();
393}
394} // namespace util
395} // namespace toolbox
396
397#endif // TOOLBOX_UTIL_STRING_HPP
#define TOOLBOX_API
Definition Config.h:39
pair< string_view, string_view > split_pair(string_view s, string_view delim) noexcept
Definition String.cpp:52
std::string to_string(ValueT &&val)
Definition String.hpp:56
void rtrim(string_view &s) noexcept
Definition String.cpp:40
void trim(std::string_view &s) noexcept
Definition String.hpp:95
constexpr std::size_t lpstrlen(const char *src, std::size_t n) noexcept
Definition String.hpp:305
std::string make_string(ArgsT &&... args)
Definition String.hpp:388
void for_each_csv_item(std::string_view csv, F f) noexcept(noexcept(split_pair(std::declval< std::string_view >(), ',')) &&noexcept(f(std::declval< std::string_view >())))
Definition String.hpp:155
std::string_view ltrim_copy(std::string_view s) noexcept
Definition String.hpp:107
std::string_view rtrim_copy(std::string_view s) noexcept
Definition String.hpp:119
void ltrim(string_view &s) noexcept
Definition String.cpp:28
constexpr std::string_view to_string_view(const char(&val)[SizeN]) noexcept
Definition String.hpp:82
constexpr std::size_t pstrlen(const char *src, std::size_t n) noexcept
Definition String.hpp:180
constexpr ValueT from_string(std::string_view sv)
Definition String.hpp:33
std::string_view sv
Definition Tokeniser.hpp:26
std::string_view trim_copy(std::string_view s) noexcept
Definition String.hpp:131
constexpr std::size_t pstrcpy(char *dst, const char *src, std::size_t n) noexcept
Definition String.hpp:212
constexpr std::size_t pstrcpyid(char *dst, std::int64_t id, std::size_t n) noexcept
Definition String.hpp:280
constexpr std::size_t lpstrcpy(char *dst, const char *src, std::size_t n) noexcept
Definition String.hpp:332
constexpr auto bind() noexcept
Definition Slot.hpp:97