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}}
rm -f **/*.gcda
${patsubst %, ./${BINDIR}/%${-g}-cov;, ${TESTS}}
mkdir cov
mkdir -p cov
gcovr --html-nested cov/index.html --txt --exclude-throw-branches
${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_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
* @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);
/**
@ -32,6 +32,7 @@ namespace baseN
* @param data vector or span of data which you want to encode
* @param base from 1 to 255
* @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);
/**
@ -39,9 +40,10 @@ namespace baseN
* @param base from 1 to 255
* @param digits char[base] array of digits
* @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
@ -59,6 +61,7 @@ namespace baseN
* str.erase(str.begin(), str.begin() + offset);
* @endcode
* @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
*/
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
* @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
@ -91,6 +94,8 @@ namespace baseN
* data.erase(data.begin(), data.begin() + offset);
* @endcode
* @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
*/
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
* @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 <basen/baseN.hpp>
#include <basen/Exception.hpp>
static constexpr auto log256 = std::log(256);
@ -16,7 +17,7 @@ namespace baseN
{
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;
}
@ -32,17 +33,25 @@ namespace baseN
}
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)
{ return item != 0; }),
data.end());
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());
}
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)
{ return ch != digits[0]; }),
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)
{
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)
{ return item != 0; }),
data + data_size);
@ -92,7 +105,7 @@ namespace baseN
}
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), ' ');
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)
{
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)
{ return ch != digits[0]; }),
str + str_size);
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);
auto sv_it = sv.begin();
@ -141,7 +158,7 @@ namespace baseN
}
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));
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/baseN.hpp>
#include <basen/Exception.hpp>
#include <basen/hex.hpp>
#include <gtest/gtest.h>
@ -13,7 +14,7 @@ TEST(baseN, digitsMap)
digitsMap(base58::digits, 58, 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)
{
@ -30,8 +31,10 @@ TEST(baseN, sizeEncoded)
{6, "12341234"},
{5, "00000000"},
};
for (auto it : tests)
for (auto it : tests)
EXPECT_EQ(it.first, sizeEncoded(hex::decode(it.second), 58));
EXPECT_THROW(sizeEncoded(hex::decode(""), 0), basen::Exception);
}
TEST(baseN, sizeDecoded)
{
@ -41,6 +44,8 @@ TEST(baseN, sizeDecoded)
};
for (auto it : tests)
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 = {
{"", ""},
@ -68,6 +73,8 @@ TEST(baseN, decode)
{
for (auto it : tests)
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)
{