diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index 4407b46a0e..1ac892085e 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -23,6 +23,54 @@ void fmt_class_string>::format(std::string& } } +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + const auto& _arg = get_object(arg); + + if (_arg.data && _arg.size) + { + // Precomputed tail sizes if input data is not multiple of 8 + static constexpr u8 s_tail[8] = {0, 2, 3, 5, 6, 7, 9, 10}; + + // Get full output size + const std::size_t out_size = _arg.size / 8 * 11 + s_tail[_arg.size % 8]; + + out.resize(out.size() + out_size); + + const auto ptr = &out.front() + (out.size() - out_size); + + // Each 8 bytes of input data produce 11 bytes of base57 output + for (std::size_t i = 0, p = 0; i < _arg.size; i += 8, p += 11) + { + // Load up to 8 bytes + be_t be_value; + + if (_arg.size - i < sizeof(be_value)) + { + std::memset(&be_value, 0, sizeof(be_value)); + std::memcpy(&be_value, _arg.data + i, _arg.size - i); + } + else + { + std::memcpy(&be_value, _arg.data + i, sizeof(be_value)); + } + + u64 value = be_value; + + for (int j = 10; j >= 0; j--) + { + if (p + j < out_size) + { + ptr[p + j] = "0123456789ACEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"[value % 57]; + } + + value /= 57; + } + } + } +} + void fmt_class_string::format(std::string& out, u64 arg) { if (arg) @@ -31,7 +79,7 @@ void fmt_class_string::format(std::string& out, u64 arg) } else { - out += "(NULL)"; + out += "(NULL)"; } } diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index 6e2878467c..17c3640238 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -250,6 +250,26 @@ using fmt_args_t = const u64(&&)[sizeof...(Args) + 1]; namespace fmt { + // Base-57 format helper + struct base57 + { + const uchar* data; + std::size_t size; + + template + base57(const T& arg) + : data(reinterpret_cast(&arg)) + , size(sizeof(T)) + { + } + + base57(const uchar* data, std::size_t size) + : data(data) + , size(size) + { + } + }; + template SAFE_BUFFERS FORCE_INLINE const fmt_type_info* get_type_info() {