#ifndef CONVERSION_UTILITIES_STRINGBUILDER_H #define CONVERSION_UTILITIES_STRINGBUILDER_H #include "../misc/traits.h" #include "./stringconversion.h" #include #include namespace CppUtilities { /// \cond namespace Helper { template > * = nullptr> inline std::size_t computeTupleElementSize(const StringType *str) { return str->size(); } template > * = nullptr> inline std::size_t computeTupleElementSize(const StringType &str) { return str.size(); } template > * = nullptr> constexpr std::size_t computeTupleElementSize(const CharType *str) { return std::char_traits::length(str); } template > * = nullptr> constexpr std::size_t computeTupleElementSize(CharType) { return 1; } template >, std::is_integral, std::is_unsigned> * = nullptr> constexpr std::size_t computeTupleElementSize(IntegralType number, typename StringType::value_type base = 10) { std::size_t size = 0; for (auto n = number; n; n /= base, ++size) ; return size; } template >, std::is_integral, std::is_signed> * = nullptr> constexpr std::size_t computeTupleElementSize(IntegralType number, typename StringType::value_type base = 10) { std::size_t size = number < 0 ? 1 : 0; for (auto n = number; n; n /= base, ++size) ; return size; } template > * = nullptr> inline void append(StringType &target, const StringType *str) { target.append(*str); } template > * = nullptr> inline void append(StringType &target, const StringType &str) { target.append(str); } template > * = nullptr> inline void append(StringType &target, const CharType *str) { target.append(str); } template > * = nullptr> inline void append(StringType &target, CharType c) { target += c; } template >, std::is_integral, std::is_unsigned> * = nullptr> inline void append(StringType &target, IntegralType number, typename StringType::value_type base = 10) { const auto start = target.begin() + target.size(); do { target.insert(start, digitToChar(number % base)); number /= base; } while (number); } template >, std::is_integral, std::is_signed> * = nullptr> inline void append(StringType &target, IntegralType number, typename StringType::value_type base = 10) { if (number < 0) { target += '-'; number = -number; } const auto start = target.begin() + target.size(); do { target.insert(start, digitToChar(number % base)); number /= base; } while (number); } template struct TupleToString { static inline std::size_t precomputeSize(const Tuple &tuple) { return TupleToString::precomputeSize(tuple) + computeTupleElementSize(std::get(tuple)); } static inline void append(const Tuple &tuple, StringType &str) { TupleToString::append(tuple, str); Helper::append(str, std::get(tuple)); } }; template struct TupleToString { static inline std::size_t precomputeSize(const Tuple &tuple) { return computeTupleElementSize(std::get<0>(tuple)); } static inline void append(const Tuple &tuple, StringType &str) { Helper::append(str, std::get<0>(tuple)); } }; } // namespace Helper /// \endcond /*! * \brief Concatenates all strings hold by the specified \a tuple. */ template inline StringType tupleToString(const std::tuple &tuple) { StringType res; res.reserve(Helper::TupleToString::precomputeSize(tuple)); Helper::TupleToString::append(tuple, res); return res; } template inline StringType argsToString(Args &&... args) { return tupleToString(std::make_tuple(std::forward(args)...)); } /*! * \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3. */ template constexpr auto operator%(const Tuple &lhs, const std::string &rhs) -> decltype(std::tuple_cat(lhs, std::make_tuple(&rhs))) { return std::tuple_cat(lhs, std::make_tuple(&rhs)); } /*! * \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3. */ template constexpr auto operator%(const Tuple &lhs, const char *rhs) -> decltype(std::tuple_cat(lhs, std::make_tuple(rhs))) { return std::tuple_cat(lhs, std::make_tuple(rhs)); } /*! * \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3. */ template > * = nullptr> constexpr auto operator%(const Tuple &lhs, IntegralType rhs) -> decltype(std::tuple_cat(lhs, std::make_tuple(rhs))) { return std::tuple_cat(lhs, std::make_tuple(rhs)); } /*! * \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3. */ constexpr auto operator%(const std::string &lhs, const std::string &rhs) -> decltype(std::make_tuple(&lhs, &rhs)) { return std::make_tuple(&lhs, &rhs); } /*! * \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3. */ constexpr auto operator%(const char *lhs, const std::string &rhs) -> decltype(std::make_tuple(lhs, &rhs)) { return std::make_tuple(lhs, &rhs); } /*! * \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3. */ constexpr auto operator%(const std::string &lhs, const char *rhs) -> decltype(std::make_tuple(&lhs, rhs)) { return std::make_tuple(&lhs, rhs); } /*! * \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3. */ constexpr auto operator%(const std::string &lhs, char rhs) -> decltype(std::make_tuple(&lhs, rhs)) { return std::make_tuple(&lhs, rhs); } /*! * \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3. */ constexpr auto operator%(char lhs, const std::string &rhs) -> decltype(std::make_tuple(lhs, &rhs)) { return std::make_tuple(lhs, &rhs); } /*! * \brief Allows construction of final string from previously constructed string-tuple and trailing string via +-operator. * * This is meant to be used for fast string building without multiple heap allocation, eg. * * ``` * printVelocity("velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)")); * ``` */ template > * = nullptr> inline std::string operator+(const Tuple &lhs, const std::string &rhs) { return tupleToString(std::tuple_cat(lhs, std::make_tuple(&rhs))); } /*! * \brief Allows construction of final string from previously constructed string-tuple and trailing string via +-operator. * * This is meant to be used for fast string building without multiple heap allocation, eg. * * ``` * printVelocity("velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)")); * ``` */ template > * = nullptr> inline std::string operator+(const Tuple &lhs, const char *rhs) { return tupleToString(std::tuple_cat(lhs, std::make_tuple(rhs))); } /*! * \brief Allows construction of final string from previously constructed string-tuple and trailing char via +-operator. * * This is meant to be used for fast string building without multiple heap allocation, eg. * * ``` * printVelocity("velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)")); * ``` */ template , std::is_integral> * = nullptr> inline std::string operator+(const Tuple &lhs, IntegralType rhs) { return tupleToString(std::tuple_cat(lhs, std::make_tuple(rhs))); } } // namespace CppUtilities #endif // CONVERSION_UTILITIES_STRINGBUILDER_H