gt22 icon

Untitled

gt22 | PRO | 07/04/20 01:10:34 PM UTC | 0 ⭐ | 1807 👁️ | Never ⏰ | []
C++ |

4.23 KB

|

None

|

0 👍

/

0 👎

#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

Comments