Skip to content

Commit

Permalink
cherry pick append_fast pointer implementation
Browse files Browse the repository at this point in the history
constexpr append changes to take into account the base of string conversion
so that pointers can be printed out in hex format and with padding zeros.
  • Loading branch information
cschreib authored and CrustyAuklet committed Apr 28, 2024
1 parent f389a8c commit cb6e74e
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 30 deletions.
36 changes: 21 additions & 15 deletions include/snitch/snitch_append.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,47 +45,53 @@ SNITCH_EXPORT [[nodiscard]] bool append_fast(small_string_span ss, double f) noe
return could_fit;
}

template<large_uint_t Base = 10u>
[[nodiscard]] constexpr std::size_t num_digits(large_uint_t x) noexcept {
return x >= 10u ? 1u + num_digits(x / 10u) : 1u;
return x >= Base ? 1u + num_digits<Base>(x / Base) : 1u;
}

template<large_int_t Base = 10>
[[nodiscard]] constexpr std::size_t num_digits(large_int_t x) noexcept {
return x >= 10 ? 1u + num_digits(x / 10) : x <= -10 ? 1u + num_digits(x / 10) : x > 0 ? 1u : 2u;
return (x >= Base || x <= -Base) ? 1u + num_digits<Base>(x / Base) : x > 0 ? 1u : 2u;
}

constexpr std::array<char, 10> digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
constexpr std::array<char, 16> digits = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

constexpr std::size_t max_uint_length = num_digits(std::numeric_limits<large_uint_t>::max());
constexpr std::size_t max_int_length = max_uint_length + 1;

