Skip to content

Commit

Permalink
Improve addcarry() and BaseX encoding (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
cyberjunk committed Nov 18, 2023
1 parent dca40f2 commit cd0559b
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 11 deletions.
145 changes: 145 additions & 0 deletions include/CppCore.Test/Encoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,141 @@ namespace CppCore { namespace Test
// TODO: More than Base10
return true;
}
INLINE static bool parse8()
{
uint8_t r;
CppCore::BaseX::parse("", r, CPPCORE_ALPHABET_B10); if (r != 0) return false;
CppCore::BaseX::parse("0", r, CPPCORE_ALPHABET_B10); if (r != 0) return false;
CppCore::BaseX::parse("1", r, CPPCORE_ALPHABET_B10); if (r != 1) return false;
CppCore::BaseX::parse("143", r, CPPCORE_ALPHABET_B10); if (r != 143) return false;
CppCore::BaseX::parse("255", r, CPPCORE_ALPHABET_B10); if (r != 255) return false;
CppCore::BaseX::parse("256", r, CPPCORE_ALPHABET_B10); if (r != 0) return false;
return true;
}
INLINE static bool parse16()
{
uint16_t r;
CppCore::BaseX::parse("", r, CPPCORE_ALPHABET_B10); if (r != 0) return false;
CppCore::BaseX::parse("0", r, CPPCORE_ALPHABET_B10); if (r != 0) return false;
CppCore::BaseX::parse("1", r, CPPCORE_ALPHABET_B10); if (r != 1) return false;
CppCore::BaseX::parse("143", r, CPPCORE_ALPHABET_B10); if (r != 143) return false;
CppCore::BaseX::parse("255", r, CPPCORE_ALPHABET_B10); if (r != 255) return false;
CppCore::BaseX::parse("65535", r, CPPCORE_ALPHABET_B10); if (r != 65535) return false;
CppCore::BaseX::parse("65536", r, CPPCORE_ALPHABET_B10); if (r != 0) return false;
return true;
}
INLINE static bool parse32()
{
uint32_t r;
CppCore::BaseX::parse("", r, CPPCORE_ALPHABET_B10); if (r != 0U) return false;
CppCore::BaseX::parse("0", r, CPPCORE_ALPHABET_B10); if (r != 0U) return false;
CppCore::BaseX::parse("1", r, CPPCORE_ALPHABET_B10); if (r != 1U) return false;
CppCore::BaseX::parse("143", r, CPPCORE_ALPHABET_B10); if (r != 143U) return false;
CppCore::BaseX::parse("255", r, CPPCORE_ALPHABET_B10); if (r != 255U) return false;
CppCore::BaseX::parse("65535", r, CPPCORE_ALPHABET_B10); if (r != 65535U) return false;
CppCore::BaseX::parse("4294967295", r, CPPCORE_ALPHABET_B10); if (r != 4294967295U) return false;
CppCore::BaseX::parse("4294967296", r, CPPCORE_ALPHABET_B10); if (r != 0) return false;
return true;
}
INLINE static bool parse64()
{
uint64_t r;
CppCore::BaseX::parse("", r, CPPCORE_ALPHABET_B10); if (r != 0U) return false;
CppCore::BaseX::parse("0", r, CPPCORE_ALPHABET_B10); if (r != 0U) return false;
CppCore::BaseX::parse("1", r, CPPCORE_ALPHABET_B10); if (r != 1U) return false;
CppCore::BaseX::parse("143", r, CPPCORE_ALPHABET_B10); if (r != 143U) return false;
CppCore::BaseX::parse("255", r, CPPCORE_ALPHABET_B10); if (r != 255U) return false;
CppCore::BaseX::parse("65535", r, CPPCORE_ALPHABET_B10); if (r != 65535U) return false;
CppCore::BaseX::parse("4294967295", r, CPPCORE_ALPHABET_B10); if (r != 4294967295U) return false;
CppCore::BaseX::parse("18446744073709551615", r, CPPCORE_ALPHABET_B10); if (r != 18446744073709551615ULL) return false;
CppCore::BaseX::parse("18446744073709551616", r, CPPCORE_ALPHABET_B10); if (r != 0) return false;
return true;
}
INLINE static bool parse128()
{
uint64_t r[2];
CppCore::BaseX::parse("", r, CPPCORE_ALPHABET_B10); if (r[1] != 0U || r[0] != 0U) return false;
CppCore::BaseX::parse("0", r, CPPCORE_ALPHABET_B10); if (r[1] != 0U || r[0] != 0U) return false;
CppCore::BaseX::parse("1", r, CPPCORE_ALPHABET_B10); if (r[1] != 0U || r[0] != 1U) return false;
CppCore::BaseX::parse("143", r, CPPCORE_ALPHABET_B10); if (r[1] != 0U || r[0] != 143U) return false;
CppCore::BaseX::parse("255", r, CPPCORE_ALPHABET_B10); if (r[1] != 0U || r[0] != 255U) return false;
CppCore::BaseX::parse("65535", r, CPPCORE_ALPHABET_B10); if (r[1] != 0U || r[0] != 65535U) return false;
CppCore::BaseX::parse("4294967295", r, CPPCORE_ALPHABET_B10); if (r[1] != 0U || r[0] != 4294967295U) return false;
CppCore::BaseX::parse("18446744073709551615", r, CPPCORE_ALPHABET_B10); if (r[1] != 0U || r[0] != 18446744073709551615ULL) return false;
CppCore::BaseX::parse("340282366920938463463374607431768211455", r, CPPCORE_ALPHABET_B10); if (r[1] != 0xFFFFFFFFFFFFFFFFULL || r[0] != 0xFFFFFFFFFFFFFFFFULL) return false;
CppCore::BaseX::parse("340282366920938463463374607431768211456", r, CPPCORE_ALPHABET_B10); if (r[1] != 0U || r[0] != 0U) return false;
return true;
}
INLINE static bool tryparse8()
{
uint8_t r;
if (!CppCore::BaseX::tryparse("0", r, CPPCORE_ALPHABET_B10) || r != 0) return false;
if (!CppCore::BaseX::tryparse("1", r, CPPCORE_ALPHABET_B10) || r != 1) return false;
if (!CppCore::BaseX::tryparse("143", r, CPPCORE_ALPHABET_B10) || r != 143) return false;
if (!CppCore::BaseX::tryparse("255", r, CPPCORE_ALPHABET_B10) || r != 255) return false;
if ( CppCore::BaseX::tryparse("256", r, CPPCORE_ALPHABET_B10)) return false;
if ( CppCore::BaseX::tryparse("", r, CPPCORE_ALPHABET_B10)) return false;
if ( CppCore::BaseX::tryparse("x", r, CPPCORE_ALPHABET_B10)) return false;
return true;
}
INLINE static bool tryparse16()
{
uint16_t r;
if (!CppCore::BaseX::tryparse("0", r, CPPCORE_ALPHABET_B10) || r != 0) return false;
if (!CppCore::BaseX::tryparse("1", r, CPPCORE_ALPHABET_B10) || r != 1) return false;
if (!CppCore::BaseX::tryparse("143", r, CPPCORE_ALPHABET_B10) || r != 143) return false;
if (!CppCore::BaseX::tryparse("255", r, CPPCORE_ALPHABET_B10) || r != 255) return false;
if (!CppCore::BaseX::tryparse("65535", r, CPPCORE_ALPHABET_B10) || r != 65535) return false;
if ( CppCore::BaseX::tryparse("65536", r, CPPCORE_ALPHABET_B10)) return false;
if ( CppCore::BaseX::tryparse("", r, CPPCORE_ALPHABET_B10)) return false;
if ( CppCore::BaseX::tryparse("x", r, CPPCORE_ALPHABET_B10)) return false;
return true;
}
INLINE static bool tryparse32()
{
uint32_t r;
if (!CppCore::BaseX::tryparse("0", r, CPPCORE_ALPHABET_B10) || r != 0) return false;
if (!CppCore::BaseX::tryparse("1", r, CPPCORE_ALPHABET_B10) || r != 1) return false;
if (!CppCore::BaseX::tryparse("143", r, CPPCORE_ALPHABET_B10) || r != 143) return false;
if (!CppCore::BaseX::tryparse("255", r, CPPCORE_ALPHABET_B10) || r != 255) return false;
if (!CppCore::BaseX::tryparse("65535", r, CPPCORE_ALPHABET_B10) || r != 65535) return false;
if (!CppCore::BaseX::tryparse("4294967295", r, CPPCORE_ALPHABET_B10) || r != 4294967295U) return false;
if ( CppCore::BaseX::tryparse("4294967296", r, CPPCORE_ALPHABET_B10)) return false;
if ( CppCore::BaseX::tryparse("", r, CPPCORE_ALPHABET_B10)) return false;
if ( CppCore::BaseX::tryparse("x", r, CPPCORE_ALPHABET_B10)) return false;
return true;
}
INLINE static bool tryparse64()
{
uint64_t r;
if (!CppCore::BaseX::tryparse("0", r, CPPCORE_ALPHABET_B10) || r != 0) return false;
if (!CppCore::BaseX::tryparse("1", r, CPPCORE_ALPHABET_B10) || r != 1) return false;
if (!CppCore::BaseX::tryparse("143", r, CPPCORE_ALPHABET_B10) || r != 143) return false;
if (!CppCore::BaseX::tryparse("255", r, CPPCORE_ALPHABET_B10) || r != 255) return false;
if (!CppCore::BaseX::tryparse("65535", r, CPPCORE_ALPHABET_B10) || r != 65535) return false;
if (!CppCore::BaseX::tryparse("4294967295", r, CPPCORE_ALPHABET_B10) || r != 4294967295U) return false;
if (!CppCore::BaseX::tryparse("18446744073709551615", r, CPPCORE_ALPHABET_B10) || r != 18446744073709551615ULL) return false;
if ( CppCore::BaseX::tryparse("18446744073709551616", r, CPPCORE_ALPHABET_B10)) return false;
if ( CppCore::BaseX::tryparse("", r, CPPCORE_ALPHABET_B10)) return false;
if ( CppCore::BaseX::tryparse("x", r, CPPCORE_ALPHABET_B10)) return false;
return true;
}
INLINE static bool tryparse128()
{
uint64_t r[2];
if (!CppCore::BaseX::tryparse("0", r, CPPCORE_ALPHABET_B10) || r[1] != 0U || r[0] != 0U) return false;
if (!CppCore::BaseX::tryparse("1", r, CPPCORE_ALPHABET_B10) || r[1] != 0U || r[0] != 1U) return false;
if (!CppCore::BaseX::tryparse("143", r, CPPCORE_ALPHABET_B10) || r[1] != 0U || r[0] != 143U) return false;
if (!CppCore::BaseX::tryparse("255", r, CPPCORE_ALPHABET_B10) || r[1] != 0U || r[0] != 255U) return false;
if (!CppCore::BaseX::tryparse("65535", r, CPPCORE_ALPHABET_B10) || r[1] != 0U || r[0] != 65535U) return false;
if (!CppCore::BaseX::tryparse("4294967295", r, CPPCORE_ALPHABET_B10) || r[1] != 0U || r[0] != 4294967295U) return false;
if (!CppCore::BaseX::tryparse("18446744073709551615", r, CPPCORE_ALPHABET_B10) || r[1] != 0U || r[0] != 18446744073709551615ULL) return false;
if (!CppCore::BaseX::tryparse("340282366920938463463374607431768211455", r, CPPCORE_ALPHABET_B10) || r[1] != 0xFFFFFFFFFFFFFFFFULL || r[0] != 0xFFFFFFFFFFFFFFFFULL) return false;
if ( CppCore::BaseX::tryparse("340282366920938463463374607431768211456", r, CPPCORE_ALPHABET_B10)) return false;
if ( CppCore::BaseX::tryparse("", r, CPPCORE_ALPHABET_B10)) return false;
if ( CppCore::BaseX::tryparse("x", r, CPPCORE_ALPHABET_B10)) return false;
return true;
}
};
class Hex
{
Expand Down Expand Up @@ -910,6 +1045,16 @@ namespace CppCore { namespace Test { namespace VS
TEST_METHOD(BASEX_TOSTRING16) { Assert::AreEqual(true, CppCore::Test::Encoding::BaseX::tostring16()); }
TEST_METHOD(BASEX_TOSTRING32) { Assert::AreEqual(true, CppCore::Test::Encoding::BaseX::tostring32()); }
TEST_METHOD(BASEX_TOSTRING64) { Assert::AreEqual(true, CppCore::Test::Encoding::BaseX::tostring64()); }
TEST_METHOD(BASEX_PARSE8) { Assert::AreEqual(true, CppCore::Test::Encoding::BaseX::parse8()); }
TEST_METHOD(BASEX_PARSE16) { Assert::AreEqual(true, CppCore::Test::Encoding::BaseX::parse16()); }
TEST_METHOD(BASEX_PARSE32) { Assert::AreEqual(true, CppCore::Test::Encoding::BaseX::parse32()); }
TEST_METHOD(BASEX_PARSE64) { Assert::AreEqual(true, CppCore::Test::Encoding::BaseX::parse64()); }
TEST_METHOD(BASEX_PARSE128) { Assert::AreEqual(true, CppCore::Test::Encoding::BaseX::parse128()); }
TEST_METHOD(BASEX_TRYPARSE8) { Assert::AreEqual(true, CppCore::Test::Encoding::BaseX::tryparse8()); }
TEST_METHOD(BASEX_TRYPARSE16) { Assert::AreEqual(true, CppCore::Test::Encoding::BaseX::tryparse16()); }
TEST_METHOD(BASEX_TRYPARSE32) { Assert::AreEqual(true, CppCore::Test::Encoding::BaseX::tryparse32()); }
TEST_METHOD(BASEX_TRYPARSE64) { Assert::AreEqual(true, CppCore::Test::Encoding::BaseX::tryparse64()); }
TEST_METHOD(BASEX_TRYPARSE128){ Assert::AreEqual(true, CppCore::Test::Encoding::BaseX::tryparse128()); }
TEST_METHOD(HEX_BYTETOHEXSTR) { Assert::AreEqual(true, CppCore::Test::Encoding::Hex::Util::bytetohexstr()); }
TEST_METHOD(HEX_TOSTRING) { Assert::AreEqual(true, CppCore::Test::Encoding::Hex::tostring()); }
TEST_METHOD(HEX_TOSTRING16) { Assert::AreEqual(true, CppCore::Test::Encoding::Hex::tostring16()); }
Expand Down
12 changes: 6 additions & 6 deletions include/CppCore/Encoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,18 +213,18 @@ namespace CppCore
{
assert(::strlen(alphabet) >= 2);
uint8_t tbl[256];
size_t n = 0;
uint8_t n = 0;
CppCore::clear(r);
CppCore::clear(tbl);
while (const char c = *alphabet++)
tbl[c] = (uint8_t)n++;
tbl[c] = n++;
if (const char c = *input++)
{
*(uint8_t*)&r = tbl[c];
while (const char c = *input++)
{
CppCore::umul(r, n, r);
CppCore::uadd(r, (size_t)tbl[c], r);
CppCore::uadd(r, tbl[c], r);
}
}
}
Expand All @@ -239,10 +239,10 @@ namespace CppCore
if (!input || !alphabet)
return false; // null pointer
uint8_t tbl[256];
size_t n = 0;
uint8_t n = 0;
CppCore::bytedup(0xFF, tbl);
while (const char c = *alphabet++)
tbl[c] = (uint8_t)n++;
tbl[c] = n++;
if (n < 2U) CPPCORE_UNLIKELY
return false; // alphabet too short
if (const char first = *input++) CPPCORE_LIKELY
Expand All @@ -262,7 +262,7 @@ namespace CppCore
if (t.of != 0U) CPPCORE_UNLIKELY
return false; // mul overflow
uint8_t carry = 0;
CppCore::addcarry(t.v, (size_t)idx, r, carry);
CppCore::addcarry(t.v, idx, r, carry);
if (carry != 0) CPPCORE_UNLIKELY
return false; // add overflow
}
Expand Down
66 changes: 61 additions & 5 deletions include/CppCore/Math/Util.h
Original file line number Diff line number Diff line change
Expand Up @@ -639,8 +639,8 @@ namespace CppCore
template<typename UINT1, typename UINT2, typename UINT3>
INLINE static void addcarry(const UINT1& x, const UINT2& y, UINT3& z, uint8_t& c)
{
static_assert(sizeof(UINT1) % 4 == 0);
static_assert(sizeof(UINT2) % 4 == 0);
static_assert(sizeof(UINT1) % 4 == 0 || sizeof(UINT1) < sizeof(size_t));
static_assert(sizeof(UINT2) % 4 == 0 || sizeof(UINT2) < sizeof(size_t));
static_assert(sizeof(UINT3) % 4 == 0);
constexpr size_t MAXSIZE = MAX(sizeof(UINT1), sizeof(UINT2));
constexpr size_t MINSIZE = MIN(sizeof(UINT1), sizeof(UINT2));
Expand All @@ -663,8 +663,11 @@ namespace CppCore
for (size_t i = NMIN; i < NUINT2; i++)
CppCore::addcarry64(0ULL, py[i], pz[i], c);
}
else
else if
#else
if
#endif
constexpr (sizeof(UINT1) % 4 == 0 && sizeof(UINT2) % 4 == 0 && sizeof(UINT3) % 4 == 0)
{
constexpr size_t NUINT1 = sizeof(UINT1) / 4;
constexpr size_t NUINT2 = sizeof(UINT2) / 4;
Expand All @@ -681,6 +684,9 @@ namespace CppCore
for (size_t i = NMIN; i < NUINT2; i++)
CppCore::addcarry32(0U, py[i], pz[i], c);
}
else if constexpr (sizeof(UINT1) < sizeof(size_t)) { addcarry<size_t, UINT2, UINT3>((size_t)x, y, z, c); }
else if constexpr (sizeof(UINT2) < sizeof(size_t)) { addcarry<UINT1, size_t, UINT3>(x, (size_t)y, z, c); }
else throw;
}

/// <summary>
Expand All @@ -691,6 +697,14 @@ namespace CppCore
CppCore::addcarry8(x, y, r, c);
}

