1 #ifndef CONVERSION_UTILITIES_STRINGBUILDER_H
2 #define CONVERSION_UTILITIES_STRINGBUILDER_H
4 #include "../misc/traits.h"
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>;
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(...);
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))>;
41 template <
class StringType,
class StringType2, Traits::EnableIf<IsStringType<StringType, StringType2>> * =
nullptr>
42 inline std::size_t computeTupleElementSize(
const StringType2 *str)
47 template <
class StringType,
class StringType2, Traits::EnableIf<IsStringType<StringType, StringType2>> * =
nullptr>
48 inline std::size_t computeTupleElementSize(
const StringType2 &str)
53 template <
class StringType,
class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRef<StringType, ConvertibleType>> * =
nullptr>
54 inline std::size_t computeTupleElementSize(
const ConvertibleType *str)
56 return computeTupleElementSize<StringType, StringType>(*str);
59 template <
class StringType,
class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRef<StringType, ConvertibleType>> * =
nullptr>
60 inline std::size_t computeTupleElementSize(
const ConvertibleType &str)
62 return computeTupleElementSize<StringType, StringType>(str);
65 template <
class StringType,
class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, ConvertibleType>> * =
nullptr>
66 inline std::size_t computeTupleElementSize(
const ConvertibleType *str)
68 return computeTupleElementSize<StringType, StringType>(str->native());
71 template <
class StringType,
class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, ConvertibleType>> * =
nullptr>
72 inline std::size_t computeTupleElementSize(
const ConvertibleType &str)
74 return computeTupleElementSize<StringType, StringType>(str.native());
77 template <
class StringType,
class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * =
nullptr>
78 inline std::size_t computeTupleElementSize(
const ViewType *str)
83 template <
class StringType,
class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * =
nullptr>
84 inline std::size_t computeTupleElementSize(ViewType str)
89 template <
class StringType,
class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * =
nullptr>
90 constexpr std::size_t computeTupleElementSize(
const CharType *str)
92 return std::char_traits<CharType>::length(str);
95 template <
class StringType,
class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * =
nullptr>
96 constexpr std::size_t computeTupleElementSize(CharType)
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, IntegralType base = 10)
106 auto size = std::size_t(0u);
107 for (
auto n = number; n; n /= base, ++size)
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, IntegralType base = 10)
117 auto size = std::size_t(number < 0 ? 1u : 0u);
118 for (
auto n = number; n; n /= base, ++size)
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);
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)
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)
140 template <
class StringType,
class StringType2, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, StringType2>> * =
nullptr>
141 inline void append(StringType &target,
const StringType2 *str)
143 target.append(str->native());
146 template <
class StringType,
class StringType2, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, StringType2>> * =
nullptr>
147 inline void append(StringType &target,
const StringType2 &str)
149 target.append(str.native());
152 template <
class StringType,
class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * =
nullptr>
153 inline void append(StringType &target,
const ViewType *str)
158 template <
class StringType,
class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * =
nullptr>
159 inline void append(StringType &target, ViewType str)
164 template <
class StringType,
class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * =
nullptr>
165 inline void append(StringType &target,
const CharType *str)
170 template <
class StringType,
class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * =
nullptr>
171 inline void append(StringType &target, CharType c)
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, IntegralType base = 10)
181 const auto start = target.begin() +
static_cast<typename StringType::difference_type
>(target.size());
183 target.insert(start,
static_cast<typename StringType::value_type
>(digitToChar<IntegralType>(number % base)));
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, IntegralType base = 10)
197 const auto start = target.begin() +
static_cast<typename StringType::difference_type
>(target.size());
199 target.insert(start,
static_cast<typename StringType::value_type
>(digitToChar<IntegralType>(number % base)));
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);
207 template <
class StringType,
class Tuple, std::
size_t N>
struct TupleToString {
208 static inline std::size_t precomputeSize(
const Tuple &tuple)
210 return TupleToString<StringType, Tuple, N - 1>::precomputeSize(tuple) + computeTupleElementSize<StringType>(std::get<N - 1>(tuple));
213 static inline void append(
const Tuple &tuple, StringType &str)
215 TupleToString<StringType, Tuple, N - 1>::append(tuple, str);
216 Helper::append(str, std::get<N - 1>(tuple));
220 template <
class StringType,
class Tuple>
struct TupleToString<StringType, Tuple, 1> {
221 static inline std::size_t precomputeSize(
const Tuple &tuple)
223 return computeTupleElementSize<StringType>(std::get<0>(tuple));
226 static inline void append(
const Tuple &tuple, StringType &str)
228 Helper::append(str, std::get<0>(tuple));
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)
236 return TupleToString<StringType, TupleType, std::tuple_size_v<std::decay_t<TupleType>>>::precomputeSize(std::forward<TupleType>(tuple));
239 template <
class StringType,
typename TupleType, Traits::EnableIf<Traits::IsSpecializationOf<std::decay_t<TupleType>, std::tuple>> *>
240 constexpr
void append(StringType &target, TupleType &&tuple,
typename StringType::value_type base)
243 return TupleToString<StringType, TupleType, std::tuple_size_v<std::decay_t<TupleType>>>::append(std::forward<TupleType>(tuple), target);
252 template <
class StringType = std::string,
class... Args>
inline StringType
tupleToString(
const std::tuple<Args...> &tuple)
255 res.reserve(Helper::TupleToString<StringType, decltype(tuple),
sizeof...(Args)>::precomputeSize(tuple));
256 Helper::TupleToString<StringType, decltype(tuple),
sizeof...(Args)>::append(tuple, res);
260 template <
class StringType = std::string,
class... Args>
inline StringType
argsToString(Args &&...args)
262 return tupleToString(std::tuple<Args &&...>(std::forward<Args>(args)...));
268 template <
class Tuple,
class StringType,
269 Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
271 constexpr
auto operator%(
const Tuple &lhs,
const StringType &rhs) -> decltype(std::tuple_cat(lhs, std::make_tuple(&rhs)))
273 return std::tuple_cat(lhs, std::make_tuple(&rhs));
279 template <
class Tuple> constexpr
auto operator%(
const Tuple &lhs,
const char *rhs) -> decltype(std::tuple_cat(lhs, std::make_tuple(rhs)))
281 return std::tuple_cat(lhs, std::make_tuple(rhs));
287 template <
class Tuple,
typename IntegralType, Traits::EnableIf<std::is_
integral<IntegralType>> * =
nullptr>
288 constexpr
auto operator%(
const Tuple &lhs, IntegralType rhs) -> decltype(std::tuple_cat(lhs, std::make_tuple(rhs)))
290 return std::tuple_cat(lhs, std::make_tuple(rhs));
296 template <
class StringType,
297 Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
299 constexpr
auto operator%(
const StringType &lhs,
const StringType &rhs) -> decltype(std::make_tuple(&lhs, &rhs))
301 return std::make_tuple(&lhs, &rhs);
307 template <
class StringType,
308 Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
310 constexpr
auto operator%(
const char *lhs,
const StringType &rhs) -> decltype(std::make_tuple(lhs, &rhs))
312 return std::make_tuple(lhs, &rhs);
318 template <
class StringType,
319 Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
321 constexpr
auto operator%(
const StringType &lhs,
const char *rhs) -> decltype(std::make_tuple(&lhs, rhs))
323 return std::make_tuple(&lhs, rhs);
329 template <
class StringType,
330 Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
332 constexpr
auto operator%(
const StringType &lhs,
char rhs) -> decltype(std::make_tuple(&lhs, rhs))
334 return std::make_tuple(&lhs, rhs);
340 template <
class StringType,
341 Traits::EnableIfAny<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>
343 constexpr
auto operator%(
char lhs,
const StringType &rhs) -> decltype(std::make_tuple(lhs, &rhs))
345 return std::make_tuple(lhs, &rhs);
357 template <
class Tuple,
class StringType,
358 Traits::EnableIf<Traits::IsSpecializationOf<Tuple, std::tuple>,
359 Traits::Any<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>>
361 inline std::string
operator+(
const Tuple &lhs,
const StringType &rhs)
363 return tupleToString(std::tuple_cat(lhs, std::make_tuple(&rhs)));
375 template <
class Tuple, Traits::EnableIf<Traits::IsSpecializationOf<Tuple, std::tuple>> * =
nullptr>
376 inline std::string
operator+(
const Tuple &lhs,
const char *rhs)
378 return tupleToString(std::tuple_cat(lhs, std::make_tuple(rhs)));
390 template <
class Tuple,
typename IntegralType,
391 Traits::EnableIf<Traits::IsSpecializationOf<Tuple, std::tuple>, std::is_integral<IntegralType>> * =
nullptr>
392 inline std::string
operator+(
const Tuple &lhs, IntegralType rhs)
394 return tupleToString(std::tuple_cat(lhs, std::make_tuple(rhs)));
#define CPP_UTILITIES_UNUSED(x)
Prevents warnings about unused variables.
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.
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.
StringType argsToString(Args &&...args)
StringType tupleToString(const std::tuple< Args... > &tuple)
Concatenates all strings hold by the specified tuple.