template<large_uint_t Base = 10u>
[[nodiscard]] constexpr bool append_constexpr(small_string_span ss, large_uint_t i) noexcept {
if (i != 0u) {
small_string<max_uint_length> tmp;
tmp.resize(num_digits(i));
tmp.resize(num_digits<Base>(i));
std::size_t k = 1;
for (large_uint_t j = i; j != 0u; j /= 10u, ++k) {
tmp[tmp.size() - k] = digits[j % 10u];
for (large_uint_t j = i; j != 0u; j /= Base, ++k) {
tmp[tmp.size() - k] = digits[j % Base];
}
return append_constexpr(ss, tmp);
} else {
return append_constexpr(ss, "0");
}
}

template<large_int_t Base = 10>
[[nodiscard]] constexpr bool append_constexpr(small_string_span ss, large_int_t i) noexcept {
if (i > 0) {
small_string<max_int_length> tmp;
tmp.resize(num_digits(i));
tmp.resize(num_digits<Base>(i));
std::size_t k = 1;
for (large_int_t j = i; j != 0; j /= 10, ++k) {
tmp[tmp.size() - k] = digits[j % 10];
for (large_int_t j = i; j != 0; j /= Base, ++k) {
tmp[tmp.size() - k] = digits[j % Base];
}
return append_constexpr(ss, tmp);
} else if (i < 0) {
small_string<max_int_length> tmp;
tmp.resize(num_digits(i));
tmp.resize(num_digits<Base>(i));
std::size_t k = 1;
for (large_int_t j = i; j != 0; j /= 10, ++k) {
tmp[tmp.size() - k] = digits[-(j % 10)];
for (large_int_t j = i; j != 0; j /= Base, ++k) {
tmp[tmp.size() - k] = digits[-(j % Base)];
}
tmp[0] = '-';
return append_constexpr(ss, tmp);
Expand All @@ -98,15 +104,15 @@ constexpr std::size_t max_int_length = max_uint_length + 1;
constexpr std::size_t min_exp_digits = 2u;

[[nodiscard]] constexpr std::size_t num_exp_digits(fixed_exp_t x) noexcept {
const std::size_t exp_digits = num_digits(static_cast<large_uint_t>(x > 0 ? x : -x));
const std::size_t exp_digits = num_digits<10>(static_cast<large_uint_t>(x > 0 ? x : -x));
return exp_digits < min_exp_digits ? min_exp_digits : exp_digits;
}

[[nodiscard]] constexpr std::size_t num_digits(const signed_fixed_data& x) noexcept {
// +1 for fractional separator '.'
// +1 for exponent separator 'e'
// +1 for exponent sign
return num_digits(static_cast<large_uint_t>(x.digits)) + num_exp_digits(x.exponent) +
return num_digits<10>(static_cast<large_uint_t>(x.digits)) + num_exp_digits(x.exponent) +
(x.sign ? 1u : 0u) + 3u;
}

Expand Down Expand Up @@ -135,7 +141,7 @@ set_precision(signed_fixed_data fd, std::size_t p) noexcept {
// and round-half-to-even is the default rounding mode for IEEE 754 floats. We don't follow
// the current rounding mode, but we can at least follow the default.

std::size_t base_digits = num_digits(static_cast<large_uint_t>(fd.digits));
std::size_t base_digits = num_digits<10>(static_cast<large_uint_t>(fd.digits));

bool only_zero = true;
while (base_digits > p) {
Expand Down
36 changes: 23 additions & 13 deletions src/snitch_append.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace snitch::impl {
namespace {
using snitch::small_string_span;
using namespace std::literals;

#if SNITCH_APPEND_TO_CHARS
// libstdc++ version 11 or greater
Expand Down Expand Up @@ -68,25 +69,16 @@ bool append_to(small_string_span ss, T value) noexcept {
ss.grow(end - ss.end());
return true;
}

bool append_to(small_string_span ss, const void* ptr) noexcept {
return append(ss, "0x") && append_to<16>(ss, reinterpret_cast<std::uintptr_t>(ptr));
}

#else
template <floating_point T>
template<floating_point T>
bool append_to(small_string_span ss, T value) noexcept {
return append_constexpr(ss, value);
}

template <large_int_t Base = 10, integral T>
template<large_int_t Base = 10, integral T>
bool append_to(small_string_span ss, T value) noexcept {
return append_constexpr(ss, value);
}

bool append_to(small_string_span ss, const void* value) noexcept {
return append_constexpr(ss, value);
}
#endif
} // namespace

Expand All @@ -108,9 +100,27 @@ bool append_fast(small_string_span ss, std::string_view str) noexcept {
bool append_fast(small_string_span ss, const void* ptr) noexcept {
if (ptr == nullptr) {
return append(ss, nullptr);
} else {
return append(ss, "0x") && append_to(ss, ptr);
}

if (!append_fast(ss, "0x"sv)) {
return false;

Check warning on line 106 in src/snitch_append.cpp

View check run for this annotation

Codecov / codecov/patch

src/snitch_append.cpp#L106

Added line #L106 was not covered by tests
}

const auto int_ptr = reinterpret_cast<std::uintptr_t>(ptr);

// Pad with zeros.
constexpr std::size_t max_digits = 2 * sizeof(void*);
std::size_t padding = max_digits - num_digits<16>(int_ptr);
while (padding > 0) {
constexpr std::string_view zeroes = "0000000000000000";
const std::size_t batch = std::min(zeroes.size(), padding);
if (!append_fast(ss, zeroes.substr(0, batch))) {
return false;
}

padding -= batch;
}
return append_to<16>(ss, int_ptr);
}

bool append_fast(small_string_span ss, large_uint_t i) noexcept {
Expand Down
8 changes: 6 additions & 2 deletions tests/runtime_tests/string_utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,10 @@ TEST_CASE("append ints", "[utility]") {
}

TEST_CASE("append floats", "[utility]") {
using ae = append_test::append_expected;
using ae = append_test::append_expected;
#if !SNITCH_CONSTEXPR_FLOAT_USE_BITCAST
using aed = append_test::append_expected_diff;
#endif

SECTION("floats do fit") {
constexpr auto a = [](const auto& value) constexpr {
Expand Down Expand Up @@ -450,8 +452,10 @@ TEST_CASE("append floats", "[utility]") {
}

TEST_CASE("append doubles", "[utility]") {
using ae = append_test::append_expected;
using ae = append_test::append_expected;
#if !SNITCH_CONSTEXPR_FLOAT_USE_BITCAST
using aed = append_test::append_expected_diff;
#endif

SECTION("doubles do fit") {
constexpr auto a = [](const auto& value) constexpr {
Expand Down

0 comments on commit cb6e74e

Please sign in to comment.