fix(baseN): basen::Exception

This commit is contained in:
2024-09-30 17:23:23 +03:00
parent 4eaf5b53c0
commit 227579d1e2
4 changed files with 43 additions and 14 deletions

View File

@ -85,7 +85,7 @@ docs:
cover: ${DIRS} ${patsubst %, ${BINDIR}/%${-g}-cov, ${TESTS}} cover: ${DIRS} ${patsubst %, ${BINDIR}/%${-g}-cov, ${TESTS}}
rm -f **/*.gcda rm -f **/*.gcda
${patsubst %, ./${BINDIR}/%${-g}-cov;, ${TESTS}} ${patsubst %, ./${BINDIR}/%${-g}-cov;, ${TESTS}}
mkdir cov mkdir -p cov
gcovr --html-nested cov/index.html --txt --exclude-throw-branches gcovr --html-nested cov/index.html --txt --exclude-throw-branches
${OBJDIR}/%${-g}-cov.o: ${SRCDIR}/%.cpp ${INCDIR}/${LIB}/%.hpp ${OBJDIR}/%${-g}-cov.o: ${SRCDIR}/%.cpp ${INCDIR}/${LIB}/%.hpp

View File

@ -11,7 +11,7 @@ namespace baseN
* @param digits char[base] array of digits * @param digits char[base] array of digits
* @param digits_size size of digits array. Equals to base * @param digits_size size of digits array. Equals to base
* @param map [out] uint8_t[256] array, where at an index equal to the value of the symbol is the index of this symbol in the digits array. 255 if there is no symbol * @param map [out] uint8_t[256] array, where at an index equal to the value of the symbol is the index of this symbol in the digits array. 255 if there is no symbol
* @throw std::logic_error if alphabet contain same chars * @throw basen::Exception(ALPH_COLLISION) if alphabet contain same chars
*/ */
void digitsMap(const char *digits, uint8_t digits_size, uint8_t *map); void digitsMap(const char *digits, uint8_t digits_size, uint8_t *map);
/** /**
@ -32,6 +32,7 @@ namespace baseN
* @param data vector or span of data which you want to encode * @param data vector or span of data which you want to encode
* @param base from 1 to 255 * @param base from 1 to 255
* @return estimated size after encoding * @return estimated size after encoding
* @throw basen::Exception(BASE) if base < 2 || base > 254
*/ */
size_t sizeEncoded(std::span<const uint8_t> data, uint8_t base); size_t sizeEncoded(std::span<const uint8_t> data, uint8_t base);
/** /**
@ -39,9 +40,10 @@ namespace baseN
* @param base from 1 to 255 * @param base from 1 to 255
* @param digits char[base] array of digits * @param digits char[base] array of digits
* @return estimated size after decoding * @return estimated size after decoding
* @throw std::overflow_error if if there is an overflow * @throw basen::Exception(BASE) if base < 2 || base > 254
* @throw basen::Exception(OVERFLOW) if if there is an overflow
*/ */
size_t sizeDecoded(std::string_view str, uint8_t base, const char *digits) noexcept; size_t sizeDecoded(std::string_view str, uint8_t base, const char *digits);
/** /**
* @param data [in] pointer to data which you want encode * @param data [in] pointer to data which you want encode
@ -59,6 +61,7 @@ namespace baseN
* str.erase(str.begin(), str.begin() + offset); * str.erase(str.begin(), str.begin() + offset);
* @endcode * @endcode
* @return number of leading chars, which should be trimmed * @return number of leading chars, which should be trimmed
* @throw basen::Exception(BASE) if base < 2 || base > 254
* @warning contain leading zeros, returns count of them * @warning contain leading zeros, returns count of them
*/ */
size_t encode(const uint8_t *data, size_t data_size, char *str, size_t str_size, uint8_t base, const char *digits); size_t encode(const uint8_t *data, size_t data_size, char *str, size_t str_size, uint8_t base, const char *digits);
@ -72,7 +75,7 @@ namespace baseN
* @endcode * @endcode
* @return encoded string * @return encoded string
*/ */
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);
/** /**
* @param str [in] pointer to string which you want decode * @param str [in] pointer to string which you want decode
@ -91,6 +94,8 @@ namespace baseN
* data.erase(data.begin(), data.begin() + offset); * data.erase(data.begin(), data.begin() + offset);
* @endcode * @endcode
* @return number of leading chars, which should be trimmed * @return number of leading chars, which should be trimmed
* @throw basen::Exception(BASE) if base < 2 || base > 254
* @throw basen::Exception(OUT_OF_ALPH) if out of alphabet
* @warning contain leading zeros, returns count of them * @warning contain leading zeros, returns count of them
*/ */
size_t decode(const char *str, size_t str_size, uint8_t *data, size_t data_size, uint8_t base, const char *digits, const uint8_t *map); size_t decode(const char *str, size_t str_size, uint8_t *data, size_t data_size, uint8_t base, const char *digits, const uint8_t *map);
@ -105,5 +110,5 @@ namespace baseN
* @endcode * @endcode
* @return decoded data * @return decoded data
*/ */
std::vector<uint8_t> decode(std::string_view str, uint8_t base, const char *digits, const uint8_t *map) noexcept; std::vector<uint8_t> decode(std::string_view str, uint8_t base, const char *digits, const uint8_t *map);
} }