/// <summary>
/// Template Specialization for 16+8=16
/// </summary>
template<> INLINE void addcarry(const uint16_t& x, const uint8_t& y, uint16_t& r, uint8_t& c)
{
CppCore::addcarry16(x, y, r, c);
}

/// <summary>
/// Template Specialization for 16+16=16
/// </summary>
Expand All @@ -699,6 +713,22 @@ namespace CppCore
CppCore::addcarry16(x, y, r, c);
}

/// <summary>
/// Template Specialization for 32+8=32
/// </summary>
template<> INLINE void addcarry(const uint32_t& x, const uint8_t& y, uint32_t& r, uint8_t& c)
{
CppCore::addcarry32(x, y, r, c);
}

/// <summary>
/// Template Specialization for 32+16=32
/// </summary>
template<> INLINE void addcarry(const uint32_t& x, const uint16_t& y, uint32_t& r, uint8_t& c)
{
CppCore::addcarry32(x, y, r, c);
}

/// <summary>
/// Template Specialization for 32+32=32
/// </summary>
Expand All @@ -707,6 +737,30 @@ namespace CppCore
CppCore::addcarry32(x, y, r, c);
}

/// <summary>
/// Template Specialization for 64+8=64
/// </summary>
template<> INLINE void addcarry(const uint64_t& x, const uint8_t& y, uint64_t& r, uint8_t& c)
{
CppCore::addcarry64(x, y, r, c);
}

