#include #include #include #include #include static constexpr auto log256 = std::log(256); namespace baseN { bool isValid(const char *str, uint64_t str_size, const int8_t *map) noexcept { std::string_view sv(str, str_size); return std::all_of(sv.begin(), sv.end(), [map](char ch) { return map[(int8_t)ch] != -1; }); } bool isValid(std::string_view str, const int8_t *map) noexcept { return baseN::isValid(str.data(), str.size(), map); } uint64_t sizeEncoded(std::span data, uint8_t base) { if (data.size() > std::numeric_limits::max() / log256) { throw std::overflow_error("baseN::sizeEncoded: overflow"); } return data.size() * log256 / std::log(base) + 1; } uint64_t sizeDecoded(std::string_view str, uint8_t base) noexcept { return str.size() * std::log(base) / log256 + 1; } void encode(const uint8_t *data, uint64_t data_size, char *str, uint64_t str_size, uint8_t base, const char *digits) { std::vector dv(std::find_if(data, data + data_size, [](uint8_t item) { return item != 0; }), data + data_size); if (dv.size() == 0) { return; } std::span sv(str, str_size); auto sv_it = sv.rbegin(); auto dv_it = dv.begin(); auto quo_it = dv.begin(); auto quo_it_last = dv.end(); uint16_t div = *dv_it++; while ((dv[0] > base || quo_it_last > dv.begin() + 1) && sv_it < sv.rend() - 1) { if (div < base) { div <<= 8; div += *dv_it++; } *quo_it++ = div / base; div %= base; while (dv_it < quo_it_last) { div <<= 8; div += *dv_it++; *quo_it++ = div / base; div %= base; } quo_it_last = quo_it; dv_it = dv.begin(); quo_it = dv.begin(); *sv_it++ = digits[div]; div = *dv_it++; } *sv_it++ = digits[div]; for (uint64_t i = 0; i < data_size - dv.size() && sv_it < sv.rend(); i++) { *sv_it++ = digits[0]; } } std::string encode(std::span data, uint8_t base, const char *digits) noexcept { std::string str(baseN::sizeEncoded(data, base), ' '); baseN::encode(data.data(), data.size(), str.data(), str.size(), base, digits); str.erase(str.begin(), std::find_if( str.begin(), str.end(), [](char ch) { return ch != ' '; })); return str; } }