C++ Utilities  5.5.0
Useful C++ classes and routines such as argument parser, IO and conversion utilities
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"
5 #include "./stringconversion.h"
6 
7 #include <string>
8 #include <tuple>
9 
10 namespace CppUtilities {
11 
13 namespace Helper {
14 
15 template <class StringType, class ViewType> using IsStringViewType = std::is_same<ViewType, std::basic_string_view<typename StringType::value_type>>;
16 template <class StringType, class CharType> using IsCharType = std::is_same<typename StringType::value_type, CharType>;
17 namespace Detail {
18 template <typename StringType, typename T>
19 auto IsStringType(int)
20  -> decltype(std::declval<StringType &>().append(std::declval<const T &>()), std::declval<const T &>().size(), Traits::Bool<true>{});
21 template <typename StringType, typename T> Traits::Bool<false> IsStringType(...);
22 template <typename StringType> void functionTakingConstStringRef(const StringType &str);
23 template <typename StringType, typename T>
24 auto IsConvertibleToConstStringRef(int) -> decltype(functionTakingConstStringRef<StringType>(std::declval<const T &>()), Traits::Bool<true>{});
25 template <typename StringType, typename T> Traits::Bool<false> IsConvertibleToConstStringRef(...);
26 template <typename StringType, typename T>
27 auto IsConvertibleToConstStringRefViaNative(int)
28  -> decltype(functionTakingConstStringRef<StringType>(std::declval<const T &>().native()), Traits::Bool<true>{});
29 template <typename StringType, typename T> Traits::Bool<false> IsConvertibleToConstStringRefViaNative(...);
30 } // namespace Detail
31 template <typename StringType, typename StringType2>
32 using IsStringType = Traits::All<Traits::Not<IsStringViewType<StringType, StringType2>>, decltype(Detail::IsStringType<StringType, StringType2>(0))>;
33 template <typename StringType, typename StringType2>
34 using IsConvertibleToConstStringRefViaNative = Traits::All<Traits::Not<IsStringType<StringType, StringType2>>,
35  decltype(Detail::IsConvertibleToConstStringRefViaNative<StringType, StringType2>(0))>;
36 template <typename StringType, typename StringType2>
37 using IsConvertibleToConstStringRef = Traits::All<Traits::Not<Traits::Any<IsStringType<StringType, StringType2>, IsCharType<StringType, StringType2>,
38  IsConvertibleToConstStringRefViaNative<StringType, StringType2>>>,
39  decltype(Detail::IsConvertibleToConstStringRef<StringType, StringType2>(0))>;
40 
41 template <class StringType, class StringType2, Traits::EnableIf<IsStringType<StringType, StringType2>> * = nullptr>
42 inline std::size_t computeTupleElementSize(const StringType2 *str)
43 {
44  return str->size();
45 }
46 
47 template <class StringType, class StringType2, Traits::EnableIf<IsStringType<StringType, StringType2>> * = nullptr>
48 inline std::size_t computeTupleElementSize(const StringType2 &str)
49 {
50  return str.size();
51 }
52 
53 template <class StringType, class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRef<StringType, ConvertibleType>> * = nullptr>
54 inline std::size_t computeTupleElementSize(const ConvertibleType *str)
55 {
56  return computeTupleElementSize<StringType, StringType>(*str);
57 }
58 
59 template <class StringType, class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRef<StringType, ConvertibleType>> * = nullptr>
60 inline std::size_t computeTupleElementSize(const ConvertibleType &str)
61 {
62  return computeTupleElementSize<StringType, StringType>(str);
63 }
64 
65 template <class StringType, class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, ConvertibleType>> * = nullptr>
66 inline std::size_t computeTupleElementSize(const ConvertibleType *str)
67 {
68  return computeTupleElementSize<StringType, StringType>(str->native());
69 }
70 
71 template <class StringType, class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, ConvertibleType>> * = nullptr>
72 inline std::size_t computeTupleElementSize(const ConvertibleType &str)
73 {
74  return computeTupleElementSize<StringType, StringType>(str.native());
75 }
76 
77 template <class StringType, class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * = nullptr>
78 inline std::size_t computeTupleElementSize(const ViewType *str)
79 {
80  return str->size();
81 }
82 
83 template <class StringType, class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * = nullptr>
84 inline std::size_t computeTupleElementSize(ViewType str)
85 {
86  return str.size();
87 }
88 
89 template <class StringType, class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * = nullptr>
90 constexpr std::size_t computeTupleElementSize(const CharType *str)
91 {
92  return std::char_traits<CharType>::length(str);
93 }
94 
95 template <class StringType, class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * = nullptr>
96 constexpr std::size_t computeTupleElementSize(CharType)
97 {
98  return 1;
99 }
100 
101 template <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>
104 constexpr std::size_t computeTupleElementSize(IntegralType number, typename StringType::value_type base = 10)
105 {
106  std::size_t size = 0;
107  for (auto n = number; n; n /= base, ++size)
108  ;
109  return size;
110 }
111 
112 template <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>
115 constexpr std::size_t computeTupleElementSize(IntegralType number, typename StringType::value_type base = 10)
116 {
117  std::size_t size = number < 0 ? 1 : 0;
118  for (auto n = number; n; n /= base, ++size)
119  ;
120  return size;
121 }
122 
123 template <class StringType, typename TupleType, Traits::EnableIf<Traits::IsSpecializationOf<std::decay_t<TupleType>, std::tuple>> * = nullptr>
124 constexpr std::size_t computeTupleElementSize(TupleType &&tuple, typename StringType::value_type base = 10);
125 
126 template <class StringType, class StringType2,
127  Traits::EnableIfAny<IsStringType<StringType, StringType2>, IsConvertibleToConstStringRef<StringType, StringType2>> * = nullptr>
128 inline void append(StringType &target, const StringType2 *str)
129 {
130  target.append(*str);
131 }
132 
133 template <class StringType, class StringType2,
134  Traits::EnableIfAny<IsStringType<StringType, StringType2>, IsConvertibleToConstStringRef<StringType, StringType2>> * = nullptr>
135 inline void append(StringType &target, const StringType2 &str)
136 {
137  target.append(str);
138 }
139 
140 template <class StringType, class StringType2, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, StringType2>> * = nullptr>
141 inline void append(StringType &target, const StringType2 *str)
142 {
143  target.append(str->native());
144 }
145 
146 template <class StringType, class StringType2, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, StringType2>> * = nullptr>
147 inline void append(StringType &target, const StringType2 &str)
148 {
149  target.append(str.native());
150 }
151 
152 template <class StringType, class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * = nullptr>
153 inline void append(StringType &target, const ViewType *str)
154 {
155  target.append(*str);
156 }
157 
158 template <class StringType, class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * = nullptr>
159 inline void append(StringType &target, ViewType str)
160 {
161  target.append(str);
162 }
163 
164 template <class StringType, class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * = nullptr>
165 inline void append(StringType &target, const CharType *str)
166 {
167  target.append(str);
168 }
169 
170 template <class StringType, class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * = nullptr>
171 inline void append(StringType &target, CharType c)
172 {
173  target += c;
174 }
175 
176 template <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>
179 inline void append(StringType &target, IntegralType number, typename StringType::value_type base = 10)
180 {
181  const auto start = target.begin() + target.size();
182  do {
183  target.insert(start, digitToChar<typename StringType::value_type>(number % base));
184  number /= base;
185  } while (number);
186 }
187 
188 template <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>
191 inline void append(StringType &target, IntegralType number, typename StringType::value_type base = 10)
192 {
193  if (number < 0) {
194  target += '-';
195  number = -number;
196  }
197  const auto start = target.begin() + target.size();
198  do {
199  target.insert(start, digitToChar<typename StringType::value_type>(number % base));
200  number /= base;
201  } while (number);
202 }
203 
204 template <class StringType, typename TupleType, Traits::EnableIf<Traits::IsSpecializationOf<std::decay_t<TupleType>, std::tuple>> * = nullptr>
205 constexpr void append(StringType &target, TupleType &&tuple, typename StringType::value_type base = 10);
206 
207 template <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 
220 template <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 
232 template <class StringType, typename TupleType, Traits::EnableIf<Traits::IsSpecializationOf<std::decay_t<TupleType>, std::tuple>> *>
233 constexpr std::size_t computeTupleElementSize(TupleType &&tuple, typename StringType::value_type base)
234 {
235  return TupleToString<StringType, TupleType, std::tuple_size_v<std::decay_t<TupleType>>>::precomputeSize(std::forward<TupleType>(tuple));
236 }
237 
238 template <class StringType, typename TupleType, Traits::EnableIf<Traits::IsSpecializationOf<std::decay_t<TupleType>, std::tuple>> *>
239 constexpr void append(StringType &target, TupleType &&tuple, typename StringType::value_type base)
240 {
241  return TupleToString<StringType, TupleType, std::tuple_size_v<std::decay_t<TupleType>>>::append(std::forward<TupleType>(tuple), target);
242 }
243 
244 } // namespace Helper
246 
250 template <class StringType = std::string, class... Args> inline StringType tupleToString(const std::tuple<Args...> &tuple)
251 {
252  StringType res;
253  res.reserve(Helper::TupleToString<StringType, decltype(tuple), sizeof...(Args)>::precomputeSize(tuple));
254  Helper::TupleToString<StringType, decltype(tuple), sizeof...(Args)>::append(tuple, res);
255  return res;
256 }
257 
258 template <class StringType = std::string, class... Args> inline StringType argsToString(Args &&... args)
259 {
260  return tupleToString(std::tuple<Args &&...>(std::forward<Args>(args)...));
261 }
262 
266 template <class Tuple, class StringType,
267  Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
268  * = nullptr>
269 constexpr auto operator%(const Tuple &lhs, const StringType &rhs) -> decltype(std::tuple_cat(lhs, std::make_tuple(&rhs)))
270 {
271  return std::tuple_cat(lhs, std::make_tuple(&rhs));
272 }
273 
277 template <class Tuple> constexpr auto operator%(const Tuple &lhs, const char *rhs) -> decltype(std::tuple_cat(lhs, std::make_tuple(rhs)))
278 {
279  return std::tuple_cat(lhs, std::make_tuple(rhs));
280 }
281 
285 template <class Tuple, typename IntegralType, Traits::EnableIf<std::is_integral<IntegralType>> * = nullptr>
286 constexpr auto operator%(const Tuple &lhs, IntegralType rhs) -> decltype(std::tuple_cat(lhs, std::make_tuple(rhs)))
287 {
288  return std::tuple_cat(lhs, std::make_tuple(rhs));
289 }
290 
294 template <class StringType,
295  Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
296  * = nullptr>
297 constexpr auto operator%(const StringType &lhs, const StringType &rhs) -> decltype(std::make_tuple(&lhs, &rhs))
298 {
299  return std::make_tuple(&lhs, &rhs);
300 }
301 
305 template <class StringType,
306  Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
307  * = nullptr>
308 constexpr auto operator%(const char *lhs, const StringType &rhs) -> decltype(std::make_tuple(lhs, &rhs))
309 {
310  return std::make_tuple(lhs, &rhs);
311 }
312 
316 template <class StringType,
317  Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
318  * = nullptr>
319 constexpr auto operator%(const StringType &lhs, const char *rhs) -> decltype(std::make_tuple(&lhs, rhs))
320 {
321  return std::make_tuple(&lhs, rhs);
322 }
323 
327 template <class StringType,
328  Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
329  * = nullptr>
330 constexpr auto operator%(const StringType &lhs, char rhs) -> decltype(std::make_tuple(&lhs, rhs))
331 {
332  return std::make_tuple(&lhs, rhs);
333 }
334 
338 template <class StringType,
339  Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
340  * = nullptr>
341 constexpr auto operator%(char lhs, const StringType &rhs) -> decltype(std::make_tuple(lhs, &rhs))
342 {
343  return std::make_tuple(lhs, &rhs);
344 }
345 
355 template <class Tuple, class StringType,
356  Traits::EnableIf<Traits::IsSpecializationOf<Tuple, std::tuple>,
357  Traits::Any<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>>
358  * = nullptr>
359 inline std::string operator+(const Tuple &lhs, const StringType &rhs)
360 {
361  return tupleToString(std::tuple_cat(lhs, std::make_tuple(&rhs)));
362 }
363 
373 template <class Tuple, Traits::EnableIf<Traits::IsSpecializationOf<Tuple, std::tuple>> * = nullptr>
374 inline std::string operator+(const Tuple &lhs, const char *rhs)
375 {
376  return tupleToString(std::tuple_cat(lhs, std::make_tuple(rhs)));
377 }
378 
388 template <class Tuple, typename IntegralType,
389  Traits::EnableIf<Traits::IsSpecializationOf<Tuple, std::tuple>, std::is_integral<IntegralType>> * = nullptr>
390 inline std::string operator+(const Tuple &lhs, IntegralType rhs)
391 {
392  return tupleToString(std::tuple_cat(lhs, std::make_tuple(rhs)));
393 }
394 } // namespace CppUtilities
395 
396 #endif // CONVERSION_UTILITIES_STRINGBUILDER_H
stringconversion.h
CppUtilities::operator+
CPP_UTILITIES_EXPORT DateTime operator+(DateTime begin, Period period)
Adds the specified period to the specified date.
Definition: period.cpp:60
CppUtilities::operator%
constexpr auto operator%(const Tuple &lhs, const StringType &rhs) -> decltype(std::tuple_cat(lhs, std::make_tuple(&rhs)))
Allows construction of string-tuples via %-operator, eg.
Definition: stringbuilder.h:269
CppUtilities::argsToString
StringType argsToString(Args &&... args)
Definition: stringbuilder.h:258
CppUtilities
Contains all utilities provides by the c++utilities library.
Definition: argumentparser.h:17
CppUtilities::tupleToString
StringType tupleToString(const std::tuple< Args... > &tuple)
Concatenates all strings hold by the specified tuple.
Definition: stringbuilder.h:250