/// <summary>
/// Template Specialization for 64+16=64
/// </summary>
template<> INLINE void addcarry(const uint64_t& x, const uint16_t& y, uint64_t& r, uint8_t& c)
{
CppCore::addcarry64(x, y, r, c);
}

/// <summary>
/// Template Specialization for 64+32=64
/// </summary>
template<> INLINE void addcarry(const uint64_t& x, const uint32_t& y, uint64_t& r, uint8_t& c)
{
CppCore::addcarry64(x, y, r, c);
}

/// <summary>
/// Template Specialization for 64+64=64
/// </summary>
Expand Down Expand Up @@ -768,8 +822,10 @@ namespace CppCore
template<typename UINT1, typename UINT2, typename UINT3>
INLINE static void uadd(const UINT1& x, const UINT2& y, UINT3& r)
{
uint8_t c = 0;
CppCore::addcarry(x, y, r, c);
if constexpr (sizeof(UINT1) < sizeof(size_t)) { CppCore::uadd((size_t)x, y, r); }
else if constexpr (sizeof(UINT2) < sizeof(size_t)) { CppCore::uadd(x, (size_t)y, r); }
else if constexpr (sizeof(UINT3) < sizeof(size_t)) { size_t t; CppCore::uadd(x, y, t); r = (UINT3)t; }
else { uint8_t c = 0; CppCore::addcarry(x, y, r, c); }
}

