#ifndef CONVERSION_UTILITIES_STRINGBUILDER_H #define CONVERSION_UTILITIES_STRINGBUILDER_H #include "../misc/traits.h" #include "./stringconversion.h" #include #include namespace ConversionUtilities { /// \cond namespace Helper { template >...> std::size_t computeTupleElementSize(const StringType *str) { return str->size(); } template >...> std::size_t computeTupleElementSize(const StringType &str) { return str.size(); } template >...> std::size_t computeTupleElementSize(const CharType *str) { return std::char_traits::length(str); } template >...> constexpr std::size_t computeTupleElementSize(CharType) { return 1; } template >, std::is_integral, std::is_unsigned>...> 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>...> 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 >...> void append(StringType &target, const StringType *str) { target.append(*str); } template >...> void append(StringType &target, const StringType &str) { target.append(str); } template >...> void append(StringType &target, const CharType *str) { target.append(str); } template >...> void append(StringType &target, CharType c) { target += c; } template >, std::is_integral, std::is_unsigned>...> 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>...> 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 std::size_t precomputeSize(const Tuple &tuple) { return TupleToString::precomputeSize(tuple) + computeTupleElementSize(std::get(tuple)); } static void append(const Tuple &tuple, StringType &str) { TupleToString::append(tuple, str); Helper::append(str, std::get(tuple)); } }; template struct TupleToString { static std::size_t precomputeSize(const Tuple &tuple) { return computeTupleElementSize(std::get<0>(tuple)); } static 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 StringType tupleToString(const std::tuple &tuple) { StringType res; res.reserve(Helper::TupleToString::precomputeSize(tuple)); Helper::TupleToString::append(tuple, res); return res; } template constexpr StringType argsToString(Args &&... args) { return tupleToString(std::make_tuple(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 >...> 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 >...> 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 >...> 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>...> inline std::string operator+(const Tuple &lhs, IntegralType rhs) { return tupleToString(std::tuple_cat(lhs, std::make_tuple(rhs))); } } // namespace ConversionUtilities #endif // CONVERSION_UTILITIES_STRINGBUILDER_H