Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <cstddef> // std::size_t
- #include <string> // std::string
- #include <charconv> // std::to_chars
- #include <cmath> // std::ceil
- #include <iterator>
- #include <type_traits>
- #include <cassert>
- #if __cplusplus < 201703L
- #error At least C++17 is required
- #endif
- namespace format {
- template<typename, typename = void>
- struct FormatHelper;
- namespace validator {
- template<typename T, size_t = sizeof(FormatHelper<T>)>
- constexpr bool has_format_helper(std::nullptr_t) {
- return true;
- }
- template<typename T>
- constexpr bool has_format_helper(...) {
- return false;
- }
- template<typename T>
- constexpr bool has_format_helper_v = has_format_helper<T>(nullptr);
- template<typename T, typename = std::enable_if_t<
- std::is_same_v<std::string,
- decltype(std::declval<const T&>().format())>>>
- constexpr bool has_format(std::nullptr_t) {
- return true;
- }
- template<typename T>
- constexpr bool has_format(...) {
- return false;
- }
- template<typename T>
- constexpr bool has_format_v = has_format<T>(nullptr);
- }
- template<>
- struct FormatHelper<bool> {
- 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<typename T>
- struct FormatHelper<std::vector<T>, std::enable_if_t<validator::has_format_helper_v<T>>> {
- explicit FormatHelper(const std::vector<T>& 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<T>& vec;
- std::vector<FormatHelper<T>> fmt;
- };
- template<typename T>
- struct FormatHelper<T, std::enable_if_t<std::is_integral_v<T>>> {
- 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<T>::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<typename T>
- struct FormatHelper<T, std::enable_if_t<validator::has_format_v<T>>> {
- 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<typename T>
- std::enable_if_t<validator::has_format_helper_v<T>, std::string> make_string(const T& value) {
- FormatHelper<T> helper(value); // Explicit!
- std::string formatted;
- formatted.reserve(helper.estimate_size());
- helper.append_to(formatted);
- formatted.shrink_to_fit();
- return formatted;
- }
- } // namespace format
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement