feat(baseN): encode

This commit is contained in:
2024-09-18 21:38:06 +03:00
parent 5a42cf1011
commit 61c0ae3a72
2 changed files with 68 additions and 132 deletions

View File

@ -25,129 +25,63 @@ namespace baseN
{
throw std::overflow_error("baseN::sizeEncoded: overflow");
}
return data.size() * log256 / std::log(base) + 1;
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, uint8_t base, const char *digits, uint64_t enc_size) noexcept
// {
// if (data_size == 0)
// {
// return;
// }
// char res_str[enc_size];
// uint8_t div_buf[data_size];
// std::copy(data, data + data_size, div_buf);
// int64_t
// zero_count = 0,
// idx_div = 0,
// idx_quo = 0,
// idx_quo_last = data_size,
// idx_str = enc_size - 1;
// uint16_t div = data[idx_div++];
void encode(const uint8_t *data, uint64_t data_size, char *str, uint64_t str_size, uint8_t base, const char *digits)
{
std::vector<uint8_t> dv(std::find_if(data, data + data_size, [](uint8_t item)
{ return item != 0; }),
data + data_size);
if (dv.size() == 0)
{
return;
}
std::span<char> 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 (zero_count < (int64_t)data_size && data[zero_count] == 0)
// {
// zero_count++;
// }
// while (idx_quo_last > 1 || div_buf[0] > base)
// {
// if (div < base)
// {
// div <<= 8;
// div += div_buf[idx_div++];
// }
// div_buf[idx_quo++] = div / base;
// div %= base;
// while (idx_div < idx_quo_last)
// {
// div <<= 8;
// div += div_buf[idx_div++];
// div_buf[idx_quo++] = div / base;
// div %= base;
// }
// idx_quo_last = idx_quo;
// idx_quo = 0;
// idx_div = 0;
// res_str[idx_str--] = digits[div];
// div = div_buf[idx_div++];
// }
// res_str[idx_str--] = digits[div];
// while (zero_count > 0 && idx_str >= 0)
// {
// res_str[idx_str--] = digits[0];
// zero_count--;
// }
// while (idx_str >= 0)
// {
// res_str[idx_str--] = ' ';
// }
// std::copy(res_str, res_str + enc_size, str);
// }
// std::string encode(std::span<const uint8_t> data, uint8_t base, const char *digits, uint64_t enc_size) noexcept
// {
// std::string str(enc_size, ' ');
// baseN::encode(data.data(), data.size(), str.data(), base, digits, enc_size);
// str.erase(str.begin(), std::find_if(
// str.begin(), str.end(), [](char ch)
// { return ch != ' '; }));
// return str;
// }
// std::string encode(std::span<const uint8_t> data, uint8_t base, const char *digits) noexcept
// {
// return baseN::encode(data, base, digits, data.size() * std::log(256) / std::log(base) + 1);
// }
// void decode(const char *str, uint8_t *data, uint64_t data_size, uint8_t base, const char *digits, const int8_t *map, uint64_t dec_size)
// {
// if (str[0] == '\0')
// {
// return;
// }
// if (!baseN::isValid(str, map))
// {
// throw std::logic_error("baseN::decode: out of digits map");
// }
// uint8_t res_data[dec_size];
// uint64_t idx_str = 0;
// int64_t
// zero_count = 0,
// idx_quo = dec_size - 1,
// idx_quo_last = dec_size - 2;
// uint16_t div;
// while (str[zero_count] != '\0' && str[zero_count] == digits[0])
// {
// zero_count++;
// }
// res_data[idx_quo] = map[(int8_t)str[idx_str++]];
// while (str[idx_str] != '\0')
// {
// div = map[(int8_t)str[idx_str++]];
// while (idx_quo > idx_quo_last && idx_quo > 0)
// {
// div += res_data[idx_quo] * base;
// res_data[idx_quo--] = div;
// div >>= 8;
// }
// res_data[idx_quo--] = div;
// idx_quo_last = idx_quo;
// idx_quo = dec_size - 1;
// }
// std::copy(res_data, res_data + std::min(dec_size, data_size), data);
// }
// std::vector<uint8_t> decode(std::string_view str, uint8_t base, const char *digits, const int8_t *map, uint64_t dec_size)
// {
// std::vector<uint8_t> data(dec_size);
// baseN::decode(str.data(), data.data(), data.size(), base, digits, map, dec_size);
// data.erase(data.begin(), std::find_if(
// data.begin(), data.end(), [](uint8_t byte)
// { return byte != 0; }));
// return data;
// }
// std::vector<uint8_t> decode(std::string_view str, uint8_t base, const char *digits, const int8_t *map)
// {
// return baseN::decode(str, base, digits, map, str.size() * std::log(base) / std::log(256) + 1);
// }
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<const uint8_t> 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;
}
}

View File

@ -32,19 +32,21 @@ TEST(baseN, isValid)
EXPECT_EQ(true, isValid("123", b58map));
EXPECT_EQ(false, isValid("@#$", b58map));
}
// TEST(baseN, encode)
// {
// EXPECT_EQ("Ky", encode(hex::decode("044c"), 58, b58digits));
// EXPECT_EQ("KyK", encode(hex::decode("f94a"), 58, b58digits));
// EXPECT_EQ("KyKX", encode(hex::decode("387ae2"), 58, b58digits));
// EXPECT_EQ("KyKXa", encode(hex::decode("0ccbd755"), 58, b58digits));
// EXPECT_EQ("KyKXaa", encode(hex::decode("02e62ec963"), 58, b58digits));
// }
// TEST(baseN, encode_1e3)
// {
// std::vector<uint8_t> data(1e3);
// encode(data, 58, b58digits, data.size() * 138 / 100 + 1);
// }
TEST(baseN, encode)
{
EXPECT_EQ("", encode(hex::decode(""), 58, b58digits));
EXPECT_EQ("Ky", encode(hex::decode("044c"), 58, b58digits));
EXPECT_EQ("KyK", encode(hex::decode("f94a"), 58, b58digits));
EXPECT_EQ("KyKX", encode(hex::decode("387ae2"), 58, b58digits));
EXPECT_EQ("KyKXa", encode(hex::decode("0ccbd755"), 58, b58digits));
EXPECT_EQ("KyKXaa", encode(hex::decode("02e62ec963"), 58, b58digits));
}
TEST(baseN, encode_1e3)
{
std::vector<uint8_t> data(1e3);
std::fill(data.begin(), data.end(), 1);
encode(data, 58, b58digits);
}
// TEST(baseN, decode)
// {
// EXPECT_EQ(hex::encode(decode("Ky", 58, b58digits, b58map)), "044c");