#include #include #include #include #include #include #include #include #include #include #include namespace std { inline to_chars_result to_chars(char* first, char* last, boost::float128_type value, chars_format format, int precision) noexcept { return to_chars(first, last, float128_t(value), format, precision); } inline to_chars_result to_chars(char* first, char* last, boost::float128_type value, chars_format format) noexcept { return to_chars(first, last, float128_t(value), format); } inline to_chars_result to_chars(char* first, char* last, boost::float128_type value) noexcept { return to_chars(first, last, float128_t(value)); } } // std namespace test { enum class library { boost, std }; constexpr std::string_view format_string(const std::chars_format format) noexcept { switch (format) { case std::chars_format::scientific: return "scientific"; case std::chars_format::fixed: return "fixed"; case std::chars_format::hex: return "hex"; default: return "general"; } } template struct to_chars_test { static_assert(ArraySize > ResultSize); using buffer_type = std::array; buffer_type buffer; std::to_chars_result result; inline static constexpr boost::charconv::chars_format cvt_format(const std::chars_format format) noexcept { switch (format) { case std::chars_format::scientific: return boost::charconv::chars_format::scientific; case std::chars_format::fixed: return boost::charconv::chars_format::fixed; case std::chars_format::hex: return boost::charconv::chars_format::hex; default: return boost::charconv::chars_format::general; } } inline static constexpr std::to_chars_result cvt_result(const boost::charconv::to_chars_result& result) noexcept { return {result.ptr, result.ec}; } inline constexpr auto begin() const noexcept { return buffer.data(); } inline constexpr auto end() const noexcept { return buffer.data()+ResultSize; } inline constexpr auto begin() noexcept { return buffer.data(); } inline constexpr auto end() noexcept { return buffer.data()+ResultSize; } inline std::string dump_string(const size_t size) const { auto is_float_char = [](const char value) constexpr noexcept -> bool { return (value=='+' || value=='-' || value=='.') ? true : (value>='0' && value<='9') ? true : (value>='a' && value<='f') ? true : false; }; std::string result{}; result.reserve(ResultSize); for (size_t i=0; i void to_chars(const Type value, const std::chars_format format, const int precision) { reset(); if constexpr (Lib == library::boost) result = cvt_result(boost::charconv::to_chars(begin(), end(), value, cvt_format(format), precision)); else result = std::to_chars(begin(), end(), value, format, precision); } template void to_chars(const Type value, const std::chars_format format) { reset(); if constexpr (Lib == library::boost) result = cvt_result(boost::charconv::to_chars(begin(), end(), value, cvt_format(format))); else result = std::to_chars(begin(), end(), value, format); } template void to_chars(const Type value) { reset(); if constexpr (Lib == library::boost) result = cvt_result(boost::charconv::to_chars(begin(), end(), value)); else result = std::to_chars(begin(), end(), value); } template constexpr bool operator==(const to_chars_test& other) const noexcept { return result.ec==other.result.ec && buffer==other.buffer; } template friend std::basic_ostream& operator<<(std::basic_ostream& stream, const to_chars_test& test) { auto out_buffer_overflow = [&]() { stream << "buffer_overflow:" << test.is_buffer_overflow() << '\t'; }; auto out_error = [&]() { stream << int(test.result.ec) << ':' << std::make_error_code(test.result.ec).message() << '\t'; }; auto out_result = [&](const size_t size) { stream << size << ':' << test.dump_string(size).c_str() << '\t'; }; stream << ((Lib == library::boost) ? "boost\t" : "std\t"); out_buffer_overflow(); out_error(); out_result(test.size_result()); out_result(test.size_written()); return stream; } }; template void show(const Type value, const std::chars_format format, const int precision) { using B = to_chars_test; using S = to_chars_test; B b; S s; b.to_chars(value, format, precision); s.to_chars(value, format, precision); std::cout << boost::core::type_name() << ':' << format_string(format) << ':' << precision << " -> " << (b==s) << '\n'; std::cout << b << '\n'; std::cout << s << '\n'; std::cout << "\n\n"; } template void show(const Type value, const std::chars_format format) { using B = to_chars_test; using S = to_chars_test; B b; S s; b.to_chars(value, format); s.to_chars(value, format); std::cout << boost::core::type_name() << ':' << format_string(format) << " -> " << (b==s) << '\n'; std::cout << b << '\n'; std::cout << s << '\n'; std::cout << "\n\n"; } template void show(const Type value) { using B = to_chars_test; using S = to_chars_test; B b; S s; b.to_chars(value); s.to_chars(value); std::cout << boost::core::type_name() << " -> " << (b==s) << '\n'; std::cout << b << '\n'; std::cout << s << '\n'; std::cout << "\n\n"; } } // test int main() { constexpr std::chars_format format = std::chars_format::fixed; constexpr std::float128_t value = 3331.519894481067353f128; constexpr int precision = 17; constexpr size_t array_size = 8192; constexpr size_t result_size = 1024; std::cout << std::boolalpha; test::show(value, format, precision); test::show(boost::float128_t(value), format, precision); test::show(boost::float80_t(value), format, precision); test::show(boost::float64_t(value), format, precision); test::show(boost::float32_t(value), format, precision); test::show(std::float16_t(value), format, precision); test::show(std::bfloat16_t(value), format, precision); test::show(value, format); test::show(boost::float128_t(value), format); test::show(boost::float80_t(value), format); test::show(boost::float64_t(value), format); test::show(boost::float32_t(value), format); test::show(std::float16_t(value), format); test::show(std::bfloat16_t(value), format); test::show(value); test::show(boost::float128_t(value)); test::show(boost::float80_t(value)); test::show(boost::float64_t(value)); test::show(boost::float32_t(value)); test::show(std::float16_t(value)); test::show(std::bfloat16_t(value)); return EXIT_SUCCESS; }