View File

@ -4,6 +4,7 @@
#include <stdexcept> #include <stdexcept>
#include <basen/baseN.hpp> #include <basen/baseN.hpp>
#include <basen/Exception.hpp>
static constexpr auto log256 = std::log(256); static constexpr auto log256 = std::log(256);
@ -16,7 +17,7 @@ namespace baseN
{ {
if (map[(uint8_t)digits[i]] != 255) if (map[(uint8_t)digits[i]] != 255)
{ {
throw std::logic_error("baseN::digitsMap: alphabet contain same chars"); throw basen::Exception(basen::Exception::Code::ALPH_COLLISION);
} }
map[(uint8_t)digits[i]] = i; map[(uint8_t)digits[i]] = i;
} }
@ -32,17 +33,25 @@ namespace baseN
} }
size_t sizeEncoded(std::span<const uint8_t> data, uint8_t base) size_t sizeEncoded(std::span<const uint8_t> data, uint8_t base)
{ {
if (base < 2 || base > 254)
{
throw basen::Exception(basen::Exception::Code::BASE);
}
std::span<const uint8_t> dv(std::find_if(data.begin(), data.end(), [](uint8_t item) std::span<const uint8_t> dv(std::find_if(data.begin(), data.end(), [](uint8_t item)
{ return item != 0; }), { return item != 0; }),
data.end()); data.end());
if (dv.size() > std::numeric_limits<size_t>::max() / log256) if (dv.size() > std::numeric_limits<size_t>::max() / log256)
{ {
throw std::overflow_error("baseN::sizeEncoded: overflow"); throw basen::Exception(basen::Exception::Code::OVERFLOW);
} }
return dv.size() * log256 / std::log(base) + 1 + (data.size() - dv.size()); return dv.size() * log256 / std::log(base) + 1 + (data.size() - dv.size());
} }
size_t sizeDecoded(std::string_view str, uint8_t base, const char *digits) noexcept size_t sizeDecoded(std::string_view str, uint8_t base, const char *digits)
{ {
if (base < 2 || base > 254)
{
throw basen::Exception(basen::Exception::Code::BASE);
}
std::string_view sv(std::find_if(str.begin(), str.end(), [digits](uint8_t ch) std::string_view sv(std::find_if(str.begin(), str.end(), [digits](uint8_t ch)
{ return ch != digits[0]; }), { return ch != digits[0]; }),
str.end()); str.end());
@ -50,6 +59,10 @@ namespace baseN
} }
size_t encode(const uint8_t *data, size_t data_size, char *str, size_t str_size, uint8_t base, const char *digits) size_t encode(const uint8_t *data, size_t data_size, char *str, size_t str_size, uint8_t base, const char *digits)
{ {
if (base < 2 || base > 254)
{
throw basen::Exception(basen::Exception::Code::BASE);
}
std::vector<uint8_t> dv(std::find_if(data, data + data_size, [](uint8_t item) std::vector<uint8_t> dv(std::find_if(data, data + data_size, [](uint8_t item)
{ return item != 0; }), { return item != 0; }),
data + data_size); data + data_size);
@ -92,7 +105,7 @@ namespace baseN
} }
return std::distance(sv_it, sv.rend()); return std::distance(sv_it, sv.rend());
} }
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)
{ {
std::string str(baseN::sizeEncoded(data, base), ' '); std::string str(baseN::sizeEncoded(data, base), ' ');
size_t offset = baseN::encode(data.data(), data.size(), str.data(), str.size(), base, digits); size_t offset = baseN::encode(data.data(), data.size(), str.data(), str.size(), base, digits);
@ -101,12 +114,16 @@ namespace baseN
} }
size_t decode(const char *str, size_t str_size, uint8_t *data, size_t data_size, uint8_t base, const char *digits, const uint8_t *map) size_t decode(const char *str, size_t str_size, uint8_t *data, size_t data_size, uint8_t base, const char *digits, const uint8_t *map)
{ {
if (base < 2 || base > 254)
{
throw basen::Exception(basen::Exception::Code::BASE);
}
std::string_view sv(std::find_if(str, str + str_size, [digits](char ch) std::string_view sv(std::find_if(str, str + str_size, [digits](char ch)
{ return ch != digits[0]; }), { return ch != digits[0]; }),
str + str_size); str + str_size);
if (!baseN::isValid(sv, map)) if (!baseN::isValid(sv, map))
{ {
throw std::logic_error("baseN::decode: out of digits map"); throw basen::Exception(basen::Exception::Code::OUT_OF_ALPH);
} }
std::span<uint8_t> dv(data, data_size); std::span<uint8_t> dv(data, data_size);
auto sv_it = sv.begin(); auto sv_it = sv.begin();
@ -141,7 +158,7 @@ namespace baseN
} }
return std::distance(quo_it_last, dv.rend()); return std::distance(quo_it_last, dv.rend());
} }
std::vector<uint8_t> decode(std::string_view str, uint8_t base, const char *digits, const uint8_t *map) noexcept std::vector<uint8_t> decode(std::string_view str, uint8_t base, const char *digits, const uint8_t *map)
{ {
std::vector<uint8_t> data(baseN::sizeDecoded(str, base, digits)); std::vector<uint8_t> data(baseN::sizeDecoded(str, base, digits));
size_t offset = baseN::decode(str.data(), str.size(), data.data(), data.size(), base, digits, map); size_t offset = baseN::decode(str.data(), str.size(), data.data(), data.size(), base, digits, map);

View File

@ -2,6 +2,7 @@
#include <basen/base58.hpp> #include <basen/base58.hpp>
#include <basen/baseN.hpp> #include <basen/baseN.hpp>
#include <basen/Exception.hpp>
#include <basen/hex.hpp> #include <basen/hex.hpp>
#include <gtest/gtest.h> #include <gtest/gtest.h>
@ -13,7 +14,7 @@ TEST(baseN, digitsMap)
digitsMap(base58::digits, 58, map); digitsMap(base58::digits, 58, map);
EXPECT_TRUE(std::equal(map, map + 256, base58::map)); EXPECT_TRUE(std::equal(map, map + 256, base58::map));
EXPECT_THROW(digitsMap("11", 2, map), std::logic_error); EXPECT_THROW(digitsMap("11", 2, map), basen::Exception);
} }
TEST(baseN, isValid) TEST(baseN, isValid)
{ {
@ -30,8 +31,10 @@ TEST(baseN, sizeEncoded)
{6, "12341234"}, {6, "12341234"},
{5, "00000000"}, {5, "00000000"},
}; };
for (auto it : tests) for (auto it : tests)
EXPECT_EQ(it.first, sizeEncoded(hex::decode(it.second), 58)); EXPECT_EQ(it.first, sizeEncoded(hex::decode(it.second), 58));
EXPECT_THROW(sizeEncoded(hex::decode(""), 0), basen::Exception);
} }
TEST(baseN, sizeDecoded) TEST(baseN, sizeDecoded)
{ {
@ -41,6 +44,8 @@ TEST(baseN, sizeDecoded)
}; };
for (auto it : tests) for (auto it : tests)
EXPECT_EQ(it.first, sizeDecoded(it.second, 58, base58::digits)); EXPECT_EQ(it.first, sizeDecoded(it.second, 58, base58::digits));
EXPECT_THROW(sizeDecoded("", 0, base58::digits), basen::Exception);
} }
std::vector<std::pair<std::string, std::string>> tests = { std::vector<std::pair<std::string, std::string>> tests = {
{"", ""}, {"", ""},
@ -68,6 +73,8 @@ TEST(baseN, decode)
{ {
for (auto it : tests) for (auto it : tests)
EXPECT_EQ(hex::encode(decode(it.first, 58, base58::digits, base58::map)), it.second); EXPECT_EQ(hex::encode(decode(it.first, 58, base58::digits, base58::map)), it.second);
EXPECT_THROW(decode("!@#", 58, base58::digits, base58::map), basen::Exception);
} }
TEST(baseN, decode_1e3) TEST(baseN, decode_1e3)
{ {