diff --git a/Makefile b/Makefile index 8ad096c..f779c62 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ TOOLS =\ TESTS =\ test-hex\ + test-baseN\ hash/test-sha256\ ifeq (${origin CC}, default) @@ -23,7 +24,7 @@ CC = g++ endif CFLAGS = -Wall -Wextra -Werror -Wno-unused-result -fPIC ifneq (${DEBUG}, false) -CFLAGS += -fsanitize=address,undefined -g -Og +CFLAGS += -fsanitize=address,undefined -g -O0 -g = -g else CFLAGS += -O3 diff --git a/src/baseN.cpp b/src/baseN.cpp index d750f9f..0fa1d4c 100644 --- a/src/baseN.cpp +++ b/src/baseN.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include @@ -21,98 +23,127 @@ namespace baseN { return baseN::isValid(str.data(), map); } - std::string encode(std::vector data, uint8_t base, uint64_t enc_size, const char *digits) noexcept + + 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) + if (data_size == 0) { - return ""; + return; } - std::string str(enc_size, ' '); + 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 = str.size() - 1; + idx_quo_last = data_size, + idx_str = enc_size - 1; uint16_t div = data[idx_div++]; while (data[zero_count] == 0) { zero_count++; } - while (idx_quo_last > 1 || data[0] > base) + while (idx_quo_last > 1 || div_buf[0] > base) { if (div < base) { div <<= 8; - div += data[idx_div++]; + div += div_buf[idx_div++]; } - data[idx_quo++] = div / base; + div_buf[idx_quo++] = div / base; div %= base; while (idx_div < idx_quo_last) { div <<= 8; - div += data[idx_div++]; - data[idx_quo++] = div / base; + div += div_buf[idx_div++]; + div_buf[idx_quo++] = div / base; div %= base; } idx_quo_last = idx_quo; idx_quo = 0; idx_div = 0; - str[idx_str--] = digits[div]; - div = data[idx_div++]; + res_str[idx_str--] = digits[div]; + div = div_buf[idx_div++]; } - str[idx_str--] = digits[div]; - while (zero_count > 0 && idx_str > 0) + res_str[idx_str--] = digits[div]; + while (zero_count > 0 && idx_str >= 0) { - str[idx_str--] = digits[0]; + res_str[idx_str--] = digits[0]; zero_count--; } - str.erase(0, idx_str + 1); + while (idx_str >= 0) + { + res_str[idx_str--] = ' '; + } + std::copy(res_str, res_str + enc_size, str); + } + void encode(const uint8_t *data, uint64_t data_size, char *str, uint8_t base, const char *digits) noexcept + { + baseN::encode(data, data_size, str, base, digits, data_size * std::log(256) / std::log(base) + 1); + } + std::string encode(std::vector 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::vector decode(const std::string &str, uint8_t base, uint64_t dec_size, const char *digits, const int8_t *map) + std::string encode(std::vector data, uint8_t base, const char *digits) noexcept { - if (str.size() == 0) - { - return std::vector(); - } - if (!baseN::isValid(str, map)) - { - throw std::logic_error("baseN::decode: out of digits map"); - } - std::vector data(dec_size); - uint64_t idx_str = 0; - int64_t - zero_count = 0, - idx_quo = data.size() - 1, - idx_quo_last = data.size() - 2; - uint16_t div; - - while (str[zero_count] == digits[0]) - { - zero_count++; - } - data[idx_quo] = map[(int8_t)str[idx_str++]]; - while (idx_str < str.size()) - { - div = map[(int8_t)str[idx_str++]]; - while (idx_quo > idx_quo_last && idx_quo > 0) - { - div += data[idx_quo] * base; - data[idx_quo--] = div; - div >>= 8; - } - data[idx_quo--] = div; - idx_quo_last = idx_quo; - idx_quo = data.size() - 1; - } - idx_quo = 0; - while (data[idx_quo] == 0) - { - idx_quo++; - } - data.erase(data.begin(), data.begin() + idx_quo - zero_count); - return data; + 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 char *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 = new uint8_t[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] == digits[0]) + // { + // zero_count++; + // } + // res_data[idx_quo] = map[(int8_t)str[idx_str++]]; + // while (idx_str < str.size()) + // { + // div = map[(int8_t)str[idx_str++]]; + // while (idx_quo > idx_quo_last && idx_quo > 0) + // { + // div += data[idx_quo] * base; + // data[idx_quo--] = div; + // div >>= 8; + // } + // data[idx_quo--] = div; + // idx_quo_last = idx_quo; + // idx_quo = data.size() - 1; + // } + // idx_quo = 0; + // while (data[idx_quo] == 0) + // { + // idx_quo++; + // } + // data.erase(data.begin(), data.begin() + idx_quo - zero_count); + // delete[] res_data; + // } + // void decode(const char *str, uint8_t *data, uint64_t data_size, uint8_t base, const char *digits, const char *map); + // std::vector decode(const std::string &str, uint8_t base, const char *digits, const char *map, uint64_t dec_size); + // std::vector decode(const std::string &str, uint8_t base, const char *digits, const char *map); } \ No newline at end of file diff --git a/test/test-baseN.cpp b/test/test-baseN.cpp new file mode 100644 index 0000000..d541762 --- /dev/null +++ b/test/test-baseN.cpp @@ -0,0 +1,65 @@ +#include +#include +#include + +using namespace baseN; + +static const char b58digits[] = + "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + +static const int8_t b58map[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, + -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, + -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +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_1e6) +// { +// std::vector data(1e6); +// encode(data); +// } +// TEST(baseN, decode) +// { +// EXPECT_EQ(btc::data::hex::encode(decode("Ky")), "044c"); +// EXPECT_EQ(btc::data::hex::encode(decode("KyK")), "f94a"); +// EXPECT_EQ(btc::data::hex::encode(decode("KyKX")), "387ae2"); +// EXPECT_EQ(btc::data::hex::encode(decode("KyKXa")), "0ccbd755"); +// EXPECT_EQ(btc::data::hex::encode(decode("KyKXaa")), "02e62ec963"); +// } +// TEST(baseN, decode_1e6) +// { +// std::string str(1e6, '0'); +// decode(str); +// } + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file