1#ifndef CONVERSION_UTILITIES_STRINGBUILDER_H
2#define CONVERSION_UTILITIES_STRINGBUILDER_H
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>;
18template <
typename StringType,
typename T>
20 int) ->
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(
28 int) ->
decltype(functionTakingConstStringRef<StringType>(std::declval<const T &>().native()), Traits::Bool<true>{});
29template <
typename StringType,
typename T> Traits::Bool<false> IsConvertibleToConstStringRefViaNative(...);
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>,
38 IsConvertibleToConstStringRefViaNative<StringType, StringType2>>>,
39 decltype(Detail::IsConvertibleToConstStringRef<StringType, StringType2>(0))>;
41template <
class StringType,
class StringType2, Traits::EnableIf<IsStringType<StringType, StringType2>> * =
nullptr>
42inline std::size_t computeTupleElementSize(
const StringType2 *str)
47template <
class StringType,
class StringType2, Traits::EnableIf<IsStringType<StringType, StringType2>> * =
nullptr>
48inline std::size_t computeTupleElementSize(
const StringType2 &str)
53template <
class StringType,
class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRef<StringType, ConvertibleType>> * =
nullptr>
54inline std::size_t computeTupleElementSize(
const ConvertibleType *str)
56 return computeTupleElementSize<StringType, StringType>(*str);
59template <
class StringType,
class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRef<StringType, ConvertibleType>> * =
nullptr>
60inline std::size_t computeTupleElementSize(
const ConvertibleType &str)
62 return computeTupleElementSize<StringType, StringType>(str);
65template <
class StringType,
class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, ConvertibleType>> * =
nullptr>
66inline std::size_t computeTupleElementSize(
const ConvertibleType *str)
68 return computeTupleElementSize<StringType, StringType>(str->native());
71template <
class StringType,
class ConvertibleType, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, ConvertibleType>> * =
nullptr>
72inline std::size_t computeTupleElementSize(
const ConvertibleType &str)
74 return computeTupleElementSize<StringType, StringType>(str.native());
77template <
class StringType,
class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * =
nullptr>
78inline std::size_t computeTupleElementSize(
const ViewType *str)
83template <
class StringType,
class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * =
nullptr>
84inline std::size_t computeTupleElementSize(ViewType str)
89template <
class StringType,
class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * =
nullptr>
90constexpr std::size_t computeTupleElementSize(
const CharType *str)
92 return std::char_traits<CharType>::length(str);
95template <
class StringType,
class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * =
nullptr>
96constexpr std::size_t computeTupleElementSize(CharType)
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>
104constexpr 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)
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>
115constexpr 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)
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);
126template <
class StringType,
class StringType2,
127 Traits::EnableIfAny<IsStringType<StringType, StringType2>, IsConvertibleToConstStringRef<StringType, StringType2>> * =
nullptr>
128inline void append(StringType &target,
const StringType2 *str)
133template <
class StringType,
class StringType2,
134 Traits::EnableIfAny<IsStringType<StringType, StringType2>, IsConvertibleToConstStringRef<StringType, StringType2>> * =
nullptr>
135inline void append(StringType &target,
const StringType2 &str)
140template <
class StringType,
class StringType2, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, StringType2>> * =
nullptr>
141inline void append(StringType &target,
const StringType2 *str)
143 target.append(str->native());
146template <
class StringType,
class StringType2, Traits::EnableIf<IsConvertibleToConstStringRefViaNative<StringType, StringType2>> * =
nullptr>
147inline void append(StringType &target,
const StringType2 &str)
149 target.append(str.native());
152template <
class StringType,
class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * =
nullptr>
153inline void append(StringType &target,
const ViewType *str)
158template <
class StringType,
class ViewType, Traits::EnableIf<IsStringViewType<StringType, ViewType>> * =
nullptr>
159inline void append(StringType &target, ViewType str)
164template <
class StringType,
class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * =
nullptr>
165inline void append(StringType &target,
const CharType *str)
170template <
class StringType,
class CharType, Traits::EnableIf<IsCharType<StringType, CharType>> * =
nullptr>
171inline void append(StringType &target, CharType c)
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>
179inline 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)));
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>
191inline 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)));
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);
207template <
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));
220template <
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));
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)
236 return TupleToString<StringType, TupleType, std::tuple_size_v<std::decay_t<TupleType>>>::precomputeSize(std::forward<TupleType>(tuple));
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)
243 return TupleToString<StringType, TupleType, std::tuple_size_v<std::decay_t<TupleType>>>::append(std::forward<TupleType>(tuple), target);
252template <
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);
260template <
class StringType = std::string,
class... Args>
inline StringType
argsToString(Args &&...args)
262 return tupleToString(std::tuple<Args &&...>(std::forward<Args>(args)...));
268template <
class Tuple,
class StringType,
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)))
273 return std::tuple_cat(lhs, std::tuple<const StringType &>(rhs));
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)))
282 return std::tuple_cat(lhs, std::tuple<const char *>(rhs));
288template <
class Tuple,
typename IntegralType,
290constexpr auto operator%(
const Tuple &lhs, IntegralType rhs) ->
decltype(std::tuple_cat(lhs, std::tuple<IntegralType>(rhs)))
292 return std::tuple_cat(lhs, std::tuple<IntegralType>(rhs));
298template <
class StringType,
301constexpr auto operator%(
const StringType &lhs,
const StringType &rhs) ->
decltype(std::tuple<const StringType &, const StringType &>(lhs, rhs))
303 return std::tuple<const StringType &, const StringType &>(lhs, rhs);
309template <
class StringType,
312constexpr auto operator%(
const char *lhs,
const StringType &rhs) ->
decltype(std::tuple<const char *, const StringType &>(lhs, rhs))
314 return std::tuple<const char *, const StringType &>(lhs, rhs);
320template <
class StringType,
323constexpr auto operator%(
const StringType &lhs,
const char *rhs) ->
decltype(std::tuple<const StringType &, const char *>(lhs, rhs))
325 return std::tuple<const StringType &, const char *>(lhs, rhs);
331template <
class StringType,
334constexpr auto operator%(
const StringType &lhs,
char rhs) ->
decltype(std::tuple<const StringType &, char>(lhs, rhs))
336 return std::tuple<const StringType &, char>(lhs, rhs);
342template <
class StringType,
345constexpr auto operator%(
char lhs,
const StringType &rhs) ->
decltype(std::tuple<char, const StringType &>(lhs, rhs))
347 return std::tuple<char, const StringType &>(lhs, rhs);
359template <
class Tuple,
class StringType,
361 Traits::Any<Traits::IsSpecializationOf<StringType, std::basic_string>, Traits::IsSpecializationOf<StringType, std::basic_string_view>>>
363inline std::string
operator+(
const Tuple &lhs,
const StringType &rhs)
365 return tupleToString(std::tuple_cat(lhs, std::tuple<const StringType &>(rhs)));
377template <
class Tuple, Traits::EnableIf<Traits::IsSpecializationOf<Tuple, std::tuple>> * =
nullptr>
378inline std::string
operator+(
const Tuple &lhs,
const char *rhs)
380 return tupleToString(std::tuple_cat(lhs, std::tuple<const char *>(rhs)));
392template <
class Tuple,
typename IntegralType,
394inline std::string
operator+(
const Tuple &lhs, IntegralType rhs)
396 return tupleToString(std::tuple_cat(lhs, std::tuple<IntegralType>(rhs)));
#define CPP_UTILITIES_UNUSED(x)
Prevents warnings about unused variables.
typename std::enable_if< Any< Condition... >::value, Detail::Enabler >::type EnableIfAny
Shortcut for std::enable_if to apply Traits::Any and omit ::value and ::type.
typename std::enable_if< All< Condition... >::value, Detail::Enabler >::type EnableIf
Shortcut for std::enable_if to omit ::value and ::type.
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::tuple< const StringType & >(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.