C++ Utilities 5.24.7
Useful C++ classes and routines such as argument parser, IO and conversion utilities
Loading...
Searching...
No Matches
stringbuilder.h
Go to the documentation of this file.
1#ifndef CONVERSION_UTILITIES_STRINGBUILDER_H
2#define CONVERSION_UTILITIES_STRINGBUILDER_H
3
4#include "../misc/traits.h"
6
7#include <string>
8#include <tuple>
9
10namespace CppUtilities {
11
13namespace Helper {
14
15template <class StringType, class ViewType> using IsStringViewType = std::is_same<ViewType, std::basic_string_view<typename StringType::value_type>>;
16template <class StringType, class CharType> using IsCharType = std::is_same<typename StringType::value_type, CharType>;
17namespace Detail {
18template <typename StringType, typename T>
19auto IsStringType(int)
20 -> decltype(std::declval<StringType &>().append(std::declval<const T &>()), std::declval<const T &>().size(), Traits::Bool<true>{});
21template <typename StringType, typename T> Traits::Bool<false> IsStringType(...);
22template <typename StringType> void functionTakingConstStringRef(const StringType &str);
23template <typename StringType, typename T>
24auto IsConvertibleToConstStringRef(int) -> decltype(functionTakingConstStringRef<StringType>(std::declval<const T &>()), Traits::Bool<true>{});
25template <typename StringType, typename T> Traits::Bool<false> IsConvertibleToConstStringRef(...);
26template <typename StringType, typename T>
27auto IsConvertibleToConstStringRefViaNative(int)
28 -> decltype(functionTakingConstStringRef<StringType>(std::declval<const T &>().native()), Traits::Bool<true>{});
29template <typename StringType, typename T> Traits::Bool<false> IsConvertibleToConstStringRefViaNative(...);
30} // namespace Detail
31template <typename StringType, typename StringType2>
32using IsStringType = Traits::All<Traits::Not<IsStringViewType<StringType, StringType2>>, decltype(Detail::IsStringType<StringType, StringType2>(0))>;
33template <typename StringType, typename StringType2>
34using IsConvertibleToConstStringRefViaNative = Traits::All<Traits::Not<IsStringType<StringType, StringType2>>,
35 decltype(Detail::IsConvertibleToConstStringRefViaNative<StringType, StringType2>(0))>;
36template <typename StringType, typename StringType2>
37using IsConvertibleToConstStringRef = Traits::All<Traits::Not<Traits::Any<IsStringType<StringType, StringType2>, IsCharType<StringType, StringType2>,
39 decltype(Detail::IsConvertibleToConstStringRef<StringType, StringType2>(0))>;
40
41template <class StringType, class StringType2, Traits::EnableIf<IsStringType<StringType, StringType2>> * = nullptr>
42inline std::size_t computeTupleElementSize(const StringType2 *str)
43{
44 return str->size();
45}
46
47template <class StringType, class StringType2, Traits::EnableIf<IsStringType<StringType, StringType2>> * = nullptr>
48inline std::size_t computeTupleElementSize(const StringType2 &str)
49{
50 return str.size();
51}
52
53template <class StringType, class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRef<StringType, ConvertibleType>> * = nullptr>
54inline std::size_t computeTupleElementSize(const ConvertibleType *str)
55{
57}
58
59template <class StringType, class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRef<StringType, ConvertibleType>> * = nullptr>
60inline std::size_t computeTupleElementSize(const ConvertibleType &str)
61{
63}
64
65template <class StringType, class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, ConvertibleType>> * = nullptr>
66inline std::size_t computeTupleElementSize(const ConvertibleType *str)
67{
69}
70
71template <class StringType, class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, ConvertibleType>> * = nullptr>
72inline std::size_t computeTupleElementSize(const ConvertibleType &str)
73{
75}
76
77template <class StringType, class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * = nullptr>
78inline std::size_t computeTupleElementSize(const ViewType *str)
79{
80 return str->size();
81}
82
83template <class StringType, class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * = nullptr>
84inline std::size_t computeTupleElementSize(ViewType str)
85{
86 return str.size();
87}
88
89template <class StringType, class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * = nullptr>
90constexpr std::size_t computeTupleElementSize(const CharType *str)
91{
92 return std::char_traits<CharType>::length(str);
93}
94
95template <class StringType, class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * = nullptr>
96constexpr std::size_t computeTupleElementSize(CharType)
97{
98 return 1;
99}
100
101template <class StringType, typename IntegralType,
102 Traits::EnableIf<Traits::Not<std::is_same<typename StringType::value_type, IntegralType>>, std::is_integral<IntegralType>,
103 std::is_unsigned<IntegralType>> * = nullptr>
105{
106 auto size = std::size_t(0u);
107 for (auto n = number; n; n /= base, ++size)
108 ;
109 return size;
110}
111
112template <class StringType, typename IntegralType,
113 Traits::EnableIf<Traits::Not<std::is_same<typename StringType::value_type, IntegralType>>, std::is_integral<IntegralType>,
114 std::is_signed<IntegralType>> * = nullptr>
116{
117 auto size = std::size_t(number < 0 ? 1u : 0u);
118 for (auto n = number; n; n /= base, ++size)
119 ;
120 return size;
121}
122
123template <class StringType, typename TupleType, Traits::EnableIf<Traits::IsSpecializationOf<std::decay_t<TupleType>, std::tuple>> * = nullptr>
124constexpr std::size_t computeTupleElementSize(TupleType &&tuple, typename StringType::value_type base = 10);
125
126template <class StringType, class StringType2,
127 Traits::EnableIfAny<IsStringType<StringType, StringType2>, IsConvertibleToConstStringRef<StringType, StringType2>> * = nullptr>
128inline void append(StringType &target, const StringType2 *str)
129{
130 target.append(*str);
131}
132
133template <class StringType, class StringType2,
134 Traits::EnableIfAny<IsStringType<StringType, StringType2>, IsConvertibleToConstStringRef<StringType, StringType2>> * = nullptr>
135inline void append(StringType &target, const StringType2 &str)
136{
137 target.append(str);
138}
139
140template <class StringType, class StringType2, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, StringType2>> * = nullptr>
141inline void append(StringType &target, const StringType2 *str)
142{
143 target.append(str->native());
144}
145
146template <class StringType, class StringType2, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, StringType2>> * = nullptr>
147inline void append(StringType &target, const StringType2 &str)
148{
149 target.append(str.native());
150}
151
152template <class StringType, class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * = nullptr>
153inline void append(StringType &target, const ViewType *str)
154{
155 target.append(*str);
156}
157
158template <class StringType, class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * = nullptr>
159inline void append(StringType &target, ViewType str)
160{
161 target.append(str);
162}
163
164template <class StringType, class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * = nullptr>
165inline void append(StringType &target, const CharType *str)
166{
167 target.append(str);
168}
169
170template <class StringType, class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * = nullptr>
171inline void append(StringType &target, CharType c)
172{
173 target += c;
174}
175
176template <class StringType, typename IntegralType,
177 Traits::EnableIf<Traits::Not<std::is_same<typename StringType::value_type, IntegralType>>, std::is_integral<IntegralType>,
178 std::is_unsigned<IntegralType>> * = nullptr>
180{
181 const auto start = target.begin() + static_cast<typename StringType::difference_type>(target.size());
182 do {
183 target.insert(start, static_cast<typename StringType::value_type>(digitToChar<IntegralType>(number % base)));
184 number /= base;
185 } while (number);
186}
187
188template <class StringType, typename IntegralType,
189 Traits::EnableIf<Traits::Not<std::is_same<typename StringType::value_type, IntegralType>>, std::is_integral<IntegralType>,
190 std::is_signed<IntegralType>> * = nullptr>
192{
193 if (number < 0) {
194 target += '-';
195 number = -number;
196 }
197 const auto start = target.begin() + static_cast<typename StringType::difference_type>(target.size());
198 do {
199 target.insert(start, static_cast<typename StringType::value_type>(digitToChar<IntegralType>(number % base)));
200 number /= base;
201 } while (number);
202}
203
204template <class StringType, typename TupleType, Traits::EnableIf<Traits::IsSpecializationOf<std::decay_t<TupleType>, std::tuple>> * = nullptr>
205constexpr void append(StringType &target, TupleType &&tuple, typename StringType::value_type base = 10);
206
207template <class StringType, class Tuple, std::size_t N> struct TupleToString {
208 static inline std::size_t precomputeSize(const Tuple &tuple)
209 {
210 return TupleToString<StringType, Tuple, N - 1>::precomputeSize(tuple) + computeTupleElementSize<StringType>(std::get<N - 1>(tuple));
211 }
212
213 static inline void append(const Tuple &tuple, StringType &str)
214 {
215 TupleToString<StringType, Tuple, N - 1>::append(tuple, str);
216 Helper::append(str, std::get<N - 1>(tuple));
217 }
218};
219
220template <class StringType, class Tuple> struct TupleToString<StringType, Tuple, 1> {
221 static inline std::size_t precomputeSize(const Tuple &tuple)
222 {
223 return computeTupleElementSize<StringType>(std::get<0>(tuple));
224 }
225
226 static inline void append(const Tuple &tuple, StringType &str)
227 {
228 Helper::append(str, std::get<0>(tuple));
229 }
230};
231
232template <class StringType, typename TupleType, Traits::EnableIf<Traits::IsSpecializationOf<std::decay_t<TupleType>, std::tuple>> *>
233constexpr std::size_t computeTupleElementSize(TupleType &&tuple, typename StringType::value_type base)
234{
237}
238
239template <class StringType, typename TupleType, Traits::EnableIf<Traits::IsSpecializationOf<std::decay_t<TupleType>, std::tuple>> *>
240constexpr void append(StringType &target, TupleType &&tuple, typename StringType::value_type base)
241{
244}
245
246} // namespace Helper
248
252template <class StringType = std::string, class... Args> inline StringType tupleToString(const std::tuple<Args...> &tuple)
253{
255 res.reserve(Helper::TupleToString<StringType, decltype(tuple), sizeof...(Args)>::precomputeSize(tuple));
256 Helper::TupleToString<StringType, decltype(tuple), sizeof...(Args)>::append(tuple, res);
257 return res;
258}
259
260template <class StringType = std::string, class... Args> inline StringType argsToString(Args &&...args)
261{
262 return tupleToString(std::tuple<Args &&...>(std::forward<Args>(args)...));
263}
264
268template <class Tuple, class StringType,
269 Traits::EnableIf<Traits::IsSpecializationOf<Tuple, std::tuple>,
270 Traits::IsSpecializingAnyOf<StringType, std::basic_string, std::basic_string_view>> * = nullptr>
271constexpr auto operator%(const Tuple &lhs, const StringType &rhs) -> decltype(std::tuple_cat(lhs, std::tuple<const StringType &>(rhs)))
272{
273 return std::tuple_cat(lhs, std::tuple<const StringType &>(rhs));
274}
275
279template <class Tuple, Traits::EnableIf<Traits::IsSpecializationOf<Tuple, std::tuple>> * = nullptr>
280constexpr auto operator%(const Tuple &lhs, const char *rhs) -> decltype(std::tuple_cat(lhs, std::tuple<const char *>(rhs)))
281{
282 return std::tuple_cat(lhs, std::tuple<const char *>(rhs));
283}
284
288template <class Tuple, typename IntegralType,
289 Traits::EnableIf<Traits::IsSpecializationOf<Tuple, std::tuple>, std::is_integral<IntegralType>> * = nullptr>
290constexpr auto operator%(const Tuple &lhs, IntegralType rhs) -> decltype(std::tuple_cat(lhs, std::tuple<IntegralType>(rhs)))
291{
292 return std::tuple_cat(lhs, std::tuple<IntegralType>(rhs));
293}
294
298template <class StringType,
299 Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
300 * = nullptr>
301constexpr auto operator%(const StringType &lhs, const StringType &rhs) -> decltype(std::tuple<const StringType &, const StringType &>(lhs, rhs))
302{
303 return std::tuple<const StringType &, const StringType &>(lhs, rhs);
304}
305
309template <class StringType,
310 Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
311 * = nullptr>
312constexpr auto operator%(const char *lhs, const StringType &rhs) -> decltype(std::tuple<const char *, const StringType &>(lhs, rhs))
313{
314 return std::tuple<const char *, const StringType &>(lhs, rhs);
315}
316
320template <class StringType,
321 Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
322 * = nullptr>
323constexpr auto operator%(const StringType &lhs, const char *rhs) -> decltype(std::tuple<const StringType &, const char *>(lhs, rhs))
324{
325 return std::tuple<const StringType &, const char *>(lhs, rhs);
326}
327
331template <class StringType,
332 Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
333 * = nullptr>
334constexpr auto operator%(const StringType &lhs, char rhs) -> decltype(std::tuple<const StringType &, char>(lhs, rhs))
335{
336 return std::tuple<const StringType &, char>(lhs, rhs);
337}
338
342template <class StringType,
343 Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
344 * = nullptr>
345constexpr auto operator%(char lhs, const StringType &rhs) -> decltype(std::tuple<char, const StringType &>(lhs, rhs))
346{
347 return std::tuple<char, const StringType &>(lhs, rhs);
348}
349
359template <class Tuple, class StringType,
360 Traits::EnableIf<Traits::IsSpecializationOf<Tuple, std::tuple>,
361 Traits::Any<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>>
362 * = nullptr>
363inline std::string operator+(const Tuple &lhs, const StringType &rhs)
364{
365 return tupleToString(std::tuple_cat(lhs, std::tuple<const StringType &>(rhs)));
366}
367
377template <class Tuple, Traits::EnableIf<Traits::IsSpecializationOf<Tuple, std::tuple>> * = nullptr>
378inline std::string operator+(const Tuple &lhs, const char *rhs)
379{
380 return tupleToString(std::tuple_cat(lhs, std::tuple<const char *>(rhs)));
381}
382
392template <class Tuple, typename IntegralType,
393 Traits::EnableIf<Traits::IsSpecializationOf<Tuple, std::tuple>, std::is_integral<IntegralType>> * = nullptr>
394inline std::string operator+(const Tuple &lhs, IntegralType rhs)
395{
396 return tupleToString(std::tuple_cat(lhs, std::tuple<IntegralType>(rhs)));
397}
398} // namespace CppUtilities
399
400#endif // CONVERSION_UTILITIES_STRINGBUILDER_H
#define CPP_UTILITIES_UNUSED(x)
Prevents warnings about unused variables.
Definition global.h:92
Contains all utilities provides by the c++utilities library.
CPP_UTILITIES_EXPORT DateTime operator+(DateTime begin, Period period)
Adds the specified period to the specified date.
Definition period.cpp:60
constexpr auto operator%(const Tuple &lhs, const StringType &rhs) -> decltype(std::tuple_cat(lhs, std::tuple< const StringType & >(rhs)))
Allows construction of string-tuples via %-operator, eg.
IntegralType stringToNumber(const StringType &string, BaseType base=10)
Converts the given string to an unsigned/signed number assuming string uses the specified base.
StringType argsToString(Args &&...args)
StringType tupleToString(const std::tuple< Args... > &tuple)
Concatenates all strings hold by the specified tuple.