/// <summary>
Expand Down
10 changes: 10 additions & 0 deletions src/CppCore.Test/Test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,16 @@ int main()
TEST(CppCore::Test::Encoding::BaseX::tostring16, "tostring16: ", std::endl);
TEST(CppCore::Test::Encoding::BaseX::tostring32, "tostring32: ", std::endl);
TEST(CppCore::Test::Encoding::BaseX::tostring64, "tostring64: ", std::endl);
TEST(CppCore::Test::Encoding::BaseX::parse8, "parse8: ", std::endl);
TEST(CppCore::Test::Encoding::BaseX::parse16, "parse16: ", std::endl);
TEST(CppCore::Test::Encoding::BaseX::parse32, "parse32: ", std::endl);
TEST(CppCore::Test::Encoding::BaseX::parse64, "parse64: ", std::endl);
TEST(CppCore::Test::Encoding::BaseX::parse128, "parse128: ", std::endl);
TEST(CppCore::Test::Encoding::BaseX::tryparse8, "tryparse8: ", std::endl);
TEST(CppCore::Test::Encoding::BaseX::tryparse16, "tryparse16: ", std::endl);
TEST(CppCore::Test::Encoding::BaseX::tryparse32, "tryparse32: ", std::endl);
TEST(CppCore::Test::Encoding::BaseX::tryparse64, "tryparse64: ", std::endl);
TEST(CppCore::Test::Encoding::BaseX::tryparse128,"tryparse128:", std::endl);

std::cout << "-------------------------------" << std::endl;
std::cout << " CppCore::Encoding::Decimal " << std::endl;
Expand Down

0 comments on commit cd0559b

Please sign in to comment.