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
22
23#include <charconv>
24#include <cstring>
25#include <sstream>
26#include <string_view>
27
28namespace toolbox {
29inline namespace util {
30
31template <typename ValueT>
32constexpr ValueT from_string(std::string_view sv)
33{
35 return Traits::from_string(sv);
36}
37static_assert(from_string<int>(std::string_view{"-123"}) == -123);
38
39template <typename ValueT>
40constexpr ValueT from_string(const std::string& s)
41{
43 return Traits::from_string(s);
44}
45
46template <typename ValueT>
47constexpr ValueT from_string(const char* s)
48{
50 return Traits::from_string(std::string_view{s});
51}
52static_assert(from_string<int>("-123") == -123);
53
54template <typename ValueT>
55std::string to_string(ValueT&& val)
56{
57 std::stringstream ss;
58 ss << val;
59 return ss.str();
60}
61
62template <typename ValueT>
63// clang-format off
64requires Arithmetic<ValueT>
65std::string to_string(ValueT&& val)
66// clang-format on
67{
68 return std::to_string(val);
69}
70
71template <std::size_t SizeN>
72constexpr std::string_view to_string_view(const char (&val)[SizeN]) noexcept
73{
74 return {val, strnlen(val, SizeN)};
75}
76
77TOOLBOX_API void ltrim(std::string_view& s) noexcept;
78
79TOOLBOX_API void ltrim(std::string& s) noexcept;
80
81TOOLBOX_API void rtrim(std::string_view& s) noexcept;
82
83TOOLBOX_API void rtrim(std::string& s) noexcept;
84
85inline void trim(std::string_view& s) noexcept
86{
87 ltrim(s);
88 rtrim(s);
89}
90
91inline void trim(std::string& s) noexcept
92{
93 ltrim(s);
94 rtrim(s);
95}
96
97inline std::string_view ltrim_copy(std::string_view s) noexcept
98{
99 ltrim(s);
100 return s;
101}
102
103inline std::string ltrim_copy(std::string s) noexcept
104{
105 ltrim(s);
106 return s;
107}
108
109inline std::string_view rtrim_copy(std::string_view s) noexcept
110{
111 rtrim(s);
112 return s;
113}
114
115inline std::string rtrim_copy(std::string s) noexcept
116{
117 rtrim(s);
118 return s;
119}
120
121inline std::string_view trim_copy(std::string_view s) noexcept
122{
123 trim(s);
124 return s;
125}
126
127inline std::string trim_copy(std::string s) noexcept
128{
129 trim(s);
130 return s;
131}
132
133TOOLBOX_API std::pair<std::string_view, std::string_view>
134split_pair(std::string_view s, std::string_view delim) noexcept;
135
136TOOLBOX_API std::pair<std::string, std::string> split_pair(const std::string& s,
137 std::string_view delim);
138
139TOOLBOX_API std::pair<std::string_view, std::string_view> split_pair(std::string_view s,
140 char delim) noexcept;
141
142TOOLBOX_API std::pair<std::string, std::string> split_pair(const std::string& s, char delim);
143
144template <typename F>
145void for_each_csv_item(std::string_view csv,
146 F f) noexcept(noexcept(split_pair(std::declval<std::string_view>(), ','))
147 && noexcept(f(std::declval<std::string_view>())))
148{
149 bool trailing_comma;
150 do {
151 std::string_view v;
152 trailing_comma = (!csv.empty() && csv.back() == ',');
153 std::tie(v, csv) = split_pair(csv, ',');
154 f(v);
155 } while (!csv.empty() || trailing_comma);
156}
157
158static_assert(noexcept(for_each_csv_item(std::string_view{"a,b"},
159 [](std::string_view) noexcept {})),
160 "for_each_csv_item is noexcept(true)");
161static_assert(!noexcept(for_each_csv_item(std::string_view{"a,b"}, [](std::string_view) {})),
162 "for_each_csv_item is noexcept(false)");
163
169template <char PadC>
170constexpr std::size_t pstrlen(const char* src, std::size_t n) noexcept
171{
172 if constexpr (PadC == '\0') {
173 // Optimised case.
174 return strnlen(src, n);
175 } else {
176 std::size_t i{0};
177 while (i < n && src[i] != PadC) {
178 ++i;
179 }
180 return i;
181 }
182}
183
189template <char PadC, std::size_t SizeN>
190constexpr std::size_t pstrlen(const char (&src)[SizeN]) noexcept
191{
192 return pstrlen<PadC>(src, SizeN);
193}
194
201template <char PadC>
202constexpr std::size_t pstrcpy(char* dst, const char* src, std::size_t n) noexcept
203{
204 if constexpr (PadC == '\0') {
205#ifndef __clang__
206#pragma GCC diagnostic push
207#pragma GCC diagnostic ignored "-Wstringop-truncation"
208#endif
209 // Optimised case.
210 return stpncpy(dst, src, n) - dst;
211#ifndef __clang__
212#pragma GCC diagnostic pop
213#endif
214 } else {
215 std::size_t i{0};
216 for (; i < n && src[i] != '\0'; ++i) {
217 dst[i] = src[i];
218 }
219 if (i < n) {
220 std::memset(dst + i, PadC, n - i);
221 }
222 return i;
223 }
224}
225
232template <char PadC, std::size_t SizeN>
233constexpr std::size_t pstrcpy(char (&dst)[SizeN], const char* src) noexcept
234{
235 return pstrcpy<PadC>(dst, src, SizeN);
236}
237
244template <char PadC>
245constexpr std::size_t pstrcpy(char* dst, std::string_view src, std::size_t n) noexcept
246{
247 const std::size_t len{std::min(n, src.size())};
248 if (len > 0) {
249 std::memcpy(dst, src.data(), len);
250 }
251 if (len < n) {
252 std::memset(dst + len, PadC, n - len);
253 }
254 return len;
255}
256
263template <char PadC, std::size_t SizeN>
264constexpr std::size_t pstrcpy(char (&dst)[SizeN], std::string_view src) noexcept
265{
266 return pstrcpy<PadC>(dst, src, SizeN);
267}
268
269template <char PadC>
270constexpr std::size_t pstrcpyid(char* dst, std::int64_t id, std::size_t n) noexcept
271{
272 auto* end = dst + n;
273 const auto [eptr, ec] = std::to_chars(dst, end, id);
274 if (ec == std::errc::value_too_large) {
275 return 0;
276 }
277 if (eptr < end) {
278 std::memset(eptr, PadC, end - eptr);
279 }
280 return eptr - dst;
281}
282
283template <char PadC, std::size_t SizeN>
284constexpr std::size_t pstrcpyid(char (&dst)[SizeN], std::int64_t id) noexcept
285{
286 return pstrcpyid<PadC>(dst, id, SizeN);
287}
288
294template <char PadC>
295constexpr std::size_t lpstrlen(const char* src, std::size_t n) noexcept
296{
297 std::size_t i{0};
298 while (i < n && src[i] == PadC) {
299 ++i;
300 }
301 return n - i;
302}
303
309template <char PadC, std::size_t SizeN>
310constexpr std::size_t lpstrlen(const char (&src)[SizeN]) noexcept
311{
312 return lpstrlen<PadC>(src, SizeN);
313}
314
321template <char PadC>
322constexpr std::size_t lpstrcpy(char* dst, const char* src, std::size_t n) noexcept
323{
324 const std::size_t len{strnlen(src, n)};
325 if (len < n) {
326 std::memset(dst, PadC, n - len);
327 }
328 if (len > 0) {
329 std::memcpy(dst + (n - len), src, len);
330 }
331 return len;
332}
333
340template <char PadC, std::size_t SizeN>
341constexpr std::size_t lpstrcpy(char (&dst)[SizeN], const char* src) noexcept
342{
343 return lpstrcpy<PadC>(dst, src, SizeN);
344}
345
352template <char PadC>
353constexpr std::size_t lpstrcpy(char* dst, std::string_view src, std::size_t n) noexcept
354{
355 const std::size_t len{std::min(n, src.size())};
356 if (len < n) {
357 std::memset(dst, PadC, n - len);
358 }
359 if (len > 0) {
360 std::memcpy(dst + (n - len), src.data(), len);
361 }
362 return len;
363}
364
371template <char PadC, std::size_t SizeN>
372constexpr std::size_t lpstrcpy(char (&dst)[SizeN], std::string_view src) noexcept
373{
374 return lpstrcpy<PadC>(dst, src, SizeN);
375}
376
377template <typename... ArgsT>
378std::string make_string(ArgsT&&... args)
379{
380 std::stringstream os;
381 (os << ... << args);
382 return os.str();
383}
384} // namespace util
385} // namespace toolbox
386
387#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:55
void rtrim(string_view &s) noexcept
Definition String.cpp:40
void trim(std::string_view &s) noexcept
Definition String.hpp:85
constexpr std::size_t lpstrlen(const char *src, std::size_t n) noexcept
Definition String.hpp:295
std::string make_string(ArgsT &&... args)
Definition String.hpp:378
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:145
std::string_view ltrim_copy(std::string_view s) noexcept
Definition String.hpp:97
std::string_view rtrim_copy(std::string_view s) noexcept
Definition String.hpp:109
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:72
constexpr std::size_t pstrlen(const char *src, std::size_t n) noexcept
Definition String.hpp:170
constexpr ValueT from_string(std::string_view sv)
Definition String.hpp:32
std::string_view sv
Definition Tokeniser.hpp:26
std::string_view trim_copy(std::string_view s) noexcept
Definition String.hpp:121
constexpr std::size_t pstrcpy(char *dst, const char *src, std::size_t n) noexcept
Definition String.hpp:202
constexpr std::size_t pstrcpyid(char *dst, std::int64_t id, std::size_t n) noexcept
Definition String.hpp:270
constexpr std::size_t lpstrcpy(char *dst, const char *src, std::size_t n) noexcept
Definition String.hpp:322
constexpr auto bind() noexcept
Definition Slot.hpp:97