Skip to content

Commit

Permalink
Adding to_chars fallback (#117)
Browse files Browse the repository at this point in the history
* adding `to_chars` fallback

* tweak suggested by @thinlang

* fixing test
  • Loading branch information
fosterbrereton authored May 24, 2024
1 parent 2e788b8 commit 49c5207
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 3 deletions.
22 changes: 22 additions & 0 deletions adobe/string/to_string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@

#include <adobe/cassert.hpp>

// `to_chars` floating-point support was added to macOS 13.3. Some ASL
// clients have deployment targets that go back earlier than that.
// In such case, `adobe::to_string` falls back to an implementation
// that relies on the output-iterator variant of `adobe::to_string`,
// pivoting on precise/short based on the exponent of the number
// being serialized. This gets us close to the output of `to_chars`
// without overcomplicating the fallback.
#if defined(_LIBCPP_AVAILABILITY_HAS_NO_TO_CHARS_FLOATING_POINT)
#define ADOBE_HAS_TO_CHARS_FP() 0
#else
#define ADOBE_HAS_TO_CHARS_FP() 1
#endif

/**************************************************************************************************/

namespace adobe {
Expand Down Expand Up @@ -161,6 +174,7 @@ inline std::string to_string(double x) {
if (x == std::numeric_limits<double>::infinity()) return "Infinity";
if (x == -std::numeric_limits<double>::infinity()) return "-Infinity";

#if ADOBE_HAS_TO_CHARS_FP()
std::array<char, 64> str;
char* first = &str[0];
char* last = first + str.size();
Expand All @@ -169,6 +183,14 @@ inline std::string to_string(double x) {
return tcr.ec == std::errc() ?
std::string(first, tcr.ptr - first) :
std::make_error_code(tcr.ec).message();
#else
std::string result;
double f3;
double f2 = std::modf(x, &f3);
const auto use_precise = std::abs(std::log10(f2)) > 7;
to_string(x, std::back_inserter(result), use_precise);
return result;
#endif
}

/**************************************************************************************************/
Expand Down
18 changes: 15 additions & 3 deletions test/to_string/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,17 @@ std::string asl_to_string(const test_t& test) {
}

std::string std_to_chars(const test_t& test) {
#if ADOBE_HAS_TO_CHARS_FP()
std::array<char, 64> str;
if (auto [ptr, ec] = std::to_chars(str.data(), str.data() + str.size(), test.value_m); ec == std::errc()) {
const auto sz = ptr - str.data();
return std::string(str.data(), sz);
} else {
return std::make_error_code(ec).message();
}
#else
return "unavailable";
#endif
}

std::string any_regular_serialization(const test_t& test) {
Expand Down Expand Up @@ -147,15 +151,23 @@ std::size_t test_suite(std::string (*convert)(const test_t& test), const char* l
/******************************************************************************/

BOOST_AUTO_TEST_CASE(serialization_test_suite) {
#if ADOBE_HAS_TO_CHARS_FP()
constexpr auto to_string_match_count_k = 10;
constexpr auto to_chars_match_count_k = 6;
#else
constexpr auto to_string_match_count_k = 9;
constexpr auto to_chars_match_count_k = 0;
#endif

BOOST_CHECK_EQUAL(test_suite(&asl_to_string_v1<true>, "adobe::to_string (precise)"), 3);

BOOST_CHECK_EQUAL(test_suite(&asl_to_string_v1<false>, "adobe::to_string (short)"), 2);

BOOST_CHECK_EQUAL(test_suite(&asl_to_string, "adobe::to_string (v2)"), 10);
BOOST_CHECK_EQUAL(test_suite(&asl_to_string, "adobe::to_string (v2)"), to_string_match_count_k);

BOOST_CHECK_EQUAL(test_suite(&std_to_chars, "std::to_chars"), 6);
BOOST_CHECK_EQUAL(test_suite(&std_to_chars, "std::to_chars"), to_chars_match_count_k);

BOOST_CHECK_EQUAL(test_suite(&any_regular_serialization, "adobe::any_regular_t"), 10);
BOOST_CHECK_EQUAL(test_suite(&any_regular_serialization, "adobe::any_regular_t"), to_string_match_count_k);
}

/******************************************************************************/

0 comments on commit 49c5207

Please sign in to comment.