#include // std::size_t #include // std::string #include // std::to_chars #include // std::ceil #include #include #include #if __cplusplus < 201703L #error At least C++17 is required #endif namespace format { template struct FormatHelper; namespace validator { template)> constexpr bool has_format_helper(std::nullptr_t) { return true; } template constexpr bool has_format_helper(...) { return false; } template constexpr bool has_format_helper_v = has_format_helper(nullptr); template().format())>>> constexpr bool has_format(std::nullptr_t) { return true; } template constexpr bool has_format(...) { return false; } template constexpr bool has_format_v = has_format(nullptr); } template<> struct FormatHelper { explicit FormatHelper(bool b) : val(b) {} std::size_t estimate_size() const { return val ? 4 : 5; } void append_to(std::string& s) const { s += val ? "true" : "false"; } private: bool val; }; template struct FormatHelper, std::enable_if_t>> { explicit FormatHelper(const std::vector& val) : vec(val) { fmt.reserve(val.size()); for (const auto& v : val) { fmt.emplace_back(v); } } std::size_t estimate_size() const { std::size_t s = 2; // "{}" for (std::size_t i = 0; i < vec.size(); i++) { s += fmt[i].estimate_size(); if (i != vec.size() - 1) { s += 2; // ", " } } return s; } void append_to(std::string& s) const { s += "{"; for (std::size_t i = 0; i < vec.size(); i++) { fmt[i].append_to(s); if (i != vec.size() - 1) { s += ", "; } } s += "}"; } private: const std::vector& vec; std::vector> fmt; }; template struct FormatHelper>> { constexpr static int BASE = 10; // +1 for potential '-' and +1 because digits10 will be rounded down constexpr static size_t BUF_SIZE = 2 + std::numeric_limits::digits10; explicit FormatHelper(const T& val) : val(val) {} std::size_t estimate_size() const { return BUF_SIZE; } void append_to(std::string& s) const { char buf[BUF_SIZE]; auto [end, ec] = std::to_chars(std::begin(buf), std::end(buf), val, BASE); assert(ec == std::errc()); s += std::string_view(buf, end - buf); } private: const T& val; }; template struct FormatHelper>> { constexpr static std::size_t DEFAULT_SIZE = 10; explicit FormatHelper(const T& val) : val(val) {} std::size_t estimate_size() const { return DEFAULT_SIZE; } void append_to(std::string& s) const { s += val.format(); } private: const T& val; }; template std::enable_if_t, std::string> make_string(const T& value) { FormatHelper helper(value); // Explicit! std::string formatted; formatted.reserve(helper.estimate_size()); helper.append_to(formatted); formatted.shrink_to_fit(); return formatted; } } // namespace format