From b27123bf48ca83c1a519dc078a46bd79f0f841d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 17 Aug 2019 11:18:11 +0200 Subject: [PATCH 01/14] intx: Restrict be::store to arrays of matching size only --- include/intx/intx.hpp | 5 +++-- test/unittests/test_intx.cpp | 11 +++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 1d00e8a7..6b340db9 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -1000,10 +1000,11 @@ inline intx::uint uint(const uint8_t bytes[sizeof(intx::uint)]) noexcept constexpr auto uint256 = uint<256>; constexpr auto uint512 = uint<512>; +/// Stores an uint value in a bytes array in big-endian order. template -inline void store(uint8_t* dst, const intx::uint& x) noexcept +inline void store(uint8_t (&dst)[N / 8], const intx::uint& x) noexcept { - auto d = bswap(x); + const auto d = bswap(x); std::memcpy(dst, &d, sizeof(d)); } diff --git a/test/unittests/test_intx.cpp b/test/unittests/test_intx.cpp index 86e46cb3..574b6db7 100644 --- a/test/unittests/test_intx.cpp +++ b/test/unittests/test_intx.cpp @@ -450,6 +450,17 @@ TYPED_TEST(uint_test, endianness) EXPECT_EQ(be::uint(data), x); } +TYPED_TEST(uint_test, be_store) +{ + const auto x = TypeParam{0x0201}; + uint8_t data[sizeof(x)]; + be::store(data, x); + EXPECT_EQ(data[sizeof(x) - 1], 1); + EXPECT_EQ(data[sizeof(x) - 2], 2); + EXPECT_EQ(data[sizeof(x) - 3], 0); + EXPECT_EQ(data[0], 0); +} + TYPED_TEST(uint_test, convert_to_bool) { EXPECT_TRUE((TypeParam{1, 0})); From 873b827048853ebd6d88ae326f0ed87a9ddfee38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 17 Aug 2019 11:25:02 +0200 Subject: [PATCH 02/14] intx: Add be::trunc() function --- include/intx/intx.hpp | 13 +++++++++++++ test/unittests/test_intx.cpp | 10 ++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 6b340db9..4f906fc0 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -1008,6 +1008,19 @@ inline void store(uint8_t (&dst)[N / 8], const intx::uint& x) noexcept std::memcpy(dst, &d, sizeof(d)); } +/// Stores the truncated value of an uint in a bytes array. +/// Only the least significant bytes from big-endian representation of the uint +/// are stored in the result bytes array up to array's size. +template +inline void trunc(uint8_t (&dst)[M], const intx::uint& x) noexcept +{ + static_assert(M < N / 8, "destination must be smaller than the source value"); + const auto d = bswap(x); + const auto b = as_bytes(d); + std::memcpy(dst, &b[sizeof(d) - M], M); +} + + } // namespace be } // namespace intx diff --git a/test/unittests/test_intx.cpp b/test/unittests/test_intx.cpp index 574b6db7..4e6576ac 100644 --- a/test/unittests/test_intx.cpp +++ b/test/unittests/test_intx.cpp @@ -461,6 +461,16 @@ TYPED_TEST(uint_test, be_store) EXPECT_EQ(data[0], 0); } +TYPED_TEST(uint_test, be_trunc) +{ + constexpr auto x = TypeParam{0xee48656c6c6f20536f6c617269732121_u128}; + uint8_t out[15]; + be::trunc(out, x); + const auto str = std::string{reinterpret_cast(out), sizeof(out)}; + EXPECT_EQ(str, "Hello Solaris!!"); +} + + TYPED_TEST(uint_test, convert_to_bool) { EXPECT_TRUE((TypeParam{1, 0})); From b74653c5144b965826b4fc386c130303a2a2b395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 17 Aug 2019 12:04:34 +0200 Subject: [PATCH 03/14] int128: Add num_bits constant to uint<128> type --- include/intx/int128.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/intx/int128.hpp b/include/intx/int128.hpp index 09ca408f..74d339e0 100644 --- a/include/intx/int128.hpp +++ b/include/intx/int128.hpp @@ -28,6 +28,8 @@ struct uint; template <> struct uint<128> { + static constexpr unsigned num_bits = 128; + uint64_t lo = 0; uint64_t hi = 0; From 10dc3bf9f3c0ff8517a3dc09bc69590b74b9ba59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 17 Aug 2019 12:05:14 +0200 Subject: [PATCH 04/14] intx: Add support for zext to be::uint<> --- include/intx/intx.hpp | 12 +++++++----- test/unittests/test_intx.cpp | 17 +++++++++++++++++ test/unittests/test_intx_api.cpp | 2 -- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 4f906fc0..c105ee19 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -990,15 +990,17 @@ inline void store(uint8_t* dst, const intx::uint& x) noexcept namespace be // Conversions to/from BE bytes. { -template -inline intx::uint uint(const uint8_t bytes[sizeof(intx::uint)]) noexcept +/// Loads an uint value from bytes of big-endian order. +/// If the size of bytes is smaller than the result uint, the value is zero-extended. +template +inline intx::uint uint(const uint8_t (&bytes)[M]) noexcept { + static_assert( + M <= N / 8, "the size of source bytes must not exceed the size of the destination uint"); auto x = intx::uint{}; - std::memcpy(&x, bytes, sizeof(x)); + std::memcpy(&as_bytes(x)[N / 8 - M], bytes, M); return bswap(x); } -constexpr auto uint256 = uint<256>; -constexpr auto uint512 = uint<512>; /// Stores an uint value in a bytes array in big-endian order. template diff --git a/test/unittests/test_intx.cpp b/test/unittests/test_intx.cpp index 4e6576ac..da5e358b 100644 --- a/test/unittests/test_intx.cpp +++ b/test/unittests/test_intx.cpp @@ -450,6 +450,23 @@ TYPED_TEST(uint_test, endianness) EXPECT_EQ(be::uint(data), x); } +TYPED_TEST(uint_test, be_zext) +{ + uint8_t data[] = {0x01, 0x02, 0x03}; + const auto x = be::uint(data); + EXPECT_EQ(x, 0x010203); +} + +TYPED_TEST(uint_test, be_load) +{ + constexpr auto size = sizeof(TypeParam); + uint8_t data[size]{}; + data[0] = 0x80; + data[size-1] = 1; + const auto x = be::uint(data); + EXPECT_EQ(x, (TypeParam{1} << (TypeParam::num_bits - 1)) | 1); +} + TYPED_TEST(uint_test, be_store) { const auto x = TypeParam{0x0201}; diff --git a/test/unittests/test_intx_api.cpp b/test/unittests/test_intx_api.cpp index d39e401a..a99846b8 100644 --- a/test/unittests/test_intx_api.cpp +++ b/test/unittests/test_intx_api.cpp @@ -8,8 +8,6 @@ using namespace intx; -static_assert(&be::uint<256> == be::uint256, "wrong alias: be::uint256"); -static_assert(&be::uint<512> == be::uint512, "wrong alias: be::uint512"); static_assert(&le::uint<256> == le::uint256, "wrong alias: le::uint256"); static_assert(&le::uint<512> == le::uint512, "wrong alias: le::uint512"); From f7d60228f12589f2e54e3d5838e38b817c06efb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 17 Aug 2019 12:08:03 +0200 Subject: [PATCH 05/14] intx: Restrict size of bytes arrays in LE API --- include/intx/intx.hpp | 6 ++---- test/unittests/test_intx_api.cpp | 3 --- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index c105ee19..feddaee3 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -970,17 +970,15 @@ constexpr uint512 operator"" _u512(const char* s) noexcept namespace le // Conversions to/from LE bytes. { template -inline intx::uint uint(const uint8_t bytes[sizeof(intx::uint)]) noexcept +inline intx::uint uint(const uint8_t (&bytes)[N / 8]) noexcept { auto x = intx::uint{}; std::memcpy(&x, bytes, sizeof(x)); return x; } -constexpr auto uint256 = uint<256>; -constexpr auto uint512 = uint<512>; template -inline void store(uint8_t* dst, const intx::uint& x) noexcept +inline void store(uint8_t (&dst)[N / 8], const intx::uint& x) noexcept { std::memcpy(dst, &x, sizeof(x)); } diff --git a/test/unittests/test_intx_api.cpp b/test/unittests/test_intx_api.cpp index a99846b8..ddbee069 100644 --- a/test/unittests/test_intx_api.cpp +++ b/test/unittests/test_intx_api.cpp @@ -8,9 +8,6 @@ using namespace intx; -static_assert(&le::uint<256> == le::uint256, "wrong alias: le::uint256"); -static_assert(&le::uint<512> == le::uint512, "wrong alias: le::uint512"); - static_assert(uint128{2} + uint128{2} == 4, ""); static_assert(uint256{2} + uint256{2} == 4, ""); static_assert(uint512{2} + uint512{2} == 4, ""); From b91e2dc7217e55a8cf4a2d5758827c51d8546929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 17 Aug 2019 12:23:52 +0200 Subject: [PATCH 06/14] intx: Add typed variant of be::store() --- include/intx/intx.hpp | 10 ++++++++++ test/unittests/test_intx.cpp | 15 ++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index feddaee3..6efd60c0 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -1008,6 +1008,16 @@ inline void store(uint8_t (&dst)[N / 8], const intx::uint& x) noexcept std::memcpy(dst, &d, sizeof(d)); } +/// Stores an uint value in .bytes field of type T. The .bytes must be an array of uint8_t +/// of the size matching the size of uint. +template +inline T store(const intx::uint& x) noexcept +{ + T r{}; + store(r.bytes, x); + return r; +} + /// Stores the truncated value of an uint in a bytes array. /// Only the least significant bytes from big-endian representation of the uint /// are stored in the result bytes array up to array's size. diff --git a/test/unittests/test_intx.cpp b/test/unittests/test_intx.cpp index da5e358b..ccdae289 100644 --- a/test/unittests/test_intx.cpp +++ b/test/unittests/test_intx.cpp @@ -462,7 +462,7 @@ TYPED_TEST(uint_test, be_load) constexpr auto size = sizeof(TypeParam); uint8_t data[size]{}; data[0] = 0x80; - data[size-1] = 1; + data[size - 1] = 1; const auto x = be::uint(data); EXPECT_EQ(x, (TypeParam{1} << (TypeParam::num_bits - 1)) | 1); } @@ -487,6 +487,19 @@ TYPED_TEST(uint_test, be_trunc) EXPECT_EQ(str, "Hello Solaris!!"); } +template +struct storage +{ + uint8_t bytes[M]; +}; + +TYPED_TEST(uint_test, typed_store) +{ + const auto x = TypeParam{2}; + const auto s = be::store>(x); + EXPECT_EQ(s.bytes[sizeof(x) - 1], 2); +} + TYPED_TEST(uint_test, convert_to_bool) { From 3a99e8aa1d88e40f31cf70f730024d1e51a4b44c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 17 Aug 2019 12:34:23 +0200 Subject: [PATCH 07/14] intx: Add typed variant of be::trunc() --- include/intx/intx.hpp | 9 +++++++++ test/unittests/test_intx.cpp | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 6efd60c0..0ca7350a 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -1030,6 +1030,15 @@ inline void trunc(uint8_t (&dst)[M], const intx::uint& x) noexcept std::memcpy(dst, &b[sizeof(d) - M], M); } +/// Stores the truncated value of an uint in the .bytes field of an object of type T. +template +inline T trunc(const intx::uint& x) noexcept +{ + T r{}; + trunc(r.bytes, x); + return r; +} + } // namespace be diff --git a/test/unittests/test_intx.cpp b/test/unittests/test_intx.cpp index ccdae289..3659df53 100644 --- a/test/unittests/test_intx.cpp +++ b/test/unittests/test_intx.cpp @@ -500,6 +500,16 @@ TYPED_TEST(uint_test, typed_store) EXPECT_EQ(s.bytes[sizeof(x) - 1], 2); } +TYPED_TEST(uint_test, typed_trunc) +{ + const auto x = TypeParam{0xaabb}; + const auto s = be::trunc>(x); + EXPECT_EQ(s.bytes[8], 0xbb); + EXPECT_EQ(s.bytes[7], 0xaa); + EXPECT_EQ(s.bytes[6], 0); + EXPECT_EQ(s.bytes[0], 0); +} + TYPED_TEST(uint_test, convert_to_bool) { From d30d3ad31e706e14235375b3f1bbd0cfb7f43866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 17 Aug 2019 12:54:33 +0200 Subject: [PATCH 08/14] intx: Add typed variant of be::uint<>() --- include/intx/intx.hpp | 6 ++++++ test/unittests/test_intx.cpp | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 0ca7350a..32e97e2e 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -1000,6 +1000,12 @@ inline intx::uint uint(const uint8_t (&bytes)[M]) noexcept return bswap(x); } +template +inline intx::uint uint(const T& t) noexcept +{ + return uint(t.bytes); +} + /// Stores an uint value in a bytes array in big-endian order. template inline void store(uint8_t (&dst)[N / 8], const intx::uint& x) noexcept diff --git a/test/unittests/test_intx.cpp b/test/unittests/test_intx.cpp index 3659df53..a41c4f5e 100644 --- a/test/unittests/test_intx.cpp +++ b/test/unittests/test_intx.cpp @@ -510,6 +510,20 @@ TYPED_TEST(uint_test, typed_trunc) EXPECT_EQ(s.bytes[0], 0); } +TYPED_TEST(uint_test, typed_zext) +{ + const auto s = storage<1>({0xed}); + const auto x = be::uint(s); + EXPECT_EQ(x, 0xed); +} + +TYPED_TEST(uint_test, typed_load) +{ + const auto s = storage({0x88}); + const auto x = be::uint(s); + EXPECT_EQ(x, TypeParam{0x88} << (TypeParam::num_bits - 8)); +} + TYPED_TEST(uint_test, convert_to_bool) { From 1b4c7b8dd9d64affc2ad7c615a01a2b70baaf9df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 17 Aug 2019 13:17:14 +0200 Subject: [PATCH 09/14] intx: Bring back the unsafe variants of store() and unit() in BE API --- include/intx/intx.hpp | 20 ++++++++++++++++++++ test/unittests/test_intx.cpp | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 32e97e2e..4703630b 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -1006,6 +1006,16 @@ inline intx::uint uint(const T& t) noexcept return uint(t.bytes); } +/// Loads an uint value from a buffer. The user must make sure +/// that the provided buffer is big enough. Therefore marked "unsafe". +template +inline intx::uint uint_unsafe(const uint8_t* bytes) noexcept +{ + auto x = intx::uint{}; + std::memcpy(&x, bytes, sizeof(x)); + return bswap(x); +} + /// Stores an uint value in a bytes array in big-endian order. template inline void store(uint8_t (&dst)[N / 8], const intx::uint& x) noexcept @@ -1045,6 +1055,16 @@ inline T trunc(const intx::uint& x) noexcept return r; } +/// Stores an uint value at the provided pointer in big-endian order. The user must make sure +/// that the provided buffer is big enough to fit the value. Therefore marked "unsafe". +template +inline void store_unsafe(uint8_t* dst, const intx::uint& x) noexcept +{ + const auto d = bswap(x); + std::memcpy(dst, &d, sizeof(d)); +} + + } // namespace be diff --git a/test/unittests/test_intx.cpp b/test/unittests/test_intx.cpp index a41c4f5e..2f952d40 100644 --- a/test/unittests/test_intx.cpp +++ b/test/unittests/test_intx.cpp @@ -448,6 +448,11 @@ TYPED_TEST(uint_test, endianness) EXPECT_EQ(data[0], 0); EXPECT_EQ(data[s - 1], 1); EXPECT_EQ(be::uint(data), x); + + be::store_unsafe(data, x); + EXPECT_EQ(data[0], 0); + EXPECT_EQ(data[s - 1], 1); + EXPECT_EQ(be::uint_unsafe(data), x); } TYPED_TEST(uint_test, be_zext) From d2aa12cf40189e8f6b56b4e64f7555cf886245e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 19 Aug 2019 22:00:16 +0200 Subject: [PATCH 10/14] intx: Rename be::uint -> be::load --- include/intx/intx.hpp | 6 +++--- test/unittests/test_intx.cpp | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 4703630b..88fe6ce6 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -991,7 +991,7 @@ namespace be // Conversions to/from BE bytes. /// Loads an uint value from bytes of big-endian order. /// If the size of bytes is smaller than the result uint, the value is zero-extended. template -inline intx::uint uint(const uint8_t (&bytes)[M]) noexcept +inline intx::uint load(const uint8_t (&bytes)[M]) noexcept { static_assert( M <= N / 8, "the size of source bytes must not exceed the size of the destination uint"); @@ -1001,9 +1001,9 @@ inline intx::uint uint(const uint8_t (&bytes)[M]) noexcept } template -inline intx::uint uint(const T& t) noexcept +inline intx::uint load(const T& t) noexcept { - return uint(t.bytes); + return load(t.bytes); } /// Loads an uint value from a buffer. The user must make sure diff --git a/test/unittests/test_intx.cpp b/test/unittests/test_intx.cpp index 2f952d40..fb13d663 100644 --- a/test/unittests/test_intx.cpp +++ b/test/unittests/test_intx.cpp @@ -447,7 +447,7 @@ TYPED_TEST(uint_test, endianness) be::store(data, x); EXPECT_EQ(data[0], 0); EXPECT_EQ(data[s - 1], 1); - EXPECT_EQ(be::uint(data), x); + EXPECT_EQ(be::load(data), x); be::store_unsafe(data, x); EXPECT_EQ(data[0], 0); @@ -458,7 +458,7 @@ TYPED_TEST(uint_test, endianness) TYPED_TEST(uint_test, be_zext) { uint8_t data[] = {0x01, 0x02, 0x03}; - const auto x = be::uint(data); + const auto x = be::load(data); EXPECT_EQ(x, 0x010203); } @@ -468,7 +468,7 @@ TYPED_TEST(uint_test, be_load) uint8_t data[size]{}; data[0] = 0x80; data[size - 1] = 1; - const auto x = be::uint(data); + const auto x = be::load(data); EXPECT_EQ(x, (TypeParam{1} << (TypeParam::num_bits - 1)) | 1); } @@ -515,17 +515,17 @@ TYPED_TEST(uint_test, typed_trunc) EXPECT_EQ(s.bytes[0], 0); } -TYPED_TEST(uint_test, typed_zext) +TYPED_TEST(uint_test, typed_load_zext) { const auto s = storage<1>({0xed}); - const auto x = be::uint(s); + const auto x = be::load(s); EXPECT_EQ(x, 0xed); } TYPED_TEST(uint_test, typed_load) { const auto s = storage({0x88}); - const auto x = be::uint(s); + const auto x = be::load(s); EXPECT_EQ(x, TypeParam{0x88} << (TypeParam::num_bits - 8)); } From a91639233ab5558e8c3e8e06a4634c92113c3279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 19 Aug 2019 22:34:00 +0200 Subject: [PATCH 11/14] intx: Use load instead of load --- include/intx/intx.hpp | 24 ++++++++++++------------ test/unittests/test_intx.cpp | 12 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 88fe6ce6..0d21782c 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -990,28 +990,28 @@ namespace be // Conversions to/from BE bytes. { /// Loads an uint value from bytes of big-endian order. /// If the size of bytes is smaller than the result uint, the value is zero-extended. -template -inline intx::uint load(const uint8_t (&bytes)[M]) noexcept +template +inline IntT load(const uint8_t (&bytes)[M]) noexcept { - static_assert( - M <= N / 8, "the size of source bytes must not exceed the size of the destination uint"); - auto x = intx::uint{}; - std::memcpy(&as_bytes(x)[N / 8 - M], bytes, M); + static_assert(M <= IntT::num_bits / 8, + "the size of source bytes must not exceed the size of the destination uint"); + auto x = IntT{}; + std::memcpy(&as_bytes(x)[IntT::num_bits / 8 - M], bytes, M); return bswap(x); } -template -inline intx::uint load(const T& t) noexcept +template +inline IntT load(const T& t) noexcept { - return load(t.bytes); + return load(t.bytes); } /// Loads an uint value from a buffer. The user must make sure /// that the provided buffer is big enough. Therefore marked "unsafe". -template -inline intx::uint uint_unsafe(const uint8_t* bytes) noexcept +template +inline IntT unsafe_load(const uint8_t* bytes) noexcept { - auto x = intx::uint{}; + auto x = IntT{}; std::memcpy(&x, bytes, sizeof(x)); return bswap(x); } diff --git a/test/unittests/test_intx.cpp b/test/unittests/test_intx.cpp index fb13d663..e7a5a0ff 100644 --- a/test/unittests/test_intx.cpp +++ b/test/unittests/test_intx.cpp @@ -447,18 +447,18 @@ TYPED_TEST(uint_test, endianness) be::store(data, x); EXPECT_EQ(data[0], 0); EXPECT_EQ(data[s - 1], 1); - EXPECT_EQ(be::load(data), x); + EXPECT_EQ(be::load(data), x); be::store_unsafe(data, x); EXPECT_EQ(data[0], 0); EXPECT_EQ(data[s - 1], 1); - EXPECT_EQ(be::uint_unsafe(data), x); + EXPECT_EQ(be::unsafe_load(data), x); } TYPED_TEST(uint_test, be_zext) { uint8_t data[] = {0x01, 0x02, 0x03}; - const auto x = be::load(data); + const auto x = be::load(data); EXPECT_EQ(x, 0x010203); } @@ -468,7 +468,7 @@ TYPED_TEST(uint_test, be_load) uint8_t data[size]{}; data[0] = 0x80; data[size - 1] = 1; - const auto x = be::load(data); + const auto x = be::load(data); EXPECT_EQ(x, (TypeParam{1} << (TypeParam::num_bits - 1)) | 1); } @@ -518,14 +518,14 @@ TYPED_TEST(uint_test, typed_trunc) TYPED_TEST(uint_test, typed_load_zext) { const auto s = storage<1>({0xed}); - const auto x = be::load(s); + const auto x = be::load(s); EXPECT_EQ(x, 0xed); } TYPED_TEST(uint_test, typed_load) { const auto s = storage({0x88}); - const auto x = be::load(s); + const auto x = be::load(s); EXPECT_EQ(x, TypeParam{0x88} << (TypeParam::num_bits - 8)); } From 37634a8539f104a2c6b8ff8581a6f73a26028263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 19 Aug 2019 22:43:52 +0200 Subject: [PATCH 12/14] intx: Pull unsafe store()/load() into intx::be::unsafe namespace --- include/intx/intx.hpp | 27 ++++++++++++++------------- test/unittests/test_intx.cpp | 4 ++-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 0d21782c..89d051d8 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -1006,16 +1006,6 @@ inline IntT load(const T& t) noexcept return load(t.bytes); } -/// Loads an uint value from a buffer. The user must make sure -/// that the provided buffer is big enough. Therefore marked "unsafe". -template -inline IntT unsafe_load(const uint8_t* bytes) noexcept -{ - auto x = IntT{}; - std::memcpy(&x, bytes, sizeof(x)); - return bswap(x); -} - /// Stores an uint value in a bytes array in big-endian order. template inline void store(uint8_t (&dst)[N / 8], const intx::uint& x) noexcept @@ -1055,16 +1045,27 @@ inline T trunc(const intx::uint& x) noexcept return r; } +namespace unsafe +{ +/// Loads an uint value from a buffer. The user must make sure +/// that the provided buffer is big enough. Therefore marked "unsafe". +template +inline IntT load(const uint8_t* bytes) noexcept +{ + auto x = IntT{}; + std::memcpy(&x, bytes, sizeof(x)); + return bswap(x); +} + /// Stores an uint value at the provided pointer in big-endian order. The user must make sure /// that the provided buffer is big enough to fit the value. Therefore marked "unsafe". template -inline void store_unsafe(uint8_t* dst, const intx::uint& x) noexcept +inline void store(uint8_t* dst, const intx::uint& x) noexcept { const auto d = bswap(x); std::memcpy(dst, &d, sizeof(d)); } - - +} // namespace unsafe } // namespace be diff --git a/test/unittests/test_intx.cpp b/test/unittests/test_intx.cpp index e7a5a0ff..b570ae51 100644 --- a/test/unittests/test_intx.cpp +++ b/test/unittests/test_intx.cpp @@ -449,10 +449,10 @@ TYPED_TEST(uint_test, endianness) EXPECT_EQ(data[s - 1], 1); EXPECT_EQ(be::load(data), x); - be::store_unsafe(data, x); + be::unsafe::store(data, x); EXPECT_EQ(data[0], 0); EXPECT_EQ(data[s - 1], 1); - EXPECT_EQ(be::unsafe_load(data), x); + EXPECT_EQ(be::unsafe::load(data), x); } TYPED_TEST(uint_test, be_zext) From a1a2beb81a02992784450a57469df4c5cf483e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 19 Aug 2019 22:53:39 +0200 Subject: [PATCH 13/14] intx: Change le::uint() to le::load() --- include/intx/intx.hpp | 8 +++++--- test/unittests/test_intx.cpp | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 89d051d8..c78a84bb 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -969,10 +969,12 @@ constexpr uint512 operator"" _u512(const char* s) noexcept namespace le // Conversions to/from LE bytes. { -template -inline intx::uint uint(const uint8_t (&bytes)[N / 8]) noexcept +template +inline IntT load(const uint8_t (&bytes)[M]) noexcept { - auto x = intx::uint{}; + static_assert(M == IntT::num_bits / 8, + "the size of source bytes must match the size of the destination uint"); + auto x = IntT{}; std::memcpy(&x, bytes, sizeof(x)); return x; } diff --git a/test/unittests/test_intx.cpp b/test/unittests/test_intx.cpp index b570ae51..01493028 100644 --- a/test/unittests/test_intx.cpp +++ b/test/unittests/test_intx.cpp @@ -442,7 +442,7 @@ TYPED_TEST(uint_test, endianness) le::store(data, x); EXPECT_EQ(data[0], 1); EXPECT_EQ(data[s - 1], 0); - EXPECT_EQ(le::uint(data), x); + EXPECT_EQ(le::load(data), x); be::store(data, x); EXPECT_EQ(data[0], 0); From 5c5982e78de7cd0aff1a8da94b1bd1ab124010e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 20 Aug 2019 12:35:52 +0200 Subject: [PATCH 14/14] Update CHANGELOG --- CHANGELOG.md | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 585d3ebe..ccc0958d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,17 +6,34 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic Versioning]. +## [0.4.0] - unreleased + +### Added + +- Added the `as_bytes()` casting helper. + [[#106](https://github.com/chfast/intx/pull/106)] + +### Changed + +- The endian-specific API for converting intx types to/from bytes has been reworked. + [[#107](https://github.com/chfast/intx/pull/107)] + + ## [0.3.0] - 2019-06-20 + ### Added -- New `addmod()` and `mulmod()` procedures have been added for the `uint256` type - ([#101](https://github.com/chfast/intx/pull/101)). +- New `addmod()` and `mulmod()` procedures have been added for the `uint256` type. + [[#101](https://github.com/chfast/intx/pull/101)] + ### Changed -- Pedantic compiler warnings have been fixed - ([#98](https://github.com/chfast/intx/pull/98)). +- Pedantic compiler warnings have been fixed. + [[#98](https://github.com/chfast/intx/pull/98)] - Performance of the division algorithm increased up to 40% - when dividing 256-bit values by 128-bit and 64-bit ones - ([#99](https://github.com/chfast/intx/pull/99)). + when dividing 256-bit values by 128-bit and 64-bit ones. + [[#99](https://github.com/chfast/intx/pull/99)] + +[0.4.0]: https://github.com/chfast/intx/compare/v0.3.0...master [0.3.0]: https://github.com/chfast/intx/releases/v0.2.0 [Keep a Changelog]: https://keepachangelog.com/en/1.0.0/