feat(baseN): sizeEncoded/Decoded

This commit is contained in:
2024-09-18 16:24:41 +03:00
parent 7c9e77d1aa
commit 5a42cf1011
5 changed files with 153 additions and 137 deletions

View File

@ -11,7 +11,7 @@ namespace base64
bool isValid(std::string_view str) noexcept; bool isValid(std::string_view str) noexcept;
uint64_t sizeEncoded(std::span<const uint8_t> data); uint64_t sizeEncoded(std::span<const uint8_t> data);
uint64_t sizeDecoded(std::string_view str_size) noexcept; uint64_t sizeDecoded(std::string_view str) noexcept;
void encode(const uint8_t *data, uint64_t data_size, char *str, uint64_t str_size); void encode(const uint8_t *data, uint64_t data_size, char *str, uint64_t str_size);
std::string encode(std::span<const uint8_t> data) noexcept; std::string encode(std::span<const uint8_t> data) noexcept;

View File

@ -10,11 +10,12 @@ namespace baseN
bool isValid(const char *str, uint64_t str_size, const int8_t *map) noexcept; bool isValid(const char *str, uint64_t str_size, const int8_t *map) noexcept;
bool isValid(std::string_view str, const int8_t *map) noexcept; bool isValid(std::string_view str, const int8_t *map) noexcept;
void encode(const uint8_t *data, uint64_t data_size, char *str, uint8_t base, const char *digits, uint64_t enc_size) noexcept; uint64_t sizeEncoded(std::span<const uint8_t> data, uint8_t base);
std::string encode(std::span<const uint8_t> data, uint8_t base, const char *digits, uint64_t enc_size) noexcept; uint64_t sizeDecoded(std::string_view str, uint8_t base) noexcept;
void encode(const uint8_t *data, uint64_t data_size, char *str, uint64_t str_size, uint8_t base, const char *digits);
std::string encode(std::span<const uint8_t> data, uint8_t base, const char *digits) noexcept; std::string encode(std::span<const uint8_t> data, uint8_t base, const char *digits) noexcept;
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); void decode(const char *str, uint64_t str_size, uint8_t *data, uint64_t data_size, uint8_t base, const char *digits, const int8_t *map);
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> decode(std::string_view str, uint8_t base, const char *digits, const int8_t *map) noexcept;
std::vector<uint8_t> decode(std::string_view str, uint8_t base, const char *digits, const int8_t *map);
} }

View File

@ -11,7 +11,7 @@ namespace hex
bool isValid(std::string_view str) noexcept; bool isValid(std::string_view str) noexcept;
uint64_t sizeEncoded(std::span<const uint8_t> data); uint64_t sizeEncoded(std::span<const uint8_t> data);
uint64_t sizeDecoded(std::string_view str_size) noexcept; uint64_t sizeDecoded(std::string_view str) noexcept;
void encode(const uint8_t *data, uint64_t data_size, char *str, uint64_t str_size); void encode(const uint8_t *data, uint64_t data_size, char *str, uint64_t str_size);
std::string encode(std::span<const uint8_t> data) noexcept; std::string encode(std::span<const uint8_t> data) noexcept;

View File

@ -1,9 +1,12 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <limits>
#include <stdexcept> #include <stdexcept>
#include <base/baseN.hpp> #include <base/baseN.hpp>
static constexpr auto log256 = std::log(256);
namespace baseN namespace baseN
{ {
bool isValid(const char *str, uint64_t str_size, const int8_t *map) noexcept bool isValid(const char *str, uint64_t str_size, const int8_t *map) noexcept
@ -16,123 +19,135 @@ namespace baseN
{ {
return baseN::isValid(str.data(), str.size(), map); return baseN::isValid(str.data(), str.size(), map);
} }
void encode(const uint8_t *data, uint64_t data_size, char *str, uint8_t base, const char *digits, uint64_t enc_size) noexcept uint64_t sizeEncoded(std::span<const uint8_t> data, uint8_t base)
{ {
if (data_size == 0) if (data.size() > std::numeric_limits<uint64_t>::max() / log256)
{ {
return; throw std::overflow_error("baseN::sizeEncoded: overflow");
} }
char res_str[enc_size]; return data.size() * log256 / std::log(base) + 1;
uint8_t div_buf[data_size]; }
std::copy(data, data + data_size, div_buf); uint64_t sizeDecoded(std::string_view str, uint8_t base) noexcept
int64_t {
zero_count = 0, return str.size() * std::log(base) / log256 + 1;
idx_div = 0, }
idx_quo = 0, // void encode(const uint8_t *data, uint64_t data_size, char *str, uint8_t base, const char *digits, uint64_t enc_size) noexcept
idx_quo_last = data_size, // {
idx_str = enc_size - 1; // if (data_size == 0)
uint16_t div = data[idx_div++]; // {
// 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++];
while (zero_count < (int64_t)data_size && data[zero_count] == 0) // while (zero_count < (int64_t)data_size && data[zero_count] == 0)
{ // {
zero_count++; // zero_count++;
} // }
while (idx_quo_last > 1 || div_buf[0] > base) // while (idx_quo_last > 1 || div_buf[0] > base)
{ // {
if (div < base) // if (div < base)
{ // {
div <<= 8; // div <<= 8;
div += div_buf[idx_div++]; // div += div_buf[idx_div++];
} // }
div_buf[idx_quo++] = div / base; // div_buf[idx_quo++] = div / base;
div %= base; // div %= base;
while (idx_div < idx_quo_last) // while (idx_div < idx_quo_last)
{ // {
div <<= 8; // div <<= 8;
div += div_buf[idx_div++]; // div += div_buf[idx_div++];
div_buf[idx_quo++] = div / base; // div_buf[idx_quo++] = div / base;
div %= base; // div %= base;
} // }
idx_quo_last = idx_quo; // idx_quo_last = idx_quo;
idx_quo = 0; // idx_quo = 0;
idx_div = 0; // idx_div = 0;
res_str[idx_str--] = digits[div]; // res_str[idx_str--] = digits[div];
div = div_buf[idx_div++]; // div = div_buf[idx_div++];
} // }
res_str[idx_str--] = digits[div]; // res_str[idx_str--] = digits[div];
while (zero_count > 0 && idx_str >= 0) // while (zero_count > 0 && idx_str >= 0)
{ // {
res_str[idx_str--] = digits[0]; // res_str[idx_str--] = digits[0];
zero_count--; // zero_count--;
} // }
while (idx_str >= 0) // while (idx_str >= 0)
{ // {
res_str[idx_str--] = ' '; // res_str[idx_str--] = ' ';
} // }
std::copy(res_str, res_str + enc_size, 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 encode(std::span<const uint8_t> data, uint8_t base, const char *digits, uint64_t enc_size) noexcept
{ // {
std::string str(enc_size, ' '); // std::string str(enc_size, ' ');
baseN::encode(data.data(), data.size(), str.data(), base, digits, enc_size); // baseN::encode(data.data(), data.size(), str.data(), base, digits, enc_size);
str.erase(str.begin(), std::find_if( // str.erase(str.begin(), std::find_if(
str.begin(), str.end(), [](char ch) // str.begin(), str.end(), [](char ch)
{ return ch != ' '; })); // { return ch != ' '; }));
return str; // return str;
} // }
std::string encode(std::span<const uint8_t> data, uint8_t base, const char *digits) noexcept // 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); // 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) // 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') // if (str[0] == '\0')
{ // {
return; // return;
} // }
if (!baseN::isValid(str, map)) // if (!baseN::isValid(str, map))
{ // {
throw std::logic_error("baseN::decode: out of digits map"); // throw std::logic_error("baseN::decode: out of digits map");
} // }
uint8_t res_data[dec_size]; // uint8_t res_data[dec_size];
uint64_t idx_str = 0; // uint64_t idx_str = 0;
int64_t // int64_t
zero_count = 0, // zero_count = 0,
idx_quo = dec_size - 1, // idx_quo = dec_size - 1,
idx_quo_last = dec_size - 2; // idx_quo_last = dec_size - 2;
uint16_t div; // uint16_t div;
while (str[zero_count] != '\0' && str[zero_count] == digits[0]) // while (str[zero_count] != '\0' && str[zero_count] == digits[0])
{ // {
zero_count++; // zero_count++;
} // }
res_data[idx_quo] = map[(int8_t)str[idx_str++]]; // res_data[idx_quo] = map[(int8_t)str[idx_str++]];
while (str[idx_str] != '\0') // while (str[idx_str] != '\0')
{ // {
div = map[(int8_t)str[idx_str++]]; // div = map[(int8_t)str[idx_str++]];
while (idx_quo > idx_quo_last && idx_quo > 0) // while (idx_quo > idx_quo_last && idx_quo > 0)
{ // {
div += res_data[idx_quo] * base; // div += res_data[idx_quo] * base;
res_data[idx_quo--] = div; // res_data[idx_quo--] = div;
div >>= 8; // div >>= 8;
} // }
res_data[idx_quo--] = div; // res_data[idx_quo--] = div;
idx_quo_last = idx_quo; // idx_quo_last = idx_quo;
idx_quo = dec_size - 1; // idx_quo = dec_size - 1;
} // }
std::copy(res_data, res_data + std::min(dec_size, data_size), data); // 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> 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); // std::vector<uint8_t> data(dec_size);
baseN::decode(str.data(), data.data(), data.size(), base, digits, map, dec_size); // baseN::decode(str.data(), data.data(), data.size(), base, digits, map, dec_size);
data.erase(data.begin(), std::find_if( // data.erase(data.begin(), std::find_if(
data.begin(), data.end(), [](uint8_t byte) // data.begin(), data.end(), [](uint8_t byte)
{ return byte != 0; })); // { return byte != 0; }));
return data; // return data;
} // }
std::vector<uint8_t> decode(std::string_view str, uint8_t base, const char *digits, const int8_t *map) // 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); // return baseN::decode(str, base, digits, map, str.size() * std::log(base) / std::log(256) + 1);
} // }
} }

View File

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