diff --git a/Makefile.am b/Makefile.am index ba22eb6817..6f107dc3ea 100755 --- a/Makefile.am +++ b/Makefile.am @@ -301,10 +301,6 @@ test_libbitcoin_system_test_SOURCES = \ test/hash/sha/sha256.cpp \ test/hash/sha/sha512.cpp \ test/hash/sha/vectorization.cpp \ - test/hash/sha/clone/algorithm.hpp \ - test/hash/sha/clone/algorithm.ipp \ - test/hash/sha/clone/algorithm_compression.ipp \ - test/hash/sha/clone/algorithm_vectorization.ipp \ test/intrinsics/haves.cpp \ test/intrinsics/intrinsics.cpp \ test/intrinsics/xcpu/cpuid.cpp \ @@ -343,9 +339,9 @@ test_libbitcoin_system_test_SOURCES = \ test/stream/devices/copy_source.cpp \ test/stream/devices/flip_sink.cpp \ test/stream/devices/push_sink.cpp \ - test/stream/simple/iostream.cpp \ - test/stream/simple/istream.cpp \ - test/stream/simple/ostream.cpp \ + test/stream/iostream/iostream.cpp \ + test/stream/iostream/istream.cpp \ + test/stream/iostream/ostream.cpp \ test/stream/streamers/bit_flipper.cpp \ test/stream/streamers/bit_reader.cpp \ test/stream/streamers/bit_writer.cpp \ @@ -647,10 +643,11 @@ include_bitcoin_system_impl_streamdir = ${includedir}/bitcoin/system/impl/stream include_bitcoin_system_impl_stream_HEADERS = \ include/bitcoin/system/impl/stream/device.ipp -include_bitcoin_system_impl_stream_simpledir = ${includedir}/bitcoin/system/impl/stream/simple -include_bitcoin_system_impl_stream_simple_HEADERS = \ - include/bitcoin/system/impl/stream/simple/istream.ipp \ - include/bitcoin/system/impl/stream/simple/ostream.ipp +include_bitcoin_system_impl_stream_iostreamdir = ${includedir}/bitcoin/system/impl/stream/iostream +include_bitcoin_system_impl_stream_iostream_HEADERS = \ + include/bitcoin/system/impl/stream/iostream/iostream.ipp \ + include/bitcoin/system/impl/stream/iostream/istream.ipp \ + include/bitcoin/system/impl/stream/iostream/ostream.ipp include_bitcoin_system_impl_stream_streamersdir = ${includedir}/bitcoin/system/impl/stream/streamers include_bitcoin_system_impl_stream_streamers_HEADERS = \ @@ -741,6 +738,7 @@ include_bitcoin_system_streamdir = ${includedir}/bitcoin/system/stream include_bitcoin_system_stream_HEADERS = \ include/bitcoin/system/stream/binary.hpp \ include/bitcoin/system/stream/device.hpp \ + include/bitcoin/system/stream/iostream.hpp \ include/bitcoin/system/stream/make_stream.hpp \ include/bitcoin/system/stream/make_streamer.hpp \ include/bitcoin/system/stream/stream.hpp \ @@ -755,12 +753,6 @@ include_bitcoin_system_stream_devices_HEADERS = \ include/bitcoin/system/stream/devices/flip_sink.hpp \ include/bitcoin/system/stream/devices/push_sink.hpp -include_bitcoin_system_stream_simpledir = ${includedir}/bitcoin/system/stream/simple -include_bitcoin_system_stream_simple_HEADERS = \ - include/bitcoin/system/stream/simple/iostream.hpp \ - include/bitcoin/system/stream/simple/istream.hpp \ - include/bitcoin/system/stream/simple/ostream.hpp - include_bitcoin_system_stream_streamersdir = ${includedir}/bitcoin/system/stream/streamers include_bitcoin_system_stream_streamers_HEADERS = \ include/bitcoin/system/stream/streamers/bit_flipper.hpp \ diff --git a/builds/cmake/CMakeLists.txt b/builds/cmake/CMakeLists.txt index 9975fadc7b..5ef9672f14 100644 --- a/builds/cmake/CMakeLists.txt +++ b/builds/cmake/CMakeLists.txt @@ -775,10 +775,6 @@ if (with-tests) "../../test/hash/sha/sha256.cpp" "../../test/hash/sha/sha512.cpp" "../../test/hash/sha/vectorization.cpp" - "../../test/hash/sha/clone/algorithm.hpp" - "../../test/hash/sha/clone/algorithm.ipp" - "../../test/hash/sha/clone/algorithm_compression.ipp" - "../../test/hash/sha/clone/algorithm_vectorization.ipp" "../../test/intrinsics/haves.cpp" "../../test/intrinsics/intrinsics.cpp" "../../test/intrinsics/xcpu/cpuid.cpp" @@ -817,9 +813,9 @@ if (with-tests) "../../test/stream/devices/copy_source.cpp" "../../test/stream/devices/flip_sink.cpp" "../../test/stream/devices/push_sink.cpp" - "../../test/stream/simple/iostream.cpp" - "../../test/stream/simple/istream.cpp" - "../../test/stream/simple/ostream.cpp" + "../../test/stream/iostream/iostream.cpp" + "../../test/stream/iostream/istream.cpp" + "../../test/stream/iostream/ostream.cpp" "../../test/stream/streamers/bit_flipper.cpp" "../../test/stream/streamers/bit_reader.cpp" "../../test/stream/streamers/bit_writer.cpp" diff --git a/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj b/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj index d4870b6541..d1a77d673a 100644 --- a/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj @@ -211,9 +211,9 @@ - - - + + + $(IntDir)test_stream_stream.obj @@ -296,7 +296,6 @@ - @@ -310,9 +309,6 @@ - - - @@ -346,11 +342,6 @@ - - - "$(TargetPath)" --run_test=istream_tests --show_progress=no --build_info=yes - - {39F60708-FF48-4C22-952D-43470866F684} @@ -359,4 +350,4 @@ - \ No newline at end of file + diff --git a/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj.filters index ce8ee07768..0927a3985a 100644 --- a/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj.filters @@ -46,14 +46,11 @@ {51A424A9-2C12-4211-0000-000000000005} - - {51A424A9-2C12-4211-0000-000000000007} - {51A424A9-2C12-4211-0000-000000000008} - {51A424A9-2C12-4211-0000-000000000008} + {51A424A9-2C12-4211-0000-000000000007} {51A424A9-2C12-4211-0000-000000000009} @@ -71,37 +68,37 @@ {51A424A9-2C12-4211-0000-00000000000D} - {51A424A9-2C12-4211-0000-000000000009} + {51A424A9-2C12-4211-0000-000000000008} - - {51A424A9-2C12-4211-0000-000000000010} + + {51A424A9-2C12-4211-0000-000000000009} - {51A424A9-2C12-4211-0000-0000000000A1} + {51A424A9-2C12-4211-0000-000000000010} {51A424A9-2C12-4211-0000-00000000000E} - {51A424A9-2C12-4211-0000-0000000000B1} + {51A424A9-2C12-4211-0000-0000000000A1} {51A424A9-2C12-4211-0000-00000000000F} - {51A424A9-2C12-4211-0000-0000000000C1} + {51A424A9-2C12-4211-0000-0000000000B1} - {51A424A9-2C12-4211-0000-0000000000D1} + {51A424A9-2C12-4211-0000-0000000000C1} - {51A424A9-2C12-4211-0000-0000000000E1} + {51A424A9-2C12-4211-0000-0000000000D1} {51A424A9-2C12-4211-0000-000000000001} - {51A424A9-2C12-4211-0000-0000000000F1} + {51A424A9-2C12-4211-0000-0000000000E1} @@ -468,14 +465,14 @@ src\stream\devices - - src\stream\simple + + src\stream\iostream - - src\stream\simple + + src\stream\iostream - - src\stream\simple + + src\stream\iostream src\stream @@ -671,9 +668,6 @@ src\hash\performance - - src\hash\sha\clone - src\hash @@ -709,15 +703,6 @@ - - src\hash\sha\clone - - - src\hash\sha\clone - - - src\hash\sha\clone - diff --git a/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj b/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj index 19af639a32..619323cece 100644 --- a/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj @@ -407,11 +407,9 @@ + - - - @@ -559,8 +557,9 @@ - - + + + diff --git a/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj.filters index bfb5208f3c..8e504d94c8 100644 --- a/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj.filters @@ -82,7 +82,7 @@ {39F60708-FF48-4C22-0000-000000000010} - + {39F60708-FF48-4C22-0000-0000000000C3} @@ -124,41 +124,38 @@ {39F60708-FF48-4C22-0000-000000000005} - - {39F60708-FF48-4C22-0000-000000000006} - - {39F60708-FF48-4C22-0000-000000000007} + {39F60708-FF48-4C22-0000-000000000006} - {39F60708-FF48-4C22-0000-000000000008} + {39F60708-FF48-4C22-0000-000000000007} {39F60708-FF48-4C22-0000-000000000011} - {39F60708-FF48-4C22-0000-000000000009} + {39F60708-FF48-4C22-0000-000000000008} {39F60708-FF48-4C22-0000-0000000000A2} - {39F60708-FF48-4C22-0000-000000000010} + {39F60708-FF48-4C22-0000-000000000009} - {39F60708-FF48-4C22-0000-000000000011} + {39F60708-FF48-4C22-0000-000000000010} - {39F60708-FF48-4C22-0000-000000000012} + {39F60708-FF48-4C22-0000-000000000011} {39F60708-FF48-4C22-0000-0000000000B2} - {39F60708-FF48-4C22-0000-000000000013} + {39F60708-FF48-4C22-0000-000000000012} - {39F60708-FF48-4C22-0000-0000000000A4} + {39F60708-FF48-4C22-0000-000000000013} {39F60708-FF48-4C22-0000-000000000000} @@ -1100,21 +1097,15 @@ include\bitcoin\system\stream\devices + + include\bitcoin\system\stream + include\bitcoin\system\stream include\bitcoin\system\stream - - include\bitcoin\system\stream\simple - - - include\bitcoin\system\stream\simple - - - include\bitcoin\system\stream\simple - include\bitcoin\system\stream @@ -1552,11 +1543,14 @@ include\bitcoin\system\impl\stream - - include\bitcoin\system\impl\stream\simple + + include\bitcoin\system\impl\stream\iostream + + + include\bitcoin\system\impl\stream\iostream - - include\bitcoin\system\impl\stream\simple + + include\bitcoin\system\impl\stream\iostream include\bitcoin\system\impl\stream\streamers diff --git a/include/bitcoin/system.hpp b/include/bitcoin/system.hpp index ebc9b3020b..687f3f649b 100755 --- a/include/bitcoin/system.hpp +++ b/include/bitcoin/system.hpp @@ -177,6 +177,7 @@ #include #include #include +#include #include #include #include @@ -187,9 +188,6 @@ #include #include #include -#include -#include -#include #include #include #include diff --git a/include/bitcoin/system/hash/sha/algorithm.hpp b/include/bitcoin/system/hash/sha/algorithm.hpp index e49b383b9b..bb04e495f8 100644 --- a/include/bitcoin/system/hash/sha/algorithm.hpp +++ b/include/bitcoin/system/hash/sha/algorithm.hpp @@ -269,10 +269,10 @@ class algorithm const xstate_t& xstate) NOEXCEPT; template = true> - INLINE static void merkle_hash_v_(idigests_t& digests, + INLINE static void merkle_hash_invoke(idigests_t& digests, iblocks_t& blocks) NOEXCEPT; - INLINE static void merkle_hash_v(digests_t& digests) NOEXCEPT; + INLINE static void merkle_hash_dispatch(digests_t& digests) NOEXCEPT; /// Message Schedule (block vectorization). /// ----------------------------------------------------------------------- @@ -285,15 +285,17 @@ class algorithm INLINE static Word extract(xWord a) NOEXCEPT; template - INLINE static void compress_v(state_t& state, + INLINE static void compress_dispatch(state_t& state, const xbuffer_t& xbuffer) NOEXCEPT; template = true> - INLINE static void iterate_v_(state_t& state, iblocks_t& blocks) NOEXCEPT; + INLINE static void iterate_invoke(state_t& state, iblocks_t& blocks) NOEXCEPT; template - INLINE static void iterate_v(state_t& state, const ablocks_t& blocks) NOEXCEPT; - INLINE static void iterate_v(state_t& state, iblocks_t& blocks) NOEXCEPT; + INLINE static void iterate_dispatch(state_t& state, + const ablocks_t& blocks) NOEXCEPT; + INLINE static void iterate_dispatch(state_t& state, + iblocks_t& blocks) NOEXCEPT; /// Message Schedule (sigma vectorization). /// ----------------------------------------------------------------------- @@ -303,17 +305,20 @@ class algorithm auto x6, auto x7, auto x8) NOEXCEPT; template - INLINE static void prepare_v(buffer_t& buffer) NOEXCEPT; - INLINE static void schedule_v(auto& buffer) NOEXCEPT; + INLINE static void prepare_dispatch(buffer_t& buffer) NOEXCEPT; + INLINE static void schedule_invoke(buffer_t& buffer) NOEXCEPT; + INLINE static void schedule_dispatch(auto& buffer) NOEXCEPT; public: static constexpr auto have_x128 = Vectorized && system::with_sse41; static constexpr auto have_x256 = Vectorized && system::with_avx2; static constexpr auto have_x512 = Vectorized && system::with_avx512; - static constexpr auto min_lanes = (have_x128 ? 16 : (have_x256 ? 32 : - (have_x128 ? 64 : 0))) / SHA::word_bytes; - static constexpr auto vectorization = (have_x128 || have_x256 || have_x512) && - !(build_x32 && is_same_size); + static constexpr auto vectorization = (have_x128 || have_x256 || have_x512) + && !(build_x32 && is_same_size); + static constexpr auto min_lanes = + (have_x128 ? bytes<128> : + (have_x256 ? bytes<256> : + (have_x512 ? bytes<512> : 0))) / SHA::word_bytes; }; } // namespace sha diff --git a/include/bitcoin/system/impl/hash/sha/algorithm.ipp b/include/bitcoin/system/impl/hash/sha/algorithm.ipp index 3673eb710a..3cd0429ed3 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm.ipp @@ -573,7 +573,7 @@ schedule(auto& buffer) NOEXCEPT } else if constexpr (vectorization) { - schedule_v(buffer); + schedule_dispatch(buffer); } else { @@ -1198,7 +1198,7 @@ iterate(state_t& state, const ablocks_t& blocks) NOEXCEPT } else if constexpr (vectorization) { - iterate_v(state, blocks); + iterate_dispatch(state, blocks); } else { @@ -1212,7 +1212,7 @@ iterate(state_t& state, iblocks_t& blocks) NOEXCEPT { if constexpr (vectorization) { - iterate_v(state, blocks); + iterate_dispatch(state, blocks); } else { @@ -1284,7 +1284,7 @@ merkle_hash(digests_t& digests) NOEXCEPT } else if constexpr (vectorization) { - merkle_hash_v(digests); + merkle_hash_dispatch(digests); } else { diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_vectorization.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_vectorization.ipp index a8cc497ed7..a3435e2a98 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_vectorization.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_vectorization.ipp @@ -404,15 +404,19 @@ output(idigests_t& digests, const xstate_t& xstate) NOEXCEPT digests.template advance(); } +// Merkle Hash. +// ---------------------------------------------------------------------------- + TEMPLATE template > INLINE void CLASS:: -merkle_hash_v_(idigests_t& digests, iblocks_t& blocks) NOEXCEPT +merkle_hash_invoke(idigests_t& digests, iblocks_t& blocks) NOEXCEPT { BC_ASSERT(digests.size() == blocks.size()); constexpr auto lanes = capacity; static_assert(is_valid_lanes); + // RUNTIME INTRINSIC CHECK if (blocks.size() >= lanes && have()) { static auto initial = pack(H::get); @@ -447,7 +451,7 @@ merkle_hash_v_(idigests_t& digests, iblocks_t& blocks) NOEXCEPT TEMPLATE INLINE void CLASS:: -merkle_hash_v(digests_t& digests) NOEXCEPT +merkle_hash_dispatch(digests_t& digests) NOEXCEPT { // Merkle vector dispatch. static_assert(sizeof(digest_t) == to_half(sizeof(block_t))); @@ -463,11 +467,11 @@ merkle_hash_v(digests_t& digests) NOEXCEPT // Merkle hash vector dispatch. if constexpr (have_x512) - merkle_hash_v_(idigests, iblocks); + merkle_hash_invoke(idigests, iblocks); if constexpr (have_x256) - merkle_hash_v_(idigests, iblocks); + merkle_hash_invoke(idigests, iblocks); if constexpr (have_x128) - merkle_hash_v_(idigests, iblocks); + merkle_hash_invoke(idigests, iblocks); // iblocks.size() is reduced by vectorization. offset = blocks - iblocks.size(); @@ -484,7 +488,7 @@ merkle_hash_v(digests_t& digests) NOEXCEPT TEMPLATE template INLINE void CLASS:: -compress_v(state_t& state, const xbuffer_t& xbuffer) NOEXCEPT +compress_dispatch(state_t& state, const xbuffer_t& xbuffer) NOEXCEPT { constexpr auto lanes = capacity; @@ -521,11 +525,12 @@ compress_v(state_t& state, const xbuffer_t& xbuffer) NOEXCEPT TEMPLATE template > INLINE void CLASS:: -iterate_v_(state_t& state, iblocks_t& blocks) NOEXCEPT +iterate_invoke(state_t& state, iblocks_t& blocks) NOEXCEPT { constexpr auto lanes = capacity; static_assert(is_valid_lanes); + // RUNTIME INTRINSIC CHECK if (blocks.size() >= lanes && have()) { BC_PUSH_WARNING(NO_UNINITIALZIED_VARIABLE) @@ -537,7 +542,7 @@ iterate_v_(state_t& state, iblocks_t& blocks) NOEXCEPT // input() advances block iterator by lanes. input(xbuffer, blocks); schedule_(xbuffer); - compress_v(state, xbuffer); + compress_dispatch(state, xbuffer); } while (blocks.size() >= lanes); } @@ -545,17 +550,17 @@ iterate_v_(state_t& state, iblocks_t& blocks) NOEXCEPT TEMPLATE INLINE void CLASS:: -iterate_v(state_t& state, iblocks_t& blocks) NOEXCEPT +iterate_dispatch(state_t& state, iblocks_t& blocks) NOEXCEPT { if (blocks.size() >= min_lanes) { // Schedule iteration vector dispatch. if constexpr (have_x512) - iterate_v_(state, blocks); + iterate_invoke(state, blocks); if constexpr (have_x256) - iterate_v_(state, blocks); + iterate_invoke(state, blocks); if constexpr (have_x128) - iterate_v_(state, blocks); + iterate_invoke(state, blocks); } // Complete rounds using normal form. @@ -566,12 +571,12 @@ iterate_v(state_t& state, iblocks_t& blocks) NOEXCEPT TEMPLATE template INLINE void CLASS:: -iterate_v(state_t& state, const ablocks_t& blocks) NOEXCEPT +iterate_dispatch(state_t& state, const ablocks_t& blocks) NOEXCEPT { if (blocks.size() >= min_lanes) { auto iblocks = iblocks_t{ array_cast(blocks) }; - iterate_v(state, iblocks); + iterate_dispatch(state, iblocks); } else { @@ -602,7 +607,7 @@ sigma0_8(auto x1, auto x2, auto x3, auto x4, auto x5, auto x6, auto x7, TEMPLATE template INLINE void CLASS:: -prepare_v(buffer_t& buffer) NOEXCEPT +prepare_dispatch(buffer_t& buffer) NOEXCEPT { // Requires avx512 for sha512 and avx2 for sha256. // sigma0x8 message scheduling for single block iteration. @@ -668,35 +673,50 @@ prepare_v(buffer_t& buffer) NOEXCEPT TEMPLATE INLINE void CLASS:: -schedule_v(auto& buffer) NOEXCEPT +schedule_invoke(buffer_t& buffer) NOEXCEPT { - using word = decltype(buffer.front()); + // RUNTIME INTRINSIC CHECK + if (have_lanes()) + { + prepare_dispatch<16>(buffer); + prepare_dispatch<24>(buffer); + prepare_dispatch<32>(buffer); + prepare_dispatch<40>(buffer); + prepare_dispatch<48>(buffer); + prepare_dispatch<56>(buffer); + + if constexpr (SHA::rounds == 80) + { + prepare_dispatch<64>(buffer); + prepare_dispatch<72>(buffer); + } - if constexpr (SHA::strength == 160 || !is_same_type) + add_k(buffer); + } + else { schedule_(buffer); } - else if (!have_lanes()) +} + +TEMPLATE +INLINE void CLASS:: +schedule_dispatch(auto& buffer) NOEXCEPT +{ + // buffer may be vectorized via merkle execution path. + using word = decltype(buffer.front()); + + // Schedule prepare vector dispatch. + if constexpr ((SHA::strength != 160) && is_same_type && + ((have_x512 && (capacity == 8u)) || + (have_x256 && (capacity == 8u)) || + (have_x128 && (capacity == 8u)))) { - schedule_(buffer); + schedule_invoke(buffer); } else { - // Schedule prepare vector dispatch. - prepare_v<16>(buffer); - prepare_v<24>(buffer); - prepare_v<32>(buffer); - prepare_v<40>(buffer); - prepare_v<48>(buffer); - prepare_v<56>(buffer); - - if constexpr (SHA::rounds == 80) - { - prepare_v<64>(buffer); - prepare_v<72>(buffer); - } - - add_k(buffer); + schedule_(buffer); } } diff --git a/include/bitcoin/system/impl/stream/iostream/iostream.ipp b/include/bitcoin/system/impl/stream/iostream/iostream.ipp new file mode 100644 index 0000000000..3d22521ed9 --- /dev/null +++ b/include/bitcoin/system/impl/stream/iostream/iostream.ipp @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#ifndef LIBBITCOIN_SYSTEM_STREAM_IOSTREAM_IOSTREAM_IPP +#define LIBBITCOIN_SYSTEM_STREAM_IOSTREAM_IOSTREAM_IPP + +#include + +namespace libbitcoin { +namespace system { + +BC_PUSH_WARNING(NO_POINTER_ARITHMETIC) + +template +INLINE iostream::iostream(Buffer& buffer) NOEXCEPT + : position_(buffer.data()), + begin_(position_), + end_(begin_ + buffer.size()), + state_(goodbit) +{ +} + +template +INLINE iostream::iostream(uint8_t* begin, + ptrdiff_t size) NOEXCEPT + : position_(begin), + begin_(position_), + end_(begin_ + size), + state_(goodbit) +{ +} + +template +INLINE typename iostream::iostate +iostream::rdstate() const NOEXCEPT +{ + return state_; +} + +template +INLINE void +iostream::setstate(iostate state) NOEXCEPT +{ + state_ |= state; +} + +template +INLINE void +iostream::clear(iostate state) NOEXCEPT +{ + state_ = state; +} + +// private +template +INLINE bool +iostream::is_overflow(pos_type size) const NOEXCEPT +{ + return (state_ != goodbit) || (size > (end_ - position_)); +} + +BC_POP_WARNING() + +} // namespace system +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/system/impl/stream/simple/istream.ipp b/include/bitcoin/system/impl/stream/iostream/istream.ipp similarity index 60% rename from include/bitcoin/system/impl/stream/simple/istream.ipp rename to include/bitcoin/system/impl/stream/iostream/istream.ipp index c9345f74d3..e0bd6939d2 100644 --- a/include/bitcoin/system/impl/stream/simple/istream.ipp +++ b/include/bitcoin/system/impl/stream/iostream/istream.ipp @@ -16,8 +16,8 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -#ifndef LIBBITCOIN_SYSTEM_STREAM_SIMPLE_ISTREAM_IPP -#define LIBBITCOIN_SYSTEM_STREAM_SIMPLE_ISTREAM_IPP +#ifndef LIBBITCOIN_SYSTEM_STREAM_IOSTREAM_ISTREAM_IPP +#define LIBBITCOIN_SYSTEM_STREAM_IOSTREAM_ISTREAM_IPP #include #include @@ -26,25 +26,18 @@ namespace libbitcoin { namespace system { -template -inline istream::istream(const Source& source) NOEXCEPT - : position_(source.data()), - begin_(position_), - end_(begin_ + source.size()), - state_(goodbit) -{ -} +BC_PUSH_WARNING(NO_POINTER_ARITHMETIC) -template -inline typename istream::pos_type -istream::tellg() const NOEXCEPT +template +INLINE typename iostream::pos_type +iostream::tellg() const NOEXCEPT { return static_cast(position_ - begin_); } -template -inline istream& -istream::seekg(off_type offset, seekdir direction) NOEXCEPT +template +INLINE iostream& +iostream::seekg(off_type offset, seekdir direction) NOEXCEPT { if (state_ != goodbit) return *this; @@ -96,30 +89,25 @@ istream::seekg(off_type offset, seekdir direction) NOEXCEPT return *this; } -template -inline typename istream::iostate -istream::rdstate() const NOEXCEPT +template +INLINE typename iostream::int_type +iostream::peek() NOEXCEPT { - return state_; -} + constexpr auto eof = std::char_traits::eof(); -template -inline void -istream::setstate(iostate state) NOEXCEPT -{ - state_ |= state; -} + if (is_overflow(1)) + { + setstate(badbit); + return eof; + } -template -inline void -istream::clear(iostate state) NOEXCEPT -{ - state_ = state; + const uint8_t value = *position_; + return system::sign_cast(value); } -template -inline void -istream::read(char_type* data, pos_type size) NOEXCEPT +template +INLINE void +iostream::read(char_type* data, pos_type size) NOEXCEPT { if (is_overflow(size)) { @@ -134,37 +122,15 @@ istream::read(char_type* data, pos_type size) NOEXCEPT position_ += size; } -template -inline typename istream::int_type -istream::peek() NOEXCEPT -{ - constexpr auto eof = std::char_traits::eof(); - - if (is_overflow(1)) - { - setstate(badbit); - return eof; - } - - const uint8_t value = *position_; - return system::sign_cast(value); -} - // private -template +template constexpr bool -istream::is_positive(off_type value) NOEXCEPT +iostream::is_positive(off_type value) NOEXCEPT { return !is_zero(value) && !system::is_negative(value); } -// private -template -inline bool -istream::is_overflow(pos_type size) const NOEXCEPT -{ - return (state_ != goodbit) || (size > (end_ - position_)); -} +BC_POP_WARNING() } // namespace system } // namespace libbitcoin diff --git a/include/bitcoin/system/impl/stream/iostream/ostream.ipp b/include/bitcoin/system/impl/stream/iostream/ostream.ipp new file mode 100644 index 0000000000..3dce8ffa09 --- /dev/null +++ b/include/bitcoin/system/impl/stream/iostream/ostream.ipp @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#ifndef LIBBITCOIN_SYSTEM_STREAM_IOSTREAM_OSTREAM_IPP +#define LIBBITCOIN_SYSTEM_STREAM_IOSTREAM_OSTREAM_IPP + +#include +#include + +namespace libbitcoin { +namespace system { + +BC_PUSH_WARNING(NO_POINTER_ARITHMETIC) + +template +INLINE typename iostream::pos_type +iostream::tellp() const NOEXCEPT +{ + return static_cast(position_ - begin_); +} + +template +INLINE void +iostream::write(const char_type* data, pos_type size) NOEXCEPT +{ + if (is_overflow(size)) + { + setstate(badbit); + return; + } + + BC_PUSH_WARNING(NO_UNSAFE_COPY_N) + std::copy_n(data, size, position_); + BC_POP_WARNING() + + position_ += size; +} + +template +INLINE void +iostream::flush() NOEXCEPT +{ +} + +BC_POP_WARNING() + +} // namespace system +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/system/impl/stream/simple/ostream.ipp b/include/bitcoin/system/impl/stream/simple/ostream.ipp deleted file mode 100644 index 26c5361e95..0000000000 --- a/include/bitcoin/system/impl/stream/simple/ostream.ipp +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#ifndef LIBBITCOIN_SYSTEM_STREAM_SIMPLE_OSTREAM_IPP -#define LIBBITCOIN_SYSTEM_STREAM_SIMPLE_OSTREAM_IPP - -#include -#include - -namespace libbitcoin { -namespace system { - -template -inline ostream::ostream(Sink& sink) NOEXCEPT - : position_(sink.data()), - begin_(position_), - end_(begin_ + sink.size()), - state_(goodbit) -{ -} - -template -inline typename ostream::pos_type -ostream::tellp() const NOEXCEPT -{ - return static_cast(position_ - begin_); -} - -template -inline typename ostream::iostate -ostream::rdstate() const NOEXCEPT -{ - return state_; -} - -template -inline void -ostream::setstate(iostate state) NOEXCEPT -{ - state_ |= state; -} - -template -inline void -ostream::clear(iostate state) NOEXCEPT -{ - state_ = state; -} - -template -inline void -ostream::write(const char_type* data, pos_type size) NOEXCEPT -{ - if (is_overflow(size)) - { - setstate(badbit); - return; - } - - BC_PUSH_WARNING(NO_UNSAFE_COPY_N) - std::copy_n(data, size, position_); - BC_POP_WARNING() - - position_ += size; -} - -template -inline void -ostream::flush() NOEXCEPT -{ - // no-op. -} - -// private -template -inline bool -ostream::is_overflow(pos_type size) const NOEXCEPT -{ - return (state_ != goodbit) || (size > (end_ - position_)); -} - -} // namespace system -} // namespace libbitcoin - -#endif diff --git a/include/bitcoin/system/intrinsics/haves.hpp b/include/bitcoin/system/intrinsics/haves.hpp index d3df545c90..7305c146b3 100644 --- a/include/bitcoin/system/intrinsics/haves.hpp +++ b/include/bitcoin/system/intrinsics/haves.hpp @@ -98,7 +98,6 @@ namespace xcr0 constexpr auto avx_bit = 2; } - // Local util because no dependency on /math. template constexpr bool get_bit(Value value) NOEXCEPT @@ -267,20 +266,6 @@ using to_extended = iif == one, xint256_t, xint512_t>>>>>>; -/// Compile time (constexpr) availability of extended integer intrinsics, -/// as a template function of the extended integer type. -template = true> -CONSTEVAL bool with() NOEXCEPT -{ - if constexpr (is_same_type) - return with_avx512; - else if constexpr (is_same_type) - return with_avx2; - else if constexpr (is_same_type) - return with_sse41; - else return false; -} - /// Runtime time availability of extended integer intrinsics, as a template /// function of the extended integer type. template = true> diff --git a/include/bitcoin/system/intrinsics/xcpu/defines.hpp b/include/bitcoin/system/intrinsics/xcpu/defines.hpp index a2b5647026..d4cb1150bb 100644 --- a/include/bitcoin/system/intrinsics/xcpu/defines.hpp +++ b/include/bitcoin/system/intrinsics/xcpu/defines.hpp @@ -21,9 +21,6 @@ #include -/// Base type for mock extended integer types, used for differentiation. -struct xmock_t {}; - #if defined(HAVE_XCPU) #include #if defined(HAVE_X64) diff --git a/include/bitcoin/system/intrinsics/xcpu/functional_128.hpp b/include/bitcoin/system/intrinsics/xcpu/functional_128.hpp index 6a3051ea97..106b47dbc1 100644 --- a/include/bitcoin/system/intrinsics/xcpu/functional_128.hpp +++ b/include/bitcoin/system/intrinsics/xcpu/functional_128.hpp @@ -274,8 +274,8 @@ INLINE xint128_t byteswap(xint128_t a) NOEXCEPT #else -// Symbol is defined but not usable. -struct xint128_t : xmock_t {}; +// Symbol is defined but not usable as an integer. +using xint128_t = std_array>; #endif // HAVE_SSE4 diff --git a/include/bitcoin/system/intrinsics/xcpu/functional_256.hpp b/include/bitcoin/system/intrinsics/xcpu/functional_256.hpp index 438f45300f..a6f83cd2cb 100644 --- a/include/bitcoin/system/intrinsics/xcpu/functional_256.hpp +++ b/include/bitcoin/system/intrinsics/xcpu/functional_256.hpp @@ -287,8 +287,8 @@ INLINE xint256_t byteswap(xint256_t a) NOEXCEPT #else -// Symbol is defined but not usable. -struct xint256_t : xmock_t {}; +// Symbol is defined but not usable as an integer. +using xint256_t = std_array>; #endif // HAVE_AVX2 diff --git a/include/bitcoin/system/intrinsics/xcpu/functional_512.hpp b/include/bitcoin/system/intrinsics/xcpu/functional_512.hpp index 90b114a725..29f3d30112 100644 --- a/include/bitcoin/system/intrinsics/xcpu/functional_512.hpp +++ b/include/bitcoin/system/intrinsics/xcpu/functional_512.hpp @@ -327,8 +327,8 @@ INLINE xint512_t byteswap(xint512_t a) NOEXCEPT #else -// Symbol is defined but not usable. -struct xint512_t : xmock_t {}; +// Symbol is defined but not usable as an integer. +using xint512_t = std_array>; #endif // HAVE_AVX512 diff --git a/include/bitcoin/system/stream/simple/istream.hpp b/include/bitcoin/system/stream/iostream.hpp similarity index 59% rename from include/bitcoin/system/stream/simple/istream.hpp rename to include/bitcoin/system/stream/iostream.hpp index 198b33b6b3..7e5fc98c19 100644 --- a/include/bitcoin/system/stream/simple/istream.hpp +++ b/include/bitcoin/system/stream/iostream.hpp @@ -16,8 +16,8 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -#ifndef LIBBITCOIN_SYSTEM_STREAM_SIMPLE_ISTREAM_HPP -#define LIBBITCOIN_SYSTEM_STREAM_SIMPLE_ISTREAM_HPP +#ifndef LIBBITCOIN_SYSTEM_STREAM_IOSTREAM_HPP +#define LIBBITCOIN_SYSTEM_STREAM_IOSTREAM_HPP #include #include @@ -25,14 +25,12 @@ namespace libbitcoin { namespace system { -BC_PUSH_WARNING(NO_POINTER_ARITHMETIC) - -/// Support for high level input operations on a byte buffer. -template -class istream +/// Support for high level input/output operations on a byte buffer. +template +class iostream { public: - DEFAULT_COPY_MOVE_DESTRUCT(istream); + DEFAULT_COPY_MOVE_DESTRUCT(iostream); using char_type = Character; using int_type = typename std::basic_ios::int_type; @@ -52,44 +50,54 @@ class istream static constexpr seekdir end = 2; /// Construct the object. - inline istream(const Source& source) NOEXCEPT; - - /// Return the relative input position indicator (zero-based). - virtual inline pos_type tellg() const NOEXCEPT; - - /// Set the relative input position indicator (zero-based). - virtual inline istream& seekg(off_type offset, seekdir direction) NOEXCEPT; + INLINE iostream(Buffer& buffer) NOEXCEPT; + INLINE iostream(uint8_t* begin, ptrdiff_t size) NOEXCEPT; /// Return state flags. - virtual inline iostate rdstate() const NOEXCEPT; + virtual INLINE iostate rdstate() const NOEXCEPT; /// Set the stream error flags state in addition to currently set flags. - virtual inline void setstate(iostate state) NOEXCEPT; + virtual INLINE void setstate(iostate state) NOEXCEPT; /// Set the stream error state flags by assigning the state value. - virtual inline void clear(iostate state = goodbit) NOEXCEPT; + virtual INLINE void clear(iostate state = goodbit) NOEXCEPT; - /// Read a block of characters, sets badbit on underflow. - virtual inline void read(char_type* data, pos_type size) NOEXCEPT; + /// Return the relative input position indicator (zero-based). + virtual INLINE pos_type tellg() const NOEXCEPT; + + /// Return the relative output position indicator (zero-based). + virtual INLINE pos_type tellp() const NOEXCEPT; + + /// Set the relative input position indicator (zero-based). + virtual INLINE iostream& seekg(off_type offset, seekdir direction) NOEXCEPT; /// Read the next character without advancing, sets badbit on underflow. - virtual inline int_type peek() NOEXCEPT; + virtual INLINE int_type peek() NOEXCEPT; + + /// Read a block of characters, sets badbit on underflow. + virtual INLINE void read(char_type* data, pos_type size) NOEXCEPT; + + /// Write a block of characters, sets badbit on overflow. + virtual INLINE void write(const char_type* data, pos_type size) NOEXCEPT; + + /// Synchronize with the underlying storage device (no-op). + virtual INLINE void flush() NOEXCEPT; private: static constexpr bool is_positive(off_type value) NOEXCEPT; - inline bool is_overflow(pos_type size) const NOEXCEPT; + INLINE bool is_overflow(pos_type size) const NOEXCEPT; - const uint8_t* position_; - const uint8_t* begin_; - const uint8_t* end_; + uint8_t* position_; + uint8_t* begin_; + uint8_t* end_; iostate state_; }; -BC_POP_WARNING() - } // namespace system } // namespace libbitcoin -#include +#include +#include +#include #endif diff --git a/include/bitcoin/system/stream/simple/iostream.hpp b/include/bitcoin/system/stream/simple/iostream.hpp deleted file mode 100644 index 9e7f05ab9a..0000000000 --- a/include/bitcoin/system/stream/simple/iostream.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#ifndef LIBBITCOIN_SYSTEM_STREAM_SIMPLE_IOSTREAM_HPP -#define LIBBITCOIN_SYSTEM_STREAM_SIMPLE_IOSTREAM_HPP - -#include -#include -#include - -namespace libbitcoin { -namespace system { - -// The only multiple inheritance conflicts are resolved below. -BC_PUSH_WARNING(DIAMOND_INHERITANCE) - -/// Support for high level input and output operations on a byte buffer. -template -class iostream - : public istream, - public ostream -{ - DEFAULT_COPY_MOVE(iostream); - - /// Common based for state methods, just pick one. - using base = istream; - - /// Construct the object. - iostream(Buffer& buffer) NOEXCEPT - : istream(buffer), - ostream(buffer) - { - } - - // Two base destructor calls order is unimportant. - ~iostream() override = default; - - inline typename base::iostate rdstate() const NOEXCEPT override - { - return base::rdstate(); - } - - inline void setstate(typename base::iostate state) NOEXCEPT override - { - base::setstate(state); - } - - inline void clear( - typename base::iostate state=base::goodbit) NOEXCEPT override - { - base::clear(state); - } -}; - -BC_POP_WARNING() - -} // namespace system -} // namespace libbitcoin - -#endif diff --git a/include/bitcoin/system/stream/simple/ostream.hpp b/include/bitcoin/system/stream/simple/ostream.hpp deleted file mode 100644 index e50741823c..0000000000 --- a/include/bitcoin/system/stream/simple/ostream.hpp +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#ifndef LIBBITCOIN_SYSTEM_STREAM_SIMPLE_OSTREAM_HPP -#define LIBBITCOIN_SYSTEM_STREAM_SIMPLE_OSTREAM_HPP - -#include -#include - -namespace libbitcoin { -namespace system { - -BC_PUSH_WARNING(NO_POINTER_ARITHMETIC) - -/// Support for high level output operations on a byte buffer. -template -class ostream -{ -public: - DEFAULT_COPY_MOVE_DESTRUCT(ostream); - - using char_type = Character; - using pos_type = typename std::basic_ios::pos_type; - using failure = typename std::ios_base::failure; - - using iostate = uint8_t; - static constexpr iostate goodbit = 0; - static constexpr iostate eofbit = 1; - static constexpr iostate failbit = 2; - static constexpr iostate badbit = 4; - - /// Construct the object. - inline ostream(Sink& sink) NOEXCEPT; - - /// Return the relative output position indicator (zero-based). - virtual inline pos_type tellp() const NOEXCEPT; - - /// Return state flags. - virtual inline iostate rdstate() const NOEXCEPT; - - /// Set the stream error flags state in addition to currently set flags. - virtual inline void setstate(iostate state) NOEXCEPT; - - /// Set the stream error state flags by assigning the state value. - virtual inline void clear(iostate state=goodbit) NOEXCEPT; - - /// Write a block of characters, sets badbit on overflow. - virtual inline void write(const char_type* data, pos_type size) NOEXCEPT; - - /// Synchronize with the underlying storage device. - virtual inline void flush() NOEXCEPT; - -private: - inline bool is_overflow(pos_type size) const NOEXCEPT; - - uint8_t* position_; - uint8_t* begin_; - uint8_t* end_; - iostate state_; -}; - -BC_POP_WARNING() - -} // namespace system -} // namespace libbitcoin - -#include - -#endif diff --git a/include/bitcoin/system/stream/stream.hpp b/include/bitcoin/system/stream/stream.hpp index 08b6443a6d..494fa10353 100644 --- a/include/bitcoin/system/stream/stream.hpp +++ b/include/bitcoin/system/stream/stream.hpp @@ -27,9 +27,7 @@ #include #include #include -#include -#include -#include +#include #include #include #include diff --git a/include/bitcoin/system/stream/streamers/bit_flipper.hpp b/include/bitcoin/system/stream/streamers/bit_flipper.hpp index fb35a2e16a..513f711fb9 100644 --- a/include/bitcoin/system/stream/streamers/bit_flipper.hpp +++ b/include/bitcoin/system/stream/streamers/bit_flipper.hpp @@ -28,12 +28,12 @@ #include #include -// The only multiple inheritance conflicts are resolved below. -BC_PUSH_WARNING(DIAMOND_INHERITANCE) - namespace libbitcoin { namespace system { +// The only multiple inheritance conflicts are resolved below. +BC_PUSH_WARNING(DIAMOND_INHERITANCE) + /// A bit reader/writer that accepts an iostream. /// Bit actions may lead to unextected read behavior, as they are read and /// flushed to the byte reader/writer on byte boundaries. Flushing a @@ -79,9 +79,9 @@ class bit_flipper } }; +BC_POP_WARNING() + } // namespace system } // namespace libbitcoin -BC_POP_WARNING() - #endif diff --git a/include/bitcoin/system/stream/streamers/bit_reader.hpp b/include/bitcoin/system/stream/streamers/bit_reader.hpp index f4bfedb76c..1ab31d103f 100644 --- a/include/bitcoin/system/stream/streamers/bit_reader.hpp +++ b/include/bitcoin/system/stream/streamers/bit_reader.hpp @@ -27,13 +27,13 @@ #include #include +namespace libbitcoin { +namespace system { + // The inheritance is virtual, so not actually multiple. // But the boost type constraint 'is_virtual_base_of' triggers the warning. BC_PUSH_WARNING(DIAMOND_INHERITANCE) -namespace libbitcoin { -namespace system { - /// A bit reader that accepts an istream. template class bit_reader @@ -77,11 +77,11 @@ class bit_reader uint8_t offset_; }; +BC_POP_WARNING() + } // namespace system } // namespace libbitcoin -BC_POP_WARNING() - #include #endif diff --git a/include/bitcoin/system/stream/streams.hpp b/include/bitcoin/system/stream/streams.hpp index 8ca0996a02..bde4d79781 100644 --- a/include/bitcoin/system/stream/streams.hpp +++ b/include/bitcoin/system/stream/streams.hpp @@ -27,9 +27,6 @@ #include #include #include -#include -#include -#include namespace libbitcoin { namespace system { @@ -46,7 +43,6 @@ namespace stream { /// An input stream that copies data from a data_reference. using copy = make_stream>; - using simple = istream; } namespace out @@ -59,14 +55,12 @@ namespace stream using push = make_stream>; using text = push; using data = push; - using simple = ostream; } namespace flip { /// An input/output stream that copies data to a data_slab. using copy = make_stream>; - using simple = iostream; } } diff --git a/test/hash/performance/performance.hpp b/test/hash/performance/performance.hpp index bfce39842c..bc0225bc45 100644 --- a/test/hash/performance/performance.hpp +++ b/test/hash/performance/performance.hpp @@ -22,7 +22,6 @@ #include "../../test.hpp" #include "baseline/rmd160.h" #include "baseline/sha256.h" -#include "../sha/clone/algorithm.hpp" #include namespace performance { diff --git a/test/hash/sha/algorithm.cpp b/test/hash/sha/algorithm.cpp index 99cea30d47..80853bb50d 100644 --- a/test/hash/sha/algorithm.cpp +++ b/test/hash/sha/algorithm.cpp @@ -18,7 +18,6 @@ */ #include "../../test.hpp" #include "../hash.hpp" -#include "clone/algorithm.hpp" BOOST_AUTO_TEST_SUITE(sha_algorithm_tests) diff --git a/test/hash/sha/clone/algorithm.hpp b/test/hash/sha/clone/algorithm.hpp deleted file mode 100644 index 78ff795e55..0000000000 --- a/test/hash/sha/clone/algorithm.hpp +++ /dev/null @@ -1,319 +0,0 @@ -/** - * Copyright (c) 2011-2022 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#ifndef LIBBITCOIN_SYSTEM_HASH_SHAX_ALGORITHM_HPP -#define LIBBITCOIN_SYSTEM_HASH_SHAX_ALGORITHM_HPP - -#include "../../../test.hpp" - -namespace shax { - -/// SHA hashing algorithm. -/// Compression not yet implemented. -/// Vectorization of message schedules and merkle hashes. -template = true> -class algorithm : algorithm_t -{ -public: - /// Types. - /// ----------------------------------------------------------------------- - - /// Aliases. - using H = SHA; - using K = typename SHA::K; - using word_t = typename SHA::word_t; - using state_t = typename SHA::state_t; - - /// Word-based types. - using chunk_t = std_array; - using words_t = std_array; - using buffer_t = std_array; - - /// Byte-based types. - using byte_t = uint8_t; - using half_t = std_array; - using block_t = std_array; - using digest_t = std_array>; - - /// Collection types. - template - using ablocks_t = std_array; - using iblocks_t = iterable; - using digests_t = std_vector; - - /// Constants (and count_t). - /// ----------------------------------------------------------------------- - /// count_t is uint64_t (sha160/256) or uint128_t (sha512). - /// All extended integer intrinsics currently have a "64 on 32" limit. - - static constexpr auto count_bits = SHA::block_words * SHA::word_bytes; - static constexpr auto count_bytes = bytes; - using count_t = unsigned_exact_type>; - - static constexpr auto caching = Cached; - static constexpr auto limit_bits = maximum -count_bits; - static constexpr auto limit_bytes = to_floored_bytes(limit_bits); - static constexpr auto big_end_count = true; - - /// Single hashing. - /// ----------------------------------------------------------------------- - template - static constexpr digest_t hash(const ablocks_t& blocks) NOEXCEPT; - static constexpr digest_t hash(const block_t& block) NOEXCEPT; - static constexpr digest_t hash(const state_t& state) NOEXCEPT; - static constexpr digest_t hash(const half_t& half) NOEXCEPT; - static constexpr digest_t hash(const half_t& left, const half_t& right) NOEXCEPT; - static digest_t hash(iblocks_t&& blocks) NOEXCEPT; - - /// Double hashing (sha256/512). - /// ----------------------------------------------------------------------- - template - static constexpr digest_t double_hash(const ablocks_t& blocks) NOEXCEPT; - static constexpr digest_t double_hash(const block_t& block) NOEXCEPT; - static constexpr digest_t double_hash(const half_t& half) NOEXCEPT; - static constexpr digest_t double_hash(const half_t& left, const half_t& right) NOEXCEPT; - static digest_t double_hash(iblocks_t&& blocks) NOEXCEPT; - - /// Merkle hashing (sha256/512). - /// ----------------------------------------------------------------------- - static VCONSTEXPR digest_t merkle_root(digests_t&& digests) NOEXCEPT; - static VCONSTEXPR digests_t& merkle_hash(digests_t& digests) NOEXCEPT; - - /// Streamed hashing (unfinalized). - /// ----------------------------------------------------------------------- - static void accumulate(state_t& state, iblocks_t&& blocks) NOEXCEPT; - static constexpr void accumulate(state_t& state, const block_t& block) NOEXCEPT; - static constexpr digest_t finalize(state_t& state, size_t blocks) NOEXCEPT; - static constexpr digest_t finalize_double(state_t& state, size_t blocks) NOEXCEPT; - static constexpr digest_t normalize(const state_t& state) NOEXCEPT; - -protected: - /// Functions - /// ----------------------------------------------------------------------- - using uint = unsigned int; - - template - INLINE static constexpr auto sigma(auto x) NOEXCEPT; - template - INLINE static constexpr auto Sigma(auto x) NOEXCEPT; - - INLINE static constexpr auto parity(auto x, auto y, auto z) NOEXCEPT; - INLINE static constexpr auto choice(auto x, auto y, auto z) NOEXCEPT; - INLINE static constexpr auto majority(auto x, auto y, auto z) NOEXCEPT; - - INLINE static constexpr auto Sigma0(auto x) NOEXCEPT; - INLINE static constexpr auto Sigma1(auto x) NOEXCEPT; - INLINE static constexpr auto sigma0(auto x) NOEXCEPT; - INLINE static constexpr auto sigma1(auto x) NOEXCEPT; - - /// Rounds - /// ----------------------------------------------------------------------- - - template - static CONSTEVAL auto functor() NOEXCEPT; - - template - INLINE static constexpr void round(auto a, auto& b, auto c, auto d, - auto& e, auto wk) NOEXCEPT; - - template - INLINE static constexpr void round(auto a, auto b, auto c, auto& d, - auto e, auto f, auto g, auto& h, auto wk) NOEXCEPT; - - template - INLINE static constexpr void round(auto& state, const auto& buffer) NOEXCEPT; - INLINE static constexpr void summarize(auto& out, const auto& in) NOEXCEPT; - - template - static constexpr void compress(auto& state, const auto& buffer) NOEXCEPT; - - template - INLINE static constexpr void prepare(auto& buffer) NOEXCEPT; - INLINE static constexpr void add_k(auto& buffer) NOEXCEPT; - INLINE static constexpr void schedule_(auto& buffer) NOEXCEPT; - static constexpr void schedule(auto& buffer) NOEXCEPT; - - INLINE static constexpr void input(auto& buffer, const auto& state) NOEXCEPT; - - /// Parsing - /// ----------------------------------------------------------------------- - INLINE static constexpr void input(buffer_t& buffer, const block_t& block) NOEXCEPT; - INLINE static constexpr void input1(buffer_t& buffer, const half_t& half) NOEXCEPT; - INLINE static constexpr void input2(buffer_t& buffer, const half_t& half) NOEXCEPT; - INLINE static constexpr digest_t output(const state_t& state) NOEXCEPT; - - /// Padding - /// ----------------------------------------------------------------------- - template - static constexpr void schedule_n(buffer_t& buffer) NOEXCEPT; - static constexpr void schedule_n(buffer_t& buffer, size_t blocks) NOEXCEPT; - static constexpr void schedule_1(buffer_t& buffer) NOEXCEPT; - static constexpr void pad_half(buffer_t& buffer) NOEXCEPT; - static constexpr void pad_n(buffer_t& buffer, count_t blocks) NOEXCEPT; - - /// Block iteration. - /// ----------------------------------------------------------------------- - - template - INLINE static constexpr void iterate(state_t& state, - const ablocks_t& blocks) NOEXCEPT; - INLINE static void iterate(state_t& state, iblocks_t& blocks) NOEXCEPT; - - template - INLINE static constexpr void iterate_(state_t& state, - const ablocks_t& blocks) NOEXCEPT; - INLINE static void iterate_(state_t& state, iblocks_t& blocks) NOEXCEPT; - - /// Merkle iteration. - /// ----------------------------------------------------------------------- - VCONSTEXPR static void merkle_hash_(digests_t& digests, - size_t offset = zero) NOEXCEPT; - -private: - using pad_t = std_array; - - template - static CONSTEVAL buffer_t scheduled_pad() NOEXCEPT; - static CONSTEVAL chunk_t chunk_pad() NOEXCEPT; - static CONSTEVAL pad_t stream_pad() NOEXCEPT; - - /// Compression. - /// ----------------------------------------------------------------------- -protected: -public: - static constexpr auto have_shani = Compressed && system::with_shani; - static constexpr auto have_neon = Compressed && system::with_neon; - static constexpr auto compression = have_shani || have_neon; - - /// Vectorization. - /// ----------------------------------------------------------------------- -protected: - /// Extended integer capacity for uint32_t/uint64_t is 2/4/8/16 only. - template - static constexpr auto is_valid_lanes = - (Lanes == 16u || Lanes == 8u || Lanes == 4u || Lanes == 2u); - - template > = true> - using wblock_t = std_array; - template = true> - using xbuffer_t = std_array; - template = true> - using xstate_t = std_array; - template = true> - using xchunk_t = std_array; - using idigests_t = mutable_iterable; - - /// Common. - /// ----------------------------------------------------------------------- - - template - INLINE static auto pack(const wblock_t& wblock) NOEXCEPT; - - template - INLINE static void input(xbuffer_t& xbuffer, - iblocks_t& blocks) NOEXCEPT; - - /// Merkle Hash (full vectorization). - /// ----------------------------------------------------------------------- - - template - INLINE static auto pack_pad_half() NOEXCEPT; - - template - INLINE static auto pack_schedule_1() NOEXCEPT; - - template - INLINE static void pad_half(xbuffer_t& xbuffer) NOEXCEPT; - - template - INLINE static void schedule_1(xbuffer_t& xbuffer) NOEXCEPT; - - template - INLINE static auto pack(const state_t& state) NOEXCEPT; - - template - INLINE static digest_t unpack(const xstate_t& xstate) NOEXCEPT; - - template - INLINE static void output(idigests_t& digests, - const xstate_t& xstate) NOEXCEPT; - - template = true> - INLINE static void merkle_hash_v_(idigests_t& digests, - iblocks_t& blocks) NOEXCEPT; - - INLINE static void merkle_hash_v(digests_t& digests) NOEXCEPT; - - /// Message Schedule (block vectorization). - /// ----------------------------------------------------------------------- - - template - INLINE static constexpr auto extract(Word a) NOEXCEPT; - - template = true> - INLINE static Word extract(xWord a) NOEXCEPT; - - template - INLINE static void compress_lanes(state_t& state, - const xbuffer_t& xbuffer) NOEXCEPT; - - template = true> - INLINE static void iterate_v_(state_t& state, iblocks_t& blocks) NOEXCEPT; - - template - INLINE static void iterate_v(state_t& state, const ablocks_t& blocks) NOEXCEPT; - INLINE static void iterate_v(state_t& state, iblocks_t& blocks) NOEXCEPT; - - /// Message Schedule (sigma vectorization). - /// ----------------------------------------------------------------------- - - template = true> - INLINE static auto sigma0_8(auto x1, auto x2, auto x3, auto x4, auto x5, - auto x6, auto x7, auto x8) NOEXCEPT; - - template - INLINE static void prepare_8(buffer_t& buffer) NOEXCEPT; - INLINE static void schedule_v(auto& buffer) NOEXCEPT; - -public: - static constexpr auto have_x128 = Vectorized && system::with_sse41; - static constexpr auto have_x256 = Vectorized && system::with_avx2; - static constexpr auto have_x512 = Vectorized && system::with_avx512; - static constexpr auto min_lanes = (have_x128 ? 16 : (have_x256 ? 32 : - (have_x128 ? 64 : 0))) / SHA::word_bytes; - static constexpr auto vectorization = (have_x128 || have_x256 || have_x512) && - !(build_x32 && is_same_size); -}; - -} // namespace shax - -#define TEMPLATE template If> -#define CLASS algorithm - -#include "algorithm.ipp" -#include "algorithm_compression.ipp" -#include "algorithm_vectorization.ipp" - -#undef CLASS -#undef TEMPLATE - -#endif diff --git a/test/hash/sha/clone/algorithm.ipp b/test/hash/sha/clone/algorithm.ipp deleted file mode 100644 index 67b35f67d1..0000000000 --- a/test/hash/sha/clone/algorithm.ipp +++ /dev/null @@ -1,1284 +0,0 @@ -/** - * Copyright (c) 2011-2022 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#ifndef LIBBITCOIN_SYSTEM_HASH_SHAX_ALGORITHM_IPP -#define LIBBITCOIN_SYSTEM_HASH_SHAX_ALGORITHM_IPP - -#include "../../../test.hpp" - -namespace shax { - -// Bogus warning suggests constexpr when declared consteval. -BC_PUSH_WARNING(USE_CONSTEXPR_FOR_FUNCTION) -BC_PUSH_WARNING(NO_UNGUARDED_POINTERS) -BC_PUSH_WARNING(NO_POINTER_ARITHMETIC) -BC_PUSH_WARNING(NO_ARRAY_INDEXING) - -// 4.1 Functions -// --------------------------------------------------------------------------- - -TEMPLATE -INLINE constexpr auto CLASS:: -parity(auto x, auto y, auto z) NOEXCEPT -{ - return f::xor_(f::xor_(x, y), z); -} - -TEMPLATE -INLINE constexpr auto CLASS:: -choice(auto x, auto y, auto z) NOEXCEPT -{ - // Normal form reduced. - ////return (x & y) ^ (~x & z); - return f::xor_(f::and_(x, f::xor_(y, z)), z); -} - -TEMPLATE -INLINE constexpr auto CLASS:: -majority(auto x, auto y, auto z) NOEXCEPT -{ - // Normal form reduced. - ////return (x & y) ^ (x & z) ^ (y & z); - return f::or_(f::and_(x, f::or_(y, z)), f::and_(y, z)); -} - -TEMPLATE -template -INLINE constexpr auto CLASS:: -sigma(auto x) NOEXCEPT -{ - constexpr auto s = SHA::word_bits; - return f::xor_(f::xor_(f::ror(x), f::ror(x)), f::shr(x)); -} - -TEMPLATE -template -INLINE constexpr auto CLASS:: -Sigma(auto x) NOEXCEPT -{ - // Specialized for non-vector destructive ror. - // "Because the ror instruction is destructive (that is, it overwrites the - // operand), implementing the above as written would involve a number of - // source register copy operations. If, however, the expressions are - // rewritten as... Then the number of register copies can be minimized." - // intel.com/content/dam/www/public/us/en/documents/white-papers/ - // sha-256-implementations-paper.pdf - // AVX optimal (sha256) - // - // Translation: - // S (n) = (n >>> x) ^ (n >>> y) ^ (n >>> z) - // S'(n) = ((((n >>> X) ^ n) >>> Y) ^ n) >>> Z - // X = z - y - // Y = y - x - // Z = x - // S'(n) = ((((n >>> (z-y)) ^ n) >>> (y-x)) ^ n) >>> x - ////return f::xor_(f::xor_(f::ror(x), f::ror(x)), f::ror(x)); - - // This Sigma refactoring reduces native processing time by ~10%. - constexpr auto s = SHA::word_bits; - return f::ror(f::xor_(f::ror(f::xor_(f::ror(x), x)), x)); -} - -// Sigma dispatch. -// --------------------------------------------------------------------------- - -TEMPLATE -INLINE constexpr auto CLASS:: -sigma0(auto x) NOEXCEPT -{ - if constexpr (SHA::strength == 256) - return sigma<7, 18, 3>(x); - else - return sigma<1, 8, 7>(x); -} - -TEMPLATE -INLINE constexpr auto CLASS:: -sigma1(auto x) NOEXCEPT -{ - if constexpr (SHA::strength == 256) - return sigma<17, 19, 10>(x); - else - return sigma<19, 61, 6>(x); -} - -TEMPLATE -INLINE constexpr auto CLASS:: -Sigma0(auto x) NOEXCEPT -{ - if constexpr (SHA::strength == 256) - return Sigma<2, 13, 22>(x); - else - return Sigma<28, 34, 39>(x); -} - -TEMPLATE -INLINE constexpr auto CLASS:: -Sigma1(auto x) NOEXCEPT -{ - if constexpr (SHA::strength == 256) - return Sigma<6, 11, 25>(x); - else - return Sigma<14, 18, 41>(x); -} - -// Rounds -// --------------------------------------------------------------------------- - -TEMPLATE -template -CONSTEVAL auto CLASS:: -functor() NOEXCEPT -{ - using self = CLASS; - constexpr auto fn = Round / K::columns; - - if constexpr (fn == 0u) - return &self::template choice; - else if constexpr (fn == 1u) - return &self::template parity; - else if constexpr (fn == 2u) - return &self::template majority; - else if constexpr (fn == 3u) - return &self::template parity; -} - -TEMPLATE -template -INLINE constexpr void CLASS:: -round(auto a, auto& b, auto c, auto d, auto& e, auto wk) NOEXCEPT -{ - constexpr auto s = SHA::word_bits; - constexpr auto fn = functor(); - e = /*a =*/ f::add(f::add(f::add(f::rol<5, s>(a), fn(b, c, d)), e), wk); - b = /*c =*/ f::rol<30, s>(b); -} - -TEMPLATE -template -INLINE constexpr void CLASS:: -round(auto a, auto b, auto c, auto& d, auto e, auto f, auto g, auto& h, - auto wk) NOEXCEPT -{ - constexpr auto s = SHA::word_bits; - const auto t = f::add(f::add(f::add(Sigma1(e), choice(e, f, g)), h), wk); - d = /*e =*/ f::add(d, t); - h = /*a =*/ f::add(f::add(Sigma0(a), majority(a, b, c)), t); -} - -TEMPLATE -template -INLINE constexpr auto CLASS:: -extract(Word a) NOEXCEPT -{ - // Compress vectorization and non-vectorization require no extraction. - static_assert(Lane == zero); - return a; -} - -TEMPLATE -template > - INLINE Word CLASS:: - extract(xWord a) NOEXCEPT -{ - // Schedule vectorization (with compress non-vectorization), extract word. - return get(a); -} - -TEMPLATE -template -INLINE constexpr void CLASS:: -round(auto& state, const auto& buffer) NOEXCEPT -{ - using word = std::decay_t; - - if constexpr (SHA::strength == 160) - { - // msvc++ not inlined in x32 for vectorized state. - BC_PUSH_WARNING(NOT_INLINED) - round( - state[(SHA::rounds + 0 - Round) % SHA::state_words], - state[(SHA::rounds + 1 - Round) % SHA::state_words], // c->b - state[(SHA::rounds + 2 - Round) % SHA::state_words], - state[(SHA::rounds + 3 - Round) % SHA::state_words], - state[(SHA::rounds + 4 - Round) % SHA::state_words], // a->e - extract(buffer[Round])); - BC_POP_WARNING() - } - else - { - // msvc++ not inlined in x32 for vectorized state. - BC_PUSH_WARNING(NOT_INLINED) - round( - state[(SHA::rounds + 0 - Round) % SHA::state_words], - state[(SHA::rounds + 1 - Round) % SHA::state_words], - state[(SHA::rounds + 2 - Round) % SHA::state_words], - state[(SHA::rounds + 3 - Round) % SHA::state_words], // e->d - state[(SHA::rounds + 4 - Round) % SHA::state_words], - state[(SHA::rounds + 5 - Round) % SHA::state_words], - state[(SHA::rounds + 6 - Round) % SHA::state_words], - state[(SHA::rounds + 7 - Round) % SHA::state_words], // a->h - extract(buffer[Round])); - BC_POP_WARNING() - } -} - -TEMPLATE -template -constexpr void CLASS:: -compress(auto& state, const auto& buffer) NOEXCEPT -{ - // state may be packed on multi-block axis. - const auto start = state; - - round< 0, Lane>(state, buffer); - round< 1, Lane>(state, buffer); - round< 2, Lane>(state, buffer); - round< 3, Lane>(state, buffer); - round< 4, Lane>(state, buffer); - round< 5, Lane>(state, buffer); - round< 6, Lane>(state, buffer); - round< 7, Lane>(state, buffer); - round< 8, Lane>(state, buffer); - round< 9, Lane>(state, buffer); - round<10, Lane>(state, buffer); - round<11, Lane>(state, buffer); - round<12, Lane>(state, buffer); - round<13, Lane>(state, buffer); - round<14, Lane>(state, buffer); - round<15, Lane>(state, buffer); - - round<16, Lane>(state, buffer); - round<17, Lane>(state, buffer); - round<18, Lane>(state, buffer); - round<19, Lane>(state, buffer); - round<20, Lane>(state, buffer); - round<21, Lane>(state, buffer); - round<22, Lane>(state, buffer); - round<23, Lane>(state, buffer); - round<24, Lane>(state, buffer); - round<25, Lane>(state, buffer); - round<26, Lane>(state, buffer); - round<27, Lane>(state, buffer); - round<28, Lane>(state, buffer); - round<29, Lane>(state, buffer); - round<30, Lane>(state, buffer); - round<31, Lane>(state, buffer); - - round<32, Lane>(state, buffer); - round<33, Lane>(state, buffer); - round<34, Lane>(state, buffer); - round<35, Lane>(state, buffer); - round<36, Lane>(state, buffer); - round<37, Lane>(state, buffer); - round<38, Lane>(state, buffer); - round<39, Lane>(state, buffer); - round<40, Lane>(state, buffer); - round<41, Lane>(state, buffer); - round<42, Lane>(state, buffer); - round<43, Lane>(state, buffer); - round<44, Lane>(state, buffer); - round<45, Lane>(state, buffer); - round<46, Lane>(state, buffer); - round<47, Lane>(state, buffer); - - round<48, Lane>(state, buffer); - round<49, Lane>(state, buffer); - round<50, Lane>(state, buffer); - round<51, Lane>(state, buffer); - round<52, Lane>(state, buffer); - round<53, Lane>(state, buffer); - round<54, Lane>(state, buffer); - round<55, Lane>(state, buffer); - round<56, Lane>(state, buffer); - round<57, Lane>(state, buffer); - round<58, Lane>(state, buffer); - round<59, Lane>(state, buffer); - round<60, Lane>(state, buffer); - round<61, Lane>(state, buffer); - round<62, Lane>(state, buffer); - round<63, Lane>(state, buffer); - - if constexpr (SHA::rounds == 80) - { - round<64, Lane>(state, buffer); - round<65, Lane>(state, buffer); - round<66, Lane>(state, buffer); - round<67, Lane>(state, buffer); - round<68, Lane>(state, buffer); - round<69, Lane>(state, buffer); - round<70, Lane>(state, buffer); - round<71, Lane>(state, buffer); - round<72, Lane>(state, buffer); - round<73, Lane>(state, buffer); - round<74, Lane>(state, buffer); - round<75, Lane>(state, buffer); - round<76, Lane>(state, buffer); - round<77, Lane>(state, buffer); - round<78, Lane>(state, buffer); - round<79, Lane>(state, buffer); - } - - summarize(state, start); -} - -TEMPLATE -template -INLINE constexpr void CLASS:: -prepare(auto& buffer) NOEXCEPT -{ - // K is added to schedule words because schedule is vectorizable. - // K-adding is shifted -16, with last 16 words added after scheduling. - constexpr auto s = SHA::word_bits; - - if constexpr (SHA::strength == 160) - { - constexpr auto r03 = Round - 3; - constexpr auto r08 = Round - 8; - constexpr auto r14 = Round - 14; - constexpr auto r16 = Round - 16; - - buffer[Round] = f::rol<1, s>(f::xor_( - f::xor_(buffer[r16], buffer[r14]), - f::xor_(buffer[r08], buffer[r03]))); - buffer[r16] = f::addc(buffer[r16]); - } - else - { - constexpr auto r02 = Round - 2; - constexpr auto r07 = Round - 7; - constexpr auto r15 = Round - 15; - constexpr auto r16 = Round - 16; - - buffer[Round] = f::add( - f::add(buffer[r16], sigma0(buffer[r15])), - f::add(buffer[r07], sigma1(buffer[r02]))); - buffer[r16] = f::addc(buffer[r16]); - } -} - -TEMPLATE -INLINE constexpr void CLASS:: -add_k(auto& buffer) NOEXCEPT -{ - // Add K to last 16 words. - constexpr auto s = SHA::word_bits; - constexpr auto r = SHA::rounds - array_count; - buffer[r + 0] = f::addc(buffer[r + 0]); - buffer[r + 1] = f::addc(buffer[r + 1]); - buffer[r + 2] = f::addc(buffer[r + 2]); - buffer[r + 3] = f::addc(buffer[r + 3]); - buffer[r + 4] = f::addc(buffer[r + 4]); - buffer[r + 5] = f::addc(buffer[r + 5]); - buffer[r + 6] = f::addc(buffer[r + 6]); - buffer[r + 7] = f::addc(buffer[r + 7]); - buffer[r + 8] = f::addc(buffer[r + 8]); - buffer[r + 9] = f::addc(buffer[r + 9]); - buffer[r + 10] = f::addc(buffer[r + 10]); - buffer[r + 11] = f::addc(buffer[r + 11]); - buffer[r + 12] = f::addc(buffer[r + 12]); - buffer[r + 13] = f::addc(buffer[r + 13]); - buffer[r + 14] = f::addc(buffer[r + 14]); - buffer[r + 15] = f::addc(buffer[r + 15]); -} - -TEMPLATE -INLINE constexpr void CLASS:: -schedule_(auto& buffer) NOEXCEPT -{ - prepare<16>(buffer); - prepare<17>(buffer); - prepare<18>(buffer); - prepare<19>(buffer); - prepare<20>(buffer); - prepare<21>(buffer); - prepare<22>(buffer); - prepare<23>(buffer); - prepare<24>(buffer); - prepare<25>(buffer); - prepare<26>(buffer); - prepare<27>(buffer); - prepare<28>(buffer); - prepare<29>(buffer); - prepare<30>(buffer); - prepare<31>(buffer); - - prepare<32>(buffer); - prepare<33>(buffer); - prepare<34>(buffer); - prepare<35>(buffer); - prepare<36>(buffer); - prepare<37>(buffer); - prepare<38>(buffer); - prepare<39>(buffer); - prepare<40>(buffer); - prepare<41>(buffer); - prepare<42>(buffer); - prepare<43>(buffer); - prepare<44>(buffer); - prepare<45>(buffer); - prepare<46>(buffer); - prepare<47>(buffer); - - prepare<48>(buffer); - prepare<49>(buffer); - prepare<50>(buffer); - prepare<51>(buffer); - prepare<52>(buffer); - prepare<53>(buffer); - prepare<54>(buffer); - prepare<55>(buffer); - prepare<56>(buffer); - prepare<57>(buffer); - prepare<58>(buffer); - prepare<59>(buffer); - prepare<60>(buffer); - prepare<61>(buffer); - prepare<62>(buffer); - prepare<63>(buffer); - - if constexpr (SHA::rounds == 80) - { - prepare<64>(buffer); - prepare<65>(buffer); - prepare<66>(buffer); - prepare<67>(buffer); - prepare<68>(buffer); - prepare<69>(buffer); - prepare<70>(buffer); - prepare<71>(buffer); - prepare<72>(buffer); - prepare<73>(buffer); - prepare<74>(buffer); - prepare<75>(buffer); - prepare<76>(buffer); - prepare<77>(buffer); - prepare<78>(buffer); - prepare<79>(buffer); - } - - add_k(buffer); -} - -TEMPLATE -constexpr void CLASS:: -schedule(auto& buffer) NOEXCEPT -{ - if (std::is_constant_evaluated()) - { - schedule_(buffer); - } - else if constexpr (vectorization) - { - schedule_v(buffer); - } - else - { - schedule_(buffer); - } -} - -TEMPLATE -INLINE constexpr void CLASS:: -summarize(auto& out, const auto& in) NOEXCEPT -{ - constexpr auto s = SHA::word_bits; - out[0] = f::add(out[0], in[0]); - out[1] = f::add(out[1], in[1]); - out[2] = f::add(out[2], in[2]); - out[3] = f::add(out[3], in[3]); - out[4] = f::add(out[4], in[4]); - - if constexpr (SHA::strength != 160) - { - out[5] = f::add(out[5], in[5]); - out[6] = f::add(out[6], in[6]); - out[7] = f::add(out[7], in[7]); - } -} - -TEMPLATE -INLINE constexpr void CLASS:: -input(auto& buffer, const auto& state) NOEXCEPT -{ - // This is a double hash optimization. - if (std::is_constant_evaluated()) - { - buffer[0] = state[0]; - buffer[1] = state[1]; - buffer[2] = state[2]; - buffer[3] = state[3]; - buffer[4] = state[4]; - - if constexpr (SHA::strength != 160) - { - buffer[5] = state[5]; - buffer[6] = state[6]; - buffer[7] = state[7]; - } - } - else - { - using word = array_element; - array_cast(buffer) = state; - } -} - -// 5.2 Parsing the Message -// --------------------------------------------------------------------------- -// big-endian I/O is conventional for SHA. - -TEMPLATE -INLINE constexpr void CLASS:: -input(buffer_t& buffer, const block_t& block) NOEXCEPT -{ - if (std::is_constant_evaluated()) - { - constexpr auto size = SHA::word_bytes; - from_big<0 * size>(buffer.at(0), block); - from_big<1 * size>(buffer.at(1), block); - from_big<2 * size>(buffer.at(2), block); - from_big<3 * size>(buffer.at(3), block); - from_big<4 * size>(buffer.at(4), block); - from_big<5 * size>(buffer.at(5), block); - from_big<6 * size>(buffer.at(6), block); - from_big<7 * size>(buffer.at(7), block); - from_big<8 * size>(buffer.at(8), block); - from_big<9 * size>(buffer.at(9), block); - from_big<10 * size>(buffer.at(10), block); - from_big<11 * size>(buffer.at(11), block); - from_big<12 * size>(buffer.at(12), block); - from_big<13 * size>(buffer.at(13), block); - from_big<14 * size>(buffer.at(14), block); - from_big<15 * size>(buffer.at(15), block); - } - else if constexpr (bc::is_little_endian) - { - const auto& in = array_cast(block); - buffer[0] = native_from_big_end(in[0]); - buffer[1] = native_from_big_end(in[1]); - buffer[2] = native_from_big_end(in[2]); - buffer[3] = native_from_big_end(in[3]); - buffer[4] = native_from_big_end(in[4]); - buffer[5] = native_from_big_end(in[5]); - buffer[6] = native_from_big_end(in[6]); - buffer[7] = native_from_big_end(in[7]); - buffer[8] = native_from_big_end(in[8]); - buffer[9] = native_from_big_end(in[9]); - buffer[10] = native_from_big_end(in[10]); - buffer[11] = native_from_big_end(in[11]); - buffer[12] = native_from_big_end(in[12]); - buffer[13] = native_from_big_end(in[13]); - buffer[14] = native_from_big_end(in[14]); - buffer[15] = native_from_big_end(in[15]); - } - else - { - array_cast(buffer) = - array_cast(block); - } -} - -TEMPLATE -INLINE constexpr void CLASS:: -input1(buffer_t& buffer, const half_t& half) NOEXCEPT -{ - using word = array_element; - - if (std::is_constant_evaluated()) - { - constexpr auto size = SHA::word_bytes; - from_big<0 * size>(buffer.at(0), half); - from_big<1 * size>(buffer.at(1), half); - from_big<2 * size>(buffer.at(2), half); - from_big<3 * size>(buffer.at(3), half); - from_big<4 * size>(buffer.at(4), half); - from_big<5 * size>(buffer.at(5), half); - from_big<6 * size>(buffer.at(6), half); - from_big<7 * size>(buffer.at(7), half); - } - else if constexpr (bc::is_little_endian) - { - const auto& in = array_cast(half); - buffer[0] = native_from_big_end(in[0]); - buffer[1] = native_from_big_end(in[1]); - buffer[2] = native_from_big_end(in[2]); - buffer[3] = native_from_big_end(in[3]); - buffer[4] = native_from_big_end(in[4]); - buffer[5] = native_from_big_end(in[5]); - buffer[6] = native_from_big_end(in[6]); - buffer[7] = native_from_big_end(in[7]); - } - else - { - array_cast(buffer) = array_cast(half); - } -} - -TEMPLATE -INLINE constexpr void CLASS:: -input2(buffer_t& buffer, const half_t& half) NOEXCEPT -{ - using word = array_element; - - if (std::is_constant_evaluated()) - { - constexpr auto size = SHA::word_bytes; - from_big<0 * size>(buffer.at(8), half); - from_big<1 * size>(buffer.at(9), half); - from_big<2 * size>(buffer.at(10), half); - from_big<3 * size>(buffer.at(11), half); - from_big<4 * size>(buffer.at(12), half); - from_big<5 * size>(buffer.at(13), half); - from_big<6 * size>(buffer.at(14), half); - from_big<7 * size>(buffer.at(15), half); - } - else if constexpr (bc::is_little_endian) - { - const auto& in = array_cast(half); - buffer[8] = native_from_big_end(in[0]); - buffer[9] = native_from_big_end(in[1]); - buffer[10] = native_from_big_end(in[2]); - buffer[11] = native_from_big_end(in[3]); - buffer[12] = native_from_big_end(in[4]); - buffer[13] = native_from_big_end(in[5]); - buffer[14] = native_from_big_end(in[6]); - buffer[15] = native_from_big_end(in[7]); - } - else - { - array_cast(buffer) = - array_cast(half); - } -} - -TEMPLATE -INLINE constexpr typename CLASS::digest_t CLASS:: -output(const state_t& state) NOEXCEPT -{ - if (std::is_constant_evaluated()) - { - digest_t digest{}; - - constexpr auto size = SHA::word_bytes; - to_big<0 * size>(digest, state.at(0)); - to_big<1 * size>(digest, state.at(1)); - to_big<2 * size>(digest, state.at(2)); - to_big<3 * size>(digest, state.at(3)); - to_big<4 * size>(digest, state.at(4)); - - if constexpr (SHA::strength != 160) - { - to_big<5 * size>(digest, state.at(5)); - to_big<6 * size>(digest, state.at(6)); - to_big<7 * size>(digest, state.at(7)); - } - - return digest; - } - else if constexpr (bc::is_little_endian) - { - if constexpr (SHA::strength == 160) - { - return array_cast(state_t - { - native_to_big_end(state[0]), - native_to_big_end(state[1]), - native_to_big_end(state[2]), - native_to_big_end(state[3]), - native_to_big_end(state[4]) - }); - } - else - { - return array_cast(state_t - { - native_to_big_end(state[0]), - native_to_big_end(state[1]), - native_to_big_end(state[2]), - native_to_big_end(state[3]), - native_to_big_end(state[4]), - native_to_big_end(state[5]), - native_to_big_end(state[6]), - native_to_big_end(state[7]) - }); - } - } - else - { - return array_cast(state); - } -} - -// 5.1 Padding the Message -// --------------------------------------------------------------------------- - -TEMPLATE -template -CONSTEVAL typename CLASS::buffer_t CLASS:: -scheduled_pad() NOEXCEPT -{ - // This precomputed padding is limited to one word of counter. - static_assert(Blocks <= maximum / byte_bits); - - // See comments in accumulator regarding padding endianness. - constexpr auto index = sub1(array_count); - constexpr auto bytes = safe_multiply(Blocks, array_count); - - buffer_t out{}; - out.front() = bit_hi; - out.at(index) = possible_narrow_cast(to_bits(bytes)); - schedule(out); - return out; -} - -TEMPLATE -CONSTEVAL typename CLASS::chunk_t CLASS:: -chunk_pad() NOEXCEPT -{ - // See comments in accumulator regarding padding endianness. - constexpr auto bytes = possible_narrow_cast(array_count); - - chunk_t out{}; - out.front() = bit_hi; - out.back() = to_bits(bytes); - return out; -} - -TEMPLATE -CONSTEVAL typename CLASS::pad_t CLASS:: -stream_pad() NOEXCEPT -{ - // See comments in accumulator regarding padding endianness. - pad_t out{}; - out.front() = bit_hi; - return out; -} - -TEMPLATE -template -constexpr void CLASS:: -schedule_n(buffer_t& buffer) NOEXCEPT -{ - // Scheduled padding for n whole blocks. - // This will compile in 4*64 (sha256) or 4*128 (sha512) bytes for each - // unique size of blocks array hashed by callers (by template expansion). - // and one for each that is cached for block vectors in schedule_n(). - constexpr auto pad = scheduled_pad(); - buffer = pad; -} - -TEMPLATE -constexpr void CLASS:: -schedule_n(buffer_t& buffer, size_t blocks) NOEXCEPT -{ - // This optimization is saves ~30% in message scheduling for one out of - // N blocks: (N + 70%)/(N + 100%). So the proportional benefit decreases - // exponentially with increasing N. For arbitrary data lengths this will - // benefit 1/64 hashes on average. All array-sized n-block hashes have - // precomputed schedules - this benefits only finalized chunk hashing. - // Testing shows a 5% performance improvement for 128 byte chunk hashes. - // Accumulator passes all write() of more than one block here. - if constexpr (caching) - { - switch (blocks) - { - case 1: schedule_n<1>(buffer); return; - case 2: schedule_n<2>(buffer); return; - case 3: schedule_n<3>(buffer); return; - case 4: schedule_n<4>(buffer); return; - default: - { - pad_n(buffer, blocks); - schedule(buffer); - return; - } - } - } - else - { - pad_n(buffer, blocks); - schedule(buffer); - return; - } -} - -TEMPLATE -constexpr void CLASS:: -schedule_1(buffer_t& buffer) NOEXCEPT -{ - // Single block padding is always prescheduled. - schedule_n(buffer); -} - -TEMPLATE -constexpr void CLASS:: -pad_half(buffer_t& buffer) NOEXCEPT -{ - // Pad for any half block, unscheduled buffer. - constexpr auto pad = chunk_pad(); - - if (std::is_constant_evaluated()) - { - buffer.at(8) = pad.at(0); - buffer.at(9) = pad.at(1); - buffer.at(10) = pad.at(2); - buffer.at(11) = pad.at(3); - buffer.at(12) = pad.at(4); - buffer.at(13) = pad.at(5); - buffer.at(14) = pad.at(6); - buffer.at(15) = pad.at(7); - } - else - { - array_cast(buffer) = pad; - } -} - -TEMPLATE -constexpr void CLASS:: -pad_n(buffer_t& buffer, count_t blocks) NOEXCEPT -{ - // Pad any number of whole blocks, unscheduled buffer. - constexpr auto pad = stream_pad(); - const auto bits = to_bits(blocks * array_count); - - if (std::is_constant_evaluated()) - { - buffer.at(0) = pad.at(0); - buffer.at(1) = pad.at(1); - buffer.at(2) = pad.at(2); - buffer.at(3) = pad.at(3); - buffer.at(4) = pad.at(4); - buffer.at(5) = pad.at(5); - buffer.at(6) = pad.at(6); - buffer.at(7) = pad.at(7); - buffer.at(8) = pad.at(8); - buffer.at(9) = pad.at(9); - buffer.at(10) = pad.at(10); - buffer.at(11) = pad.at(11); - buffer.at(12) = pad.at(12); - buffer.at(13) = pad.at(13); - buffer.at(14) = hi_word(bits); - buffer.at(15) = lo_word(bits); - } - else - { - array_cast>(buffer) = pad; - - // Split count into hi/low words and assign end of padded buffer. - buffer[14] = hi_word(bits); - buffer[15] = lo_word(bits); - } -} - -// Hashing. -// --------------------------------------------------------------------------- -// No hash(state_t) optimizations for sha160 (requires chunk_t/half_t). - -TEMPLATE -template -constexpr typename CLASS::digest_t CLASS:: -hash(const ablocks_t& blocks) NOEXCEPT -{ - buffer_t buffer{}; - auto state = H::get; - iterate(state, blocks); - schedule_n(buffer); - compress(state, buffer); - return output(state); -} - -TEMPLATE -typename CLASS::digest_t CLASS:: -hash(iblocks_t&& blocks) NOEXCEPT -{ - // Save block count, as iterable decrements. - const auto count = blocks.size(); - - buffer_t buffer{}; - auto state = H::get; - iterate(state, blocks); - schedule_n(buffer, count); - compress(state, buffer); - return output(state); -} - - -TEMPLATE -constexpr typename CLASS::digest_t CLASS:: -hash(const block_t& block) NOEXCEPT -{ - buffer_t buffer{}; - auto state = H::get; - input(buffer, block); - schedule(buffer); - compress(state, buffer); - schedule_1(buffer); - compress(state, buffer); - return output(state); -} - -TEMPLATE -constexpr typename CLASS::digest_t CLASS:: -hash(const state_t& state) NOEXCEPT -{ - static_assert(is_same_type); - - buffer_t buffer{}; - auto state2 = H::get; - input(buffer, state); - pad_half(buffer); - schedule(buffer); - compress(state2, buffer); - return output(state2); -} - -TEMPLATE -constexpr typename CLASS::digest_t CLASS:: -hash(const half_t& half) NOEXCEPT -{ - buffer_t buffer{}; - auto state = H::get; - input1(buffer, half); - pad_half(buffer); - schedule(buffer); - compress(state, buffer); - return output(state); -} - -TEMPLATE -constexpr typename CLASS::digest_t CLASS:: -hash(const half_t& left, const half_t& right) NOEXCEPT -{ - buffer_t buffer{}; - auto state = H::get; - input1(buffer, left); - input2(buffer, right); - schedule(buffer); - compress(state, buffer); - schedule_1(buffer); - compress(state, buffer); - return output(state); -} - -// Double Hashing. -// --------------------------------------------------------------------------- -// No double_hash optimizations for sha160 (requires chunk_t/half_t). - -TEMPLATE -template -constexpr typename CLASS::digest_t CLASS:: -double_hash(const ablocks_t& blocks) NOEXCEPT -{ - static_assert(is_same_type); - - buffer_t buffer{}; - auto state = H::get; - iterate(state, blocks); - schedule_n(buffer); - compress(state, buffer); - - // Second hash - input(buffer, state); - pad_half(buffer); - schedule(buffer); - state = H::get; - compress(state, buffer); - return output(state); -} - -TEMPLATE -typename CLASS::digest_t CLASS:: -double_hash(iblocks_t&& blocks) NOEXCEPT -{ - static_assert(is_same_type); - - // Save block count, as iterable decrements. - const auto count = blocks.size(); - - buffer_t buffer{}; - auto state = H::get; - iterate(state, blocks); - schedule_n(buffer, count); - compress(state, buffer); - - // Second hash - input(buffer, state); - pad_half(buffer); - schedule(buffer); - state = H::get; - compress(state, buffer); - return output(state); -} - -TEMPLATE -constexpr typename CLASS::digest_t CLASS:: -double_hash(const block_t& block) NOEXCEPT -{ - static_assert(is_same_type); - - buffer_t buffer{}; - - auto state = H::get; - input(buffer, block); - schedule(buffer); - compress(state, buffer); - schedule_1(buffer); - compress(state, buffer); - - // Second hash - input(buffer, state); - pad_half(buffer); - schedule(buffer); - state = H::get; - compress(state, buffer); - return output(state); -} - -TEMPLATE -constexpr typename CLASS::digest_t CLASS:: -double_hash(const half_t& half) NOEXCEPT -{ - static_assert(is_same_type); - - buffer_t buffer{}; - auto state = H::get; - input1(buffer, half); - pad_half(buffer); - schedule(buffer); - compress(state, buffer); - - // Second hash - input(buffer, state); - pad_half(buffer); - schedule(buffer); - state = H::get; - compress(state, buffer); - return output(state); -} - -TEMPLATE -constexpr typename CLASS::digest_t CLASS:: -double_hash(const half_t& left, const half_t& right) NOEXCEPT -{ - static_assert(is_same_type); - - buffer_t buffer{}; - auto state = H::get; - input1(buffer, left); - input2(buffer, right); - schedule(buffer); - compress(state, buffer); - schedule_1(buffer); - compress(state, buffer); - - // Second hash - input(buffer, state); - pad_half(buffer); - schedule(buffer); - state = H::get; - compress(state, buffer); - return output(state); -} - -// Block iteration. -// ------------------------------------------------------------------------ - -TEMPLATE -template -INLINE constexpr void CLASS:: -iterate(state_t& state, const ablocks_t& blocks) NOEXCEPT -{ - if (std::is_constant_evaluated()) - { - iterate_(state, blocks); - } - else if constexpr (vectorization) - { - iterate_v(state, blocks); - } - else - { - iterate_(state, blocks); - } -} - -TEMPLATE -INLINE void CLASS:: -iterate(state_t& state, iblocks_t& blocks) NOEXCEPT -{ - if constexpr (vectorization) - { - iterate_v(state, blocks); - } - else - { - iterate_(state, blocks); - } -} - -TEMPLATE -template -INLINE constexpr void CLASS:: -iterate_(state_t& state, const ablocks_t& blocks) NOEXCEPT -{ - buffer_t buffer{}; - for (auto& block: blocks) - { - input(buffer, block); - schedule(buffer); - compress(state, buffer); - } -} - -TEMPLATE -INLINE void CLASS:: -iterate_(state_t& state, iblocks_t& blocks) NOEXCEPT -{ - buffer_t buffer{}; - for (auto& block: blocks) - { - input(buffer, block); - schedule(buffer); - compress(state, buffer); - } -} - - -// Merkle Hashing (sha256/512). -// ------------------------------------------------------------------------ -// No merkle_hash optimizations for sha160 (double_hash requires half_t). - -TEMPLATE -VCONSTEXPR typename CLASS::digest_t CLASS:: -merkle_root(digests_t&& digests) NOEXCEPT -{ - static_assert(is_same_type); - - if (is_zero(digests.size())) - return {}; - - while (!is_one(digests.size())) - { - if (is_odd(digests.size())) - digests.push_back(digests.back()); - - merkle_hash(digests); - } - - return std::move(digests.front()); -} - -TEMPLATE -VCONSTEXPR typename CLASS::digests_t& CLASS:: -merkle_hash(digests_t& digests) NOEXCEPT -{ - static_assert(is_same_type); - - if (std::is_constant_evaluated()) - { - merkle_hash_(digests); - } - else if constexpr (vectorization) - { - merkle_hash_v(digests); - } - else - { - merkle_hash_(digests); - } - - return digests; -}; - -TEMPLATE -VCONSTEXPR void CLASS:: -merkle_hash_(digests_t& digests, size_t offset) NOEXCEPT -{ - const auto blocks = to_half(digests.size()); - for (auto i = offset, j = offset * two; i < blocks; ++i, j += two) - digests[i] = double_hash(digests[j], digests[add1(j)]); - - digests.resize(blocks); -} - -// Streaming (unfinalized). -// --------------------------------------------------------------------------- - -TEMPLATE -void CLASS:: -accumulate(state_t& state, iblocks_t&& blocks) NOEXCEPT -{ - iterate(state, blocks); -} - -TEMPLATE -constexpr void CLASS:: -accumulate(state_t& state, const block_t& block) NOEXCEPT -{ - buffer_t buffer{}; - input(buffer, block); - schedule(buffer); - compress(state, buffer); -} - -TEMPLATE -constexpr typename CLASS::digest_t CLASS:: -finalize(state_t& state, size_t blocks) NOEXCEPT -{ - buffer_t buffer{}; - schedule_n(buffer, blocks); - compress(state, buffer); - return output(state); -} - -TEMPLATE -constexpr typename CLASS::digest_t CLASS:: -finalize_double(state_t& state, size_t blocks) NOEXCEPT -{ - // The state out parameter is updated for first hash. - buffer_t buffer{}; - schedule_n(buffer, blocks); - compress(state, buffer); - - // Second hash - input(buffer, state); - pad_half(buffer); - schedule(buffer); - auto state2 = H::get; - compress(state2, buffer); - return output(state2); -} - -TEMPLATE -constexpr typename CLASS::digest_t CLASS:: -normalize(const state_t& state) NOEXCEPT -{ - return output(state); -} - -BC_POP_WARNING() -BC_POP_WARNING() -BC_POP_WARNING() -BC_POP_WARNING() - -} // namespace shax - -#endif diff --git a/test/hash/sha/clone/algorithm_compression.ipp b/test/hash/sha/clone/algorithm_compression.ipp deleted file mode 100644 index 64baec00d3..0000000000 --- a/test/hash/sha/clone/algorithm_compression.ipp +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2011-2022 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#ifndef LIBBITCOIN_SYSTEM_HASH_SHAX_ALGORITHM_COMPRESSION_IPP -#define LIBBITCOIN_SYSTEM_HASH_SHAX_ALGORITHM_COMPRESSION_IPP - -namespace shax { - -} // namespace shax - -#endif diff --git a/test/hash/sha/clone/algorithm_vectorization.ipp b/test/hash/sha/clone/algorithm_vectorization.ipp deleted file mode 100644 index 3e29447f07..0000000000 --- a/test/hash/sha/clone/algorithm_vectorization.ipp +++ /dev/null @@ -1,782 +0,0 @@ -/** - * Copyright (c) 2011-2022 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#ifndef LIBBITCOIN_SYSTEM_HASH_SHAX_ALGORITHM_VECTORIZATION_IPP -#define LIBBITCOIN_SYSTEM_HASH_SHAX_ALGORITHM_VECTORIZATION_IPP - -#include "../../../test.hpp" - -namespace shax { - -BC_PUSH_WARNING(NO_ARRAY_INDEXING) - -// Common. -// ---------------------------------------------------------------------------- - -TEMPLATE -template -INLINE auto CLASS:: -pack(const wblock_t& wblock) NOEXCEPT -{ - using xword = to_extended; - - if constexpr (Lanes == 2) - { - return byteswap(set( - wblock[0][Word], - wblock[1][Word])); - } - else if constexpr (Lanes == 4) - { - return byteswap(set( - wblock[0][Word], - wblock[1][Word], - wblock[2][Word], - wblock[3][Word])); - } - else if constexpr (Lanes == 8) - { - return byteswap(set( - wblock[0][Word], - wblock[1][Word], - wblock[2][Word], - wblock[3][Word], - wblock[4][Word], - wblock[5][Word], - wblock[6][Word], - wblock[7][Word])); - } - else if constexpr (Lanes == 16) - { - return byteswap(set( - wblock[ 0][Word], - wblock[ 1][Word], - wblock[ 2][Word], - wblock[ 3][Word], - wblock[ 4][Word], - wblock[ 5][Word], - wblock[ 6][Word], - wblock[ 7][Word], - wblock[ 8][Word], - wblock[ 9][Word], - wblock[10][Word], - wblock[11][Word], - wblock[12][Word], - wblock[13][Word], - wblock[14][Word], - wblock[15][Word])); - } -} - -TEMPLATE -template -INLINE void CLASS:: -input(xbuffer_t& xbuffer, iblocks_t& blocks) NOEXCEPT -{ - constexpr auto lanes = capacity; - - const auto& wblock = array_cast(blocks.template to_array()); - xbuffer[0] = pack<0>(wblock); - xbuffer[1] = pack<1>(wblock); - xbuffer[2] = pack<2>(wblock); - xbuffer[3] = pack<3>(wblock); - xbuffer[4] = pack<4>(wblock); - xbuffer[5] = pack<5>(wblock); - xbuffer[6] = pack<6>(wblock); - xbuffer[7] = pack<7>(wblock); - xbuffer[8] = pack<8>(wblock); - xbuffer[9] = pack<9>(wblock); - xbuffer[10] = pack<10>(wblock); - xbuffer[11] = pack<11>(wblock); - xbuffer[12] = pack<12>(wblock); - xbuffer[13] = pack<13>(wblock); - xbuffer[14] = pack<14>(wblock); - xbuffer[15] = pack<15>(wblock); - blocks.template advance(); -} - -// Merkle Hash. -// ---------------------------------------------------------------------------- - -TEMPLATE -template -INLINE auto CLASS:: -pack_pad_half() NOEXCEPT -{ - constexpr auto pad = chunk_pad(); - - return xchunk_t - { - broadcast(pad[0]), - broadcast(pad[1]), - broadcast(pad[2]), - broadcast(pad[3]), - broadcast(pad[4]), - broadcast(pad[5]), - broadcast(pad[6]), - broadcast(pad[7]) - }; -} - -TEMPLATE -template -INLINE auto CLASS:: -pack_schedule_1() NOEXCEPT -{ - constexpr auto pad = scheduled_pad(); - - if constexpr (SHA::rounds == 80) - { - return xbuffer_t - { - broadcast(pad[0]), - broadcast(pad[1]), - broadcast(pad[2]), - broadcast(pad[3]), - broadcast(pad[4]), - broadcast(pad[5]), - broadcast(pad[6]), - broadcast(pad[7]), - broadcast(pad[8]), - broadcast(pad[9]), - broadcast(pad[10]), - broadcast(pad[11]), - broadcast(pad[12]), - broadcast(pad[13]), - broadcast(pad[14]), - broadcast(pad[15]), - - broadcast(pad[16]), - broadcast(pad[17]), - broadcast(pad[18]), - broadcast(pad[19]), - broadcast(pad[20]), - broadcast(pad[21]), - broadcast(pad[22]), - broadcast(pad[23]), - broadcast(pad[24]), - broadcast(pad[25]), - broadcast(pad[26]), - broadcast(pad[27]), - broadcast(pad[28]), - broadcast(pad[29]), - broadcast(pad[30]), - broadcast(pad[31]), - - broadcast(pad[32]), - broadcast(pad[33]), - broadcast(pad[34]), - broadcast(pad[35]), - broadcast(pad[36]), - broadcast(pad[37]), - broadcast(pad[38]), - broadcast(pad[39]), - broadcast(pad[40]), - broadcast(pad[41]), - broadcast(pad[42]), - broadcast(pad[43]), - broadcast(pad[44]), - broadcast(pad[45]), - broadcast(pad[46]), - broadcast(pad[47]), - - broadcast(pad[48]), - broadcast(pad[49]), - broadcast(pad[50]), - broadcast(pad[51]), - broadcast(pad[52]), - broadcast(pad[53]), - broadcast(pad[54]), - broadcast(pad[55]), - broadcast(pad[56]), - broadcast(pad[57]), - broadcast(pad[58]), - broadcast(pad[59]), - broadcast(pad[60]), - broadcast(pad[61]), - broadcast(pad[62]), - broadcast(pad[63]), - - broadcast(pad[64]), - broadcast(pad[65]), - broadcast(pad[66]), - broadcast(pad[67]), - broadcast(pad[68]), - broadcast(pad[69]), - broadcast(pad[70]), - broadcast(pad[71]), - broadcast(pad[72]), - broadcast(pad[73]), - broadcast(pad[74]), - broadcast(pad[75]), - broadcast(pad[76]), - broadcast(pad[77]), - broadcast(pad[78]), - broadcast(pad[79]) - }; - } - else - { - return xbuffer_t - { - broadcast(pad[0]), - broadcast(pad[1]), - broadcast(pad[2]), - broadcast(pad[3]), - broadcast(pad[4]), - broadcast(pad[5]), - broadcast(pad[6]), - broadcast(pad[7]), - broadcast(pad[8]), - broadcast(pad[9]), - broadcast(pad[10]), - broadcast(pad[11]), - broadcast(pad[12]), - broadcast(pad[13]), - broadcast(pad[14]), - broadcast(pad[15]), - - broadcast(pad[16]), - broadcast(pad[17]), - broadcast(pad[18]), - broadcast(pad[19]), - broadcast(pad[20]), - broadcast(pad[21]), - broadcast(pad[22]), - broadcast(pad[23]), - broadcast(pad[24]), - broadcast(pad[25]), - broadcast(pad[26]), - broadcast(pad[27]), - broadcast(pad[28]), - broadcast(pad[29]), - broadcast(pad[30]), - broadcast(pad[31]), - - broadcast(pad[32]), - broadcast(pad[33]), - broadcast(pad[34]), - broadcast(pad[35]), - broadcast(pad[36]), - broadcast(pad[37]), - broadcast(pad[38]), - broadcast(pad[39]), - broadcast(pad[40]), - broadcast(pad[41]), - broadcast(pad[42]), - broadcast(pad[43]), - broadcast(pad[44]), - broadcast(pad[45]), - broadcast(pad[46]), - broadcast(pad[47]), - - broadcast(pad[48]), - broadcast(pad[49]), - broadcast(pad[50]), - broadcast(pad[51]), - broadcast(pad[52]), - broadcast(pad[53]), - broadcast(pad[54]), - broadcast(pad[55]), - broadcast(pad[56]), - broadcast(pad[57]), - broadcast(pad[58]), - broadcast(pad[59]), - broadcast(pad[60]), - broadcast(pad[61]), - broadcast(pad[62]), - broadcast(pad[63]) - }; - } -} - -TEMPLATE -template -INLINE void CLASS:: -pad_half(xbuffer_t& xbuffer) NOEXCEPT -{ - static const auto xchunk_pad = pack_pad_half(); - array_cast(xbuffer) = xchunk_pad; -} - -TEMPLATE -template -INLINE void CLASS:: -schedule_1(xbuffer_t& xbuffer) NOEXCEPT -{ - static const auto xscheduled_pad = pack_schedule_1(); - xbuffer = xscheduled_pad; -} - -TEMPLATE -template -INLINE auto CLASS:: -pack(const state_t& state) NOEXCEPT -{ - return xstate_t - { - broadcast(state[0]), - broadcast(state[1]), - broadcast(state[2]), - broadcast(state[3]), - broadcast(state[4]), - broadcast(state[5]), - broadcast(state[6]), - broadcast(state[7]) - }; -} - -TEMPLATE -template -INLINE typename CLASS::digest_t CLASS:: -unpack(const xstate_t& xstate) NOEXCEPT -{ - // TODO: this is inefficient, swapping all xwords Lanes times. - // TODO: and getting each lane individually. - return array_cast(state_t - { - get(byteswap(xstate[0])), - get(byteswap(xstate[1])), - get(byteswap(xstate[2])), - get(byteswap(xstate[3])), - get(byteswap(xstate[4])), - get(byteswap(xstate[5])), - get(byteswap(xstate[6])), - get(byteswap(xstate[7])) - }); -} - -TEMPLATE -template -INLINE void CLASS:: -output(idigests_t& digests, const xstate_t& xstate) NOEXCEPT -{ - constexpr auto lanes = capacity; - BC_ASSERT(digests.size() >= lanes); - - auto& wdigest = array_cast(digests.template to_array()); - - wdigest[0] = unpack<0>(xstate); - wdigest[1] = unpack<1>(xstate); - - if constexpr (lanes >= 4) - { - wdigest[2] = unpack<2>(xstate); - wdigest[3] = unpack<3>(xstate); - } - - if constexpr (lanes >= 8) - { - wdigest[4] = unpack<4>(xstate); - wdigest[5] = unpack<5>(xstate); - wdigest[6] = unpack<6>(xstate); - wdigest[7] = unpack<7>(xstate); - } - - if constexpr (lanes >= 16) - { - wdigest[8] = unpack<8>(xstate); - wdigest[9] = unpack<9>(xstate); - wdigest[10] = unpack<10>(xstate); - wdigest[11] = unpack<11>(xstate); - wdigest[12] = unpack<12>(xstate); - wdigest[13] = unpack<13>(xstate); - wdigest[14] = unpack<14>(xstate); - wdigest[15] = unpack<15>(xstate); - } - - digests.template advance(); -} - -TEMPLATE -template > -INLINE void CLASS:: -merkle_hash_v_(idigests_t& digests, iblocks_t& blocks) NOEXCEPT -{ - BC_ASSERT(digests.size() == blocks.size()); - constexpr auto lanes = capacity; - static_assert(is_valid_lanes); - - if (blocks.size() >= lanes && have()) - { - static auto initial = pack(H::get); - BC_PUSH_WARNING(NO_UNINITIALZIED_VARIABLE) - xbuffer_t xbuffer; - BC_POP_WARNING() - - do - { - auto xstate = initial; - - // input() advances block iterator by lanes. - input(xbuffer, blocks); - schedule(xbuffer); - compress(xstate, xbuffer); - schedule_1(xbuffer); - compress(xstate, xbuffer); - - // Second hash - input(xbuffer, xstate); - pad_half(xbuffer); - schedule(xbuffer); - xstate = initial; - compress(xstate, xbuffer); - - // output() advances digest iterator by lanes. - output(digests, xstate); - } - while (blocks.size() >= lanes); - } -} - -TEMPLATE -INLINE void CLASS:: -merkle_hash_v(digests_t& digests) NOEXCEPT -{ - // Merkle vector dispatch. - static_assert(sizeof(digest_t) == to_half(sizeof(block_t))); - auto offset = zero; - - if (digests.size() >= min_lanes * two) - { - const auto data = digests.front().data(); - const auto size = digests.size() * array_count; - auto iblocks = iblocks_t{ size, data }; - auto idigests = idigests_t{ to_half(size), data }; - const auto blocks = iblocks.size(); - - // Merkle hash vector dispatch. - if constexpr (have_x512) - merkle_hash_v_(idigests, iblocks); - if constexpr (have_x256) - merkle_hash_v_(idigests, iblocks); - if constexpr (have_x128) - merkle_hash_v_(idigests, iblocks); - - // iblocks.size() is reduced by vectorization. - offset = blocks - iblocks.size(); - } - - // Complete rounds using normal form. - merkle_hash_(digests, offset); -} - -// Message Schedule (block vectorization). -// ---------------------------------------------------------------------------- -// eprint.iacr.org/2012/067.pdf - -TEMPLATE -template -INLINE void CLASS:: -compress_lanes(state_t& state, const xbuffer_t& xbuffer) NOEXCEPT -{ - constexpr auto lanes = capacity; - - compress<0>(state, xbuffer); - compress<1>(state, xbuffer); - - if constexpr (lanes >= 4) - { - compress<2>(state, xbuffer); - compress<3>(state, xbuffer); - } - - if constexpr (lanes >= 8) - { - compress<4>(state, xbuffer); - compress<5>(state, xbuffer); - compress<6>(state, xbuffer); - compress<7>(state, xbuffer); - } - - if constexpr (lanes >= 16) - { - compress<8>(state, xbuffer); - compress<9>(state, xbuffer); - compress<10>(state, xbuffer); - compress<11>(state, xbuffer); - compress<12>(state, xbuffer); - compress<13>(state, xbuffer); - compress<14>(state, xbuffer); - compress<15>(state, xbuffer); - } -} - -TEMPLATE -template > -INLINE void CLASS:: -iterate_v_(state_t& state, iblocks_t& blocks) NOEXCEPT -{ - constexpr auto lanes = capacity; - static_assert(is_valid_lanes); - - if (blocks.size() >= lanes && have()) - { - BC_PUSH_WARNING(NO_UNINITIALZIED_VARIABLE) - xbuffer_t xbuffer; - BC_POP_WARNING() - - do - { - // input() advances block iterator by lanes. - input(xbuffer, blocks); - schedule_(xbuffer); - compress_lanes(state, xbuffer); - } - while (blocks.size() >= lanes); - } -} - -TEMPLATE -INLINE void CLASS:: -iterate_v(state_t& state, iblocks_t& blocks) NOEXCEPT -{ - if (blocks.size() >= min_lanes) -{ - // Schedule iteration vector dispatch. - if constexpr (have_x512) - iterate_v_(state, blocks); - if constexpr (have_x256) - iterate_v_(state, blocks); - if constexpr (have_x128) - iterate_v_(state, blocks); - } - - // Complete rounds using normal form. - // blocks.size() is reduced by vectorization. - iterate_(state, blocks); -} - -TEMPLATE -template -INLINE void CLASS:: -iterate_v(state_t& state, const ablocks_t& blocks) NOEXCEPT -{ - if (blocks.size() >= min_lanes) - { - auto iblocks = iblocks_t{ array_cast(blocks) }; - iterate_v(state, iblocks); - } - else - { - iterate_(state, blocks); - } -} - -// Message Schedule (sigma vectorization). -// ---------------------------------------------------------------------------- - -constexpr auto add0(auto a) noexcept { return depromote(a + 0); } -constexpr auto add2(auto a) noexcept { return depromote(a + 2); } -constexpr auto add3(auto a) noexcept { return depromote(a + 3); } -constexpr auto add4(auto a) noexcept { return depromote(a + 4); } -constexpr auto add5(auto a) noexcept { return depromote(a + 5); } -constexpr auto add6(auto a) noexcept { return depromote(a + 6); } -constexpr auto add7(auto a) noexcept { return depromote(a + 7); } - -TEMPLATE -template > -INLINE auto CLASS:: -sigma0_8(auto x1, auto x2, auto x3, auto x4, auto x5, auto x6, auto x7, - auto x8) NOEXCEPT -{ - return sigma0(set(x1, x2, x3, x4, x5, x6, x7, x8)); -} - -TEMPLATE -template -INLINE void CLASS:: -prepare_8(buffer_t& buffer) NOEXCEPT -{ - // Requires avx512 for sha512 and avx2 for sha256. - // sigma0x8 message scheduling for single block iteration. - // Tests of adding sigma1x2 half lanes vectorization show loss ~10%. - // Tests of adding sigma0x8 full lanes vectorization show a gain of ~5%. - // The simplicity of sha160 message prepare precludes this optimization. - static_assert(SHA::strength != 160); - - constexpr auto r02 = Round - 2; - constexpr auto r07 = Round - 7; - constexpr auto r15 = Round - 15; - constexpr auto r16 = Round - 16; - constexpr auto s = SHA::word_bits; - - const auto xr15 = sigma0_8>( - buffer[add0(r15)], buffer[add1(r15)], - buffer[add2(r15)], buffer[add3(r15)], - buffer[add4(r15)], buffer[add5(r15)], - buffer[add6(r15)], buffer[add7(r15)]); - - buffer[add0(Round)] = f::add( - f::add(buffer[add0(r16)], get(xr15)), - f::add(buffer[add0(r07)], sigma1(buffer[add0(r02)]))); - buffer[add0(r16)] = f::addc(buffer[add0(r16)]); - - buffer[add1(Round)] = f::add( - f::add(buffer[add1(r16)], get(xr15)), - f::add(buffer[add1(r07)], sigma1(buffer[add1(r02)]))); - buffer[add1(r16)] = f::addc(buffer[add1(r16)]); - - buffer[add2(Round)] = f::add( - f::add(buffer[add2(r16)], get(xr15)), - f::add(buffer[add2(r07)], sigma1(buffer[add2(r02)]))); - buffer[add2(r16)] = f::addc(buffer[add2(r16)]); - - buffer[add3(Round)] = f::add( - f::add(buffer[add3(r16)], get(xr15)), - f::add(buffer[add3(r07)], sigma1(buffer[add3(r02)]))); - buffer[add3(r16)] = f::addc(buffer[add3(r16)]); - - buffer[add4(Round)] = f::add( - f::add(buffer[add4(r16)], get(xr15)), - f::add(buffer[add4(r07)], sigma1(buffer[add4(r02)]))); - buffer[add4(r16)] = f::addc(buffer[add4(r16)]); - - buffer[add5(Round)] = f::add( - f::add(buffer[add5(r16)], get(xr15)), - f::add(buffer[add5(r07)], sigma1(buffer[add5(r02)]))); - buffer[add5(r16)] = f::addc(buffer[add5(r16)]); - - buffer[add6(Round)] = f::add( - f::add(buffer[add6(r16)], get(xr15)), - f::add(buffer[add6(r07)], sigma1(buffer[add6(r02)]))); - buffer[add6(r16)] = f::addc(buffer[add6(r16)]); - - // buffer[add7(r07)] is buffer[add0(Round)] - // This is why sigma0 is limited to 8 lanes (vs 16). - buffer[add7(Round)] = f::add( - f::add(buffer[add7(r16)], get(xr15)), - f::add(buffer[add7(r07)], sigma1(buffer[add7(r02)]))); - buffer[add7(r16)] = f::addc(buffer[add7(r16)]); -} - -TEMPLATE -INLINE void CLASS:: -schedule_v(auto& buffer) NOEXCEPT -{ - using word = decltype(buffer.front()); - - if constexpr (SHA::strength == 160 || !is_same_type) - { - schedule_(buffer); - } - else if (!have_lanes()) - { - schedule_(buffer); - } - else - { - // Schedule prepare vector dispatch. - prepare_8<16>(buffer); - prepare_8<24>(buffer); - prepare_8<32>(buffer); - prepare_8<40>(buffer); - prepare_8<48>(buffer); - prepare_8<56>(buffer); - - if constexpr (SHA::rounds == 80) - { - prepare_8<64>(buffer); - prepare_8<72>(buffer); - } - - add_k(buffer); - } -} - -// sha intrinsics (compressing) -// ---------------------------------------------------------------------------- -// -// Compress. -// SNA-NI/NEON -// buffer[Round] is 128 (w + k). -// buffer is packed on a different axis than full block vectorization. -// State packs 4/5 into xint128 (one state xword plus uint32_t e). -// State aspect is also packed on a different axist than full block, -// though full block (merkle) doesn't support sha160 (half != digest). -// -// SHA-NI/NEON -// buffer[Round] is 128 (w + k). -// buffer is packed on a different axis than full block vectorization. -// State packs 4/8 into xint128 (two state xwords). -// State aspect is also packed on a different axist than full block. -// -// SHA-NI -// Four rounds (total rounds 80/4). -// First round is add(e, w), then sha1nexte(e, w). -// fk is round-based enumeration implying f selection and k value. -// e1 = sha1nexte(e0, w); -// abcd = sha1rnds4(abcd, e0, fk); -// NEON -// f is implied by k in wk. -// e1 = vsha1h(vgetq_lane(abcd, 0); -// vsha1cq(abcd, e0, vaddq(w, k)); -// -// Each call is 2 rounds, 4 rounds total. -// s, w and k are 128 (4 words each, s1/s2 is 8 word state). -// SHA-NI -// const auto value = add(w, k); -// abcd = sha256rnds2(abef, cdgh, value); -// efgh = sha256rnds2(cdgh, abef, shuffle(value)); -// NEON -// const auto value = vaddq(w, k); -// abcd = vsha256hq(abef, cdgh, value); -// efgh = vsha256h2q(cdgh, abef, value); -// -// Schedule. -// Each word is 128, buffer goes from 16 word_t/uint32_t to 4 xint128_t. -// TODO: these use 4 lane xint128 full block vectorization, but instead -// TODO: of each block filling one lane, a single block packs into all 4 -// TODO: lanes (x 4 xwords = 16 word_t). This divides round count by 4. -// -// sha160 -// SHA-NI -// buffer[Round] = sha1msg2 // xor and rotl1 -// ( -// xor // not using sha1msg1 -// ( -// sha1msg1 // xor (specialized) -// ( -// buffer[Round - 16], -// buffer[Round - 14] -// ), -// buffer[Round - 8] -// ), -// buffer[Round - 3] -// ); -// NEON -// vsha1su1q/vsha1su0q -// -// sha256 -// SHA-NI -// buffer[Round] = -// sha256msg1(buffer[Round - 16], buffer[Round - 15]) + -// sha256msg2(buffer[Round - 7], buffer[Round - 2]); -// NEON -// Not sure about these indexes. -// mijailovic.net/2018/06/06/sha256-armv8 -// buffer[Round] = -// vsha256su0q(buffer[Round - 13], buffer[Round - 9]) -// vsha256su1q(buffer[Round - 13], buffer[Round - 5], -// buffer[Round - 1]); - -BC_POP_WARNING() - -} // namespace shax - -#endif diff --git a/test/hash/sha/vectorization.cpp b/test/hash/sha/vectorization.cpp index bca7baa432..5c1147a22b 100644 --- a/test/hash/sha/vectorization.cpp +++ b/test/hash/sha/vectorization.cpp @@ -17,7 +17,6 @@ * along with this program. If not, see . */ #include "../../test.hpp" -#include "clone/algorithm.hpp" BOOST_AUTO_TEST_SUITE(vectorization_tests) @@ -76,12 +75,12 @@ BOOST_AUTO_TEST_CASE(vectorization__sha256__merkle_root__expected) constexpr auto expected = sha_256::double_hash(expected26, expected27); BOOST_CHECK_EQUAL(sha_256::merkle_root( - { - { 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, - { 8 }, { 9 }, { 10 }, { 11 }, { 12 }, { 13 }, { 14 }, { 15 }, - { 16 }, { 17 }, { 18 }, { 19 }, { 20 }, { 21 }, { 22 }, { 23 }, - { 24 }, { 25 }, { 26 }, { 27 } - }), expected); + { + { 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, + { 8 }, { 9 }, { 10 }, { 11 }, { 12 }, { 13 }, { 14 }, { 15 }, + { 16 }, { 17 }, { 18 }, { 19 }, { 20 }, { 21 }, { 22 }, { 23 }, + { 24 }, { 25 }, { 26 }, { 27 } + }), expected); } BOOST_AUTO_TEST_CASE(vectorization__sha512__merkle_root__expected) @@ -134,12 +133,12 @@ BOOST_AUTO_TEST_CASE(vectorization__sha512__merkle_root__expected) constexpr auto expected = sha_512::double_hash(expected26, expected27); BOOST_CHECK_EQUAL(sha_512::merkle_root( - { - { 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, - { 8 }, { 9 }, { 10 }, { 11 }, { 12 }, { 13 }, { 14 }, { 15 }, - { 16 }, { 17 }, { 18 }, { 19 }, { 20 }, { 21 }, { 22 }, { 23 }, - { 24 }, { 25 }, { 26 }, { 27 } - }), expected); + { + { 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, + { 8 }, { 9 }, { 10 }, { 11 }, { 12 }, { 13 }, { 14 }, { 15 }, + { 16 }, { 17 }, { 18 }, { 19 }, { 20 }, { 21 }, { 22 }, { 23 }, + { 24 }, { 25 }, { 26 }, { 27 } + }), expected); } // Message scheduling diff --git a/test/intrinsics/haves.cpp b/test/intrinsics/haves.cpp index 6942e6179f..ac87b93e36 100644 --- a/test/intrinsics/haves.cpp +++ b/test/intrinsics/haves.cpp @@ -298,7 +298,7 @@ BOOST_AUTO_TEST_CASE(intrinsics_haves__have_neon__always__when_defined__true) #endif } -// types +// is_extended // ---------------------------------------------------------------------------- // is_extended is true even with mock type. @@ -310,35 +310,9 @@ static_assert(is_defined>); static_assert(is_defined>); static_assert(is_defined>); -#if defined(HAVE_SSE4) -static_assert(with() == with_sse41); -BOOST_AUTO_TEST_CASE(intrinsics_haves__have_sse41__always__expected) -{ - BOOST_REQUIRE_EQUAL(have(), have_sse41()); -} -#endif - -#if defined(HAVE_AVX2) -static_assert(with() == with_avx2); -BOOST_AUTO_TEST_CASE(intrinsics_haves__have_avx2__always__expected) -{ - BOOST_REQUIRE_EQUAL(have(), have_avx2()); -} -#endif - -#if defined(HAVE_AVX512) -static_assert(with() == with_avx512); - -BOOST_AUTO_TEST_CASE(intrinsics_haves__have_avx512__always__expected) -{ - BOOST_REQUIRE_EQUAL(have(), have_avx512()); -} -#endif - // capacity [for extended integers] // ---------------------------------------------------------------------------- -#if defined(HAVE_SSE4) static_assert(capacity == 16); // required to fill static_assert(capacity == 16); // full static_assert(capacity == 8); // full @@ -384,9 +358,7 @@ static_assert(capacity == 2); static_assert(capacity == 1); // full static_assert(capacity == 0); ////static_assert(capacity == 0); -#endif -#if defined(HAVE_AVX2) static_assert(capacity == 32); // required to fill static_assert(capacity == 16); // full static_assert(capacity == 8); // full @@ -432,9 +404,7 @@ static_assert(capacity == 2); static_assert(capacity == 1); // full static_assert(capacity == 0); ////static_assert(capacity == 0); -#endif -#if defined(HAVE_AVX512) static_assert(capacity == 64); // required to fill static_assert(capacity == 16); // full static_assert(capacity == 8); // full @@ -480,12 +450,10 @@ static_assert(capacity == 2); static_assert(capacity == 1); // full static_assert(capacity == 0); ////static_assert(capacity == 0); -#endif // to_extended // ---------------------------------------------------------------------------- -#if defined(HAVE_AVX2) && defined(HAVE_SSE4) && defined(HAVE_AVX512) ////static_assert(is_same_type, xint512_t>); static_assert(is_same_type, xint512_t>); // full static_assert(is_same_type, xint512_t>); @@ -543,6 +511,5 @@ static_assert(is_same_type, xint256_t>); static_assert(is_same_type, xint128_t>); // full static_assert(is_same_type, uint64_t>); // full ////static_assert(is_same_type, uint64_t>); -#endif BOOST_AUTO_TEST_SUITE_END() diff --git a/test/stream/iostream/iostream.cpp b/test/stream/iostream/iostream.cpp new file mode 100644 index 0000000000..ba98dce2be --- /dev/null +++ b/test/stream/iostream/iostream.cpp @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#include "../../test.hpp" + +BOOST_AUTO_TEST_SUITE(iostream_tests) + +using iostream_chunk = iostream; + +// setstate/clear + +BOOST_AUTO_TEST_CASE(iostream__setstate__goodbit__goodbit) +{ + data_chunk empty{}; + iostream_chunk stream{ empty }; + stream.setstate(iostream_chunk::goodbit); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__setstate__eofbit__eofbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + stream.setstate(iostream_chunk::eofbit); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::eofbit); + + stream.clear(); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__setstate__failbit__failbit) +{ + data_chunk empty{}; + iostream_chunk stream{ empty }; + stream.setstate(iostream_chunk::failbit); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::failbit); + + stream.clear(); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__setstate__badbit__badbit) +{ + data_chunk empty{}; + iostream_chunk stream{ empty }; + stream.setstate(iostream_chunk::badbit); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::badbit); + + stream.clear(); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__setstate__badbit_failbit__badbit_failbit) +{ + constexpr auto badfail = iostream_chunk::failbit | iostream_chunk::badbit; + + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + stream.setstate(iostream_chunk::badbit); + stream.setstate(iostream_chunk::failbit); + BOOST_REQUIRE(stream.rdstate() == badfail); + + stream.clear(iostream_chunk::badbit); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::badbit); + + stream.clear(iostream_chunk::failbit); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::failbit); + + stream.clear(iostream_chunk::goodbit); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/stream/iostream/istream.cpp b/test/stream/iostream/istream.cpp new file mode 100644 index 0000000000..1d2b0c0a81 --- /dev/null +++ b/test/stream/iostream/istream.cpp @@ -0,0 +1,268 @@ +/** + * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#include "../../test.hpp" + +BOOST_AUTO_TEST_SUITE(iostream_tests) + +using iostream_chunk = iostream; +using seekdir = typename iostream_chunk::seekdir; +using pos_type = typename iostream_chunk::pos_type; +using iostate = typename iostream_chunk::iostate; + +// tellg + +BOOST_AUTO_TEST_CASE(iostream__tellg__empty__zero_goodbit) +{ + data_chunk empty{}; + iostream_chunk stream{ empty }; + BOOST_REQUIRE(is_zero(stream.tellg())); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__tellg__initial__zero_goodbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + const iostream_chunk stream{ chunk }; + BOOST_REQUIRE(is_zero(stream.tellg())); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +// iostream_chunk::beg + +BOOST_AUTO_TEST_CASE(iostream__seekg__zero_from_begin__tellg_zero_goodbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE_EQUAL(stream.seekg(3, iostream_chunk::beg).tellg(), 3); + BOOST_REQUIRE(is_zero(stream.seekg(0, iostream_chunk::beg).tellg())); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__seekg__three_from_begin__tellg_three_goodbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE_EQUAL(stream.seekg(3, iostream_chunk::beg).tellg(), 3); + BOOST_REQUIRE_EQUAL(stream.seekg(3, iostream_chunk::beg).tellg(), 3); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__seekg__size_from_begin__tellg_size_goodbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE_EQUAL(stream.seekg(3, iostream_chunk::beg).tellg(), 3); + BOOST_REQUIRE_EQUAL(stream.seekg(chunk.size(), iostream_chunk::beg).tellg(), to_signed(chunk.size())); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__seekg__overflow_from_begin__unchanged_badbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE(is_zero(stream.seekg(add1(chunk.size()), iostream_chunk::beg).tellg())); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::badbit); +} + +// iostream_chunk::cur + +BOOST_AUTO_TEST_CASE(iostream__seekg__zero_from_three_current__tellg_three_goodbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE_EQUAL(stream.seekg(3, iostream_chunk::beg).tellg(), 3); + BOOST_REQUIRE_EQUAL(stream.seekg(0, iostream_chunk::cur).tellg(), 3); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__seekg__three_from_three_current__tellg_six_goodbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE_EQUAL(stream.seekg(3, iostream_chunk::beg).tellg(), 3); + BOOST_REQUIRE_EQUAL(stream.seekg(3, iostream_chunk::cur).tellg(), 6); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__seekg__size_from_zero_current__tellg_size_goodbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE_EQUAL(stream.seekg(chunk.size(), iostream_chunk::cur).tellg(), to_signed(chunk.size())); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__seekg__overflow_from_three_current__unchanged_badbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE_EQUAL(stream.seekg(3, iostream_chunk::beg).tellg(), 3); + BOOST_REQUIRE(stream.seekg(chunk.size(), iostream_chunk::cur).tellg() == 3); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::badbit); +} + +// iostream_chunk::end + +BOOST_AUTO_TEST_CASE(iostream__seekg__zero_from_end__tellg_size_goodbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE_EQUAL(stream.seekg(3, iostream_chunk::beg).tellg(), 3); + BOOST_REQUIRE_EQUAL(stream.seekg(0, iostream_chunk::end).tellg(), to_signed(chunk.size())); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__seekg__negative_three_from_end__tellg_size_less_three_goodbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE_EQUAL(stream.seekg(3, iostream_chunk::beg).tellg(), 3); + BOOST_REQUIRE_EQUAL(stream.seekg(-3, iostream_chunk::end).tellg(), to_signed(chunk.size()) - 3); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__seekg__negative_size_from_end__tellg_zero_goodbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE(is_zero(stream.seekg(-to_signed(chunk.size()), iostream_chunk::end).tellg())); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__seekg__underflow_from_end__unchanged_badbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE(is_zero(stream.seekg(add1(chunk.size()), iostream_chunk::end).tellg())); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::badbit); +} + +// peek + +BOOST_AUTO_TEST_CASE(iostream__peek__empty__eof_badbit) +{ + constexpr auto eof = std::char_traits::eof(); + data_chunk empty{}; + iostream_chunk stream{ empty }; + BOOST_REQUIRE_EQUAL(stream.peek(), eof); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::badbit); +} + +BOOST_AUTO_TEST_CASE(iostream__peek__chunk__no_advance_expected_goodbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE_EQUAL(stream.peek(), 0x00); + BOOST_REQUIRE(is_zero(stream.tellg())); + BOOST_REQUIRE_EQUAL(stream.peek(), 0x00); + BOOST_REQUIRE(is_zero(stream.tellg())); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__peek__end__eof_badbit) +{ + constexpr auto eof = std::char_traits::eof(); + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE_EQUAL(stream.seekg(0, iostream_chunk::end).tellg(), to_signed(chunk.size())); + BOOST_REQUIRE_EQUAL(stream.peek(), eof); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::badbit); +} + +BOOST_AUTO_TEST_CASE(iostream__peek__chunk__advance_expected_goodbit) +{ + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + BOOST_REQUIRE_EQUAL(stream.peek(), 0x00); + BOOST_REQUIRE_EQUAL(stream.seekg(1, iostream_chunk::cur).tellg(), 1); + BOOST_REQUIRE_EQUAL(stream.peek(), 0x01); + BOOST_REQUIRE_EQUAL(stream.seekg(1, iostream_chunk::cur).tellg(), 2); + BOOST_REQUIRE_EQUAL(stream.peek(), 0x02); + BOOST_REQUIRE_EQUAL(stream.seekg(1, iostream_chunk::cur).tellg(), 3); + BOOST_REQUIRE_EQUAL(stream.peek(), 0x03); + BOOST_REQUIRE_EQUAL(stream.seekg(1, iostream_chunk::cur).tellg(), 4); + BOOST_REQUIRE_EQUAL(stream.peek(), 0x04); + BOOST_REQUIRE_EQUAL(stream.seekg(1, iostream_chunk::cur).tellg(), 5); + BOOST_REQUIRE_EQUAL(stream.peek(), 0x05); + BOOST_REQUIRE_EQUAL(stream.seekg(1, iostream_chunk::cur).tellg(), 6); + BOOST_REQUIRE_EQUAL(stream.peek(), 0x06); + BOOST_REQUIRE_EQUAL(stream.seekg(1, iostream_chunk::cur).tellg(), 7); + BOOST_REQUIRE_EQUAL(stream.peek(), 0x07); + BOOST_REQUIRE_EQUAL(stream.seekg(1, iostream_chunk::cur).tellg(), 8); + BOOST_REQUIRE_EQUAL(stream.peek(), 0x08); + BOOST_REQUIRE_EQUAL(stream.seekg(1, iostream_chunk::cur).tellg(), 9); + BOOST_REQUIRE_EQUAL(stream.peek(), 0x09); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +// read + +BOOST_AUTO_TEST_CASE(iostream__read__none_empty__goodbit) +{ + data_chunk buffer{}; + data_chunk empty{}; + iostream_chunk stream{ empty }; + stream.read(system::pointer_cast(buffer.data()), buffer.size()); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__read__underflow_empty__badbit) +{ + auto buffer = base16_chunk("00000000000000000000"); + data_chunk empty{}; + iostream_chunk stream{ empty }; + stream.read(system::pointer_cast(buffer.data()), buffer.size()); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::badbit); +} + +BOOST_AUTO_TEST_CASE(iostream__read__underflow_nonempty__badbit) +{ + auto buffer = base16_chunk("00000000000000000000000000"); + auto chunk = base16_chunk("00010203040506070809"); + iostream_chunk stream{ chunk }; + stream.read(system::pointer_cast(buffer.data()), add1(chunk.size())); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::badbit); +} + +BOOST_AUTO_TEST_CASE(iostream__read__full_buffer__goodbit) +{ + auto buffer = base16_chunk("00000000000000000000000000"); + auto chunk = base16_chunk("00010203040506070809"); + BOOST_REQUIRE_GE(buffer.size(), chunk.size()); + BOOST_REQUIRE_NE(buffer, chunk); + + iostream_chunk stream{ chunk }; + stream.read(system::pointer_cast(buffer.data()), chunk.size()); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); + buffer.resize(chunk.size()); + BOOST_REQUIRE_EQUAL(buffer, chunk); +} + +// reader + +BOOST_AUTO_TEST_CASE(iostream__reader__read_8_bytes_big_endian__exected_goodbit) +{ + auto chunk = base16_chunk("010203040506070809"); + iostream_chunk stream{ chunk }; + byte_reader reader{ stream }; + BOOST_REQUIRE_EQUAL(reader.read_8_bytes_big_endian(), 0x0102030405060708_u64); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/stream/iostream/ostream.cpp b/test/stream/iostream/ostream.cpp new file mode 100644 index 0000000000..7a465ef86d --- /dev/null +++ b/test/stream/iostream/ostream.cpp @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#include "../../test.hpp" + +BOOST_AUTO_TEST_SUITE(iostream_tests) + +using iostream_chunk = iostream; +using pos_type = typename iostream_chunk::pos_type; +using iostate = typename iostream_chunk::iostate; +const auto chunk = base16_chunk("00010203040506070809"); + +// tellp + +BOOST_AUTO_TEST_CASE(iostream__tellp__empty__zero_goodbit) +{ + data_chunk empty{}; + iostream_chunk stream{ empty }; + BOOST_REQUIRE(is_zero(stream.tellp())); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__tellp__initial__zero_goodbit) +{ + data_chunk empty{}; + iostream_chunk stream{ empty }; + BOOST_REQUIRE(is_zero(stream.tellp())); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +// write + +BOOST_AUTO_TEST_CASE(iostream__write__none_empty__goodbit) +{ + const data_chunk buffer{}; + data_chunk empty{}; + iostream_chunk stream{ empty }; + stream.write(system::pointer_cast(buffer.data()), buffer.size()); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); +} + +BOOST_AUTO_TEST_CASE(iostream__write__overflow_empty__badbit) +{ + const auto buffer = base16_chunk("00010203040506070809"); + data_chunk empty{}; + iostream_chunk stream{ empty }; + stream.write(system::pointer_cast(buffer.data()), buffer.size()); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::badbit); +} + +BOOST_AUTO_TEST_CASE(iostream__write__overflow_nonempty__badbit) +{ + const auto buffer = base16_chunk("00010203040506070809"); + auto chunk = base16_chunk("000000000000"); + iostream_chunk stream{ chunk }; + stream.write(system::pointer_cast(buffer.data()), buffer.size()); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::badbit); +} + +BOOST_AUTO_TEST_CASE(iostream__write__full_buffer__goodbit) +{ + const auto buffer = base16_chunk("00010203040506070809"); + auto chunk = base16_chunk("00000000000000000000000000"); + BOOST_REQUIRE_GE(chunk.size(), buffer.size()); + BOOST_REQUIRE_NE(buffer, chunk); + + iostream_chunk stream{ chunk }; + stream.write(system::pointer_cast(buffer.data()), buffer.size()); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); + chunk.resize(buffer.size()); + BOOST_REQUIRE_EQUAL(buffer, chunk); +} + +// writer + +BOOST_AUTO_TEST_CASE(iostream__writer__write_8_bytes_big_endian__exected_goodbit) +{ + const auto expected = base16_chunk("010203040506070800"); + auto chunk = base16_chunk("000000000000000000"); + iostream_chunk stream{ chunk }; + byte_writer writer{ stream }; + writer.write_8_bytes_big_endian(0x0102030405060708_u64); + BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); + BOOST_REQUIRE_EQUAL(chunk, expected); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/stream/simple/iostream.cpp b/test/stream/simple/iostream.cpp deleted file mode 100644 index f628b0f80e..0000000000 --- a/test/stream/simple/iostream.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#include "../../test.hpp" - -BOOST_AUTO_TEST_SUITE(iostream_tests) - -using iostream_chunk = istream; -using seekdir = typename iostream_chunk::seekdir; -using pos_type = typename iostream_chunk::pos_type; -using iostate = typename iostream_chunk::iostate; -auto chunk = base16_chunk("01020304050607080900"); - -BOOST_AUTO_TEST_CASE(iostream__setstate__goodbit__goodbit) -{ - iostream_chunk stream{ {} }; - stream.setstate(iostream_chunk::goodbit); - BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(iostream__tellg__initial__zero_goodbit) -{ - const iostream_chunk stream{ chunk }; - BOOST_REQUIRE(is_zero(stream.tellg())); - BOOST_REQUIRE(stream.rdstate() == iostream_chunk::goodbit); -} - -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/test/stream/simple/istream.cpp b/test/stream/simple/istream.cpp deleted file mode 100644 index e238f55416..0000000000 --- a/test/stream/simple/istream.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/** - * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#include "../../test.hpp" - -BOOST_AUTO_TEST_SUITE(istream_tests) - -using istream_chunk = istream; -using seekdir = typename istream_chunk::seekdir; -using pos_type = typename istream_chunk::pos_type; -using iostate = typename istream_chunk::iostate; -const auto chunk = base16_chunk("00010203040506070809"); - -// setstate/clear - -BOOST_AUTO_TEST_CASE(istream__setstate__goodbit__goodbit) -{ - istream_chunk stream{ {} }; - stream.setstate(istream_chunk::goodbit); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__setstate__eofbit__eofbit) -{ - istream_chunk stream{ chunk }; - stream.setstate(istream_chunk::eofbit); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::eofbit); - - stream.clear(); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__setstate__failbit__failbit) -{ - istream_chunk stream{ {} }; - stream.setstate(istream_chunk::failbit); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::failbit); - - stream.clear(); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__setstate__badbit__badbit) -{ - istream_chunk stream{ {} }; - stream.setstate(istream_chunk::badbit); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::badbit); - - stream.clear(); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__setstate__badbit_failbit__badbit_failbit) -{ - constexpr auto badfail = istream_chunk::failbit | istream_chunk::badbit; - - istream_chunk stream{ chunk }; - stream.setstate(istream_chunk::badbit); - stream.setstate(istream_chunk::failbit); - BOOST_REQUIRE(stream.rdstate() == badfail); - - stream.clear(istream_chunk::badbit); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::badbit); - - stream.clear(istream_chunk::failbit); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::failbit); - - stream.clear(istream_chunk::goodbit); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -// tellg - -BOOST_AUTO_TEST_CASE(istream__tellg__empty__zero_goodbit) -{ - const istream_chunk stream{ {} }; - BOOST_REQUIRE(is_zero(stream.tellg())); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__tellg__initial__zero_goodbit) -{ - const istream_chunk stream{ chunk }; - BOOST_REQUIRE(is_zero(stream.tellg())); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -// istream_chunk::beg - -BOOST_AUTO_TEST_CASE(istream__seekg__zero_from_begin__tellg_zero_goodbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE_EQUAL(stream.seekg(3, istream_chunk::beg).tellg(), 3); - BOOST_REQUIRE(is_zero(stream.seekg(0, istream_chunk::beg).tellg())); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__seekg__three_from_begin__tellg_three_goodbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE_EQUAL(stream.seekg(3, istream_chunk::beg).tellg(), 3); - BOOST_REQUIRE_EQUAL(stream.seekg(3, istream_chunk::beg).tellg(), 3); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__seekg__size_from_begin__tellg_size_goodbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE_EQUAL(stream.seekg(3, istream_chunk::beg).tellg(), 3); - BOOST_REQUIRE_EQUAL(stream.seekg(chunk.size(), istream_chunk::beg).tellg(), to_signed(chunk.size())); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__seekg__overflow_from_begin__unchanged_badbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE(is_zero(stream.seekg(add1(chunk.size()), istream_chunk::beg).tellg())); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::badbit); -} - -// istream_chunk::cur - -BOOST_AUTO_TEST_CASE(istream__seekg__zero_from_three_current__tellg_three_goodbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE_EQUAL(stream.seekg(3, istream_chunk::beg).tellg(), 3); - BOOST_REQUIRE_EQUAL(stream.seekg(0, istream_chunk::cur).tellg(), 3); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__seekg__three_from_three_current__tellg_six_goodbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE_EQUAL(stream.seekg(3, istream_chunk::beg).tellg(), 3); - BOOST_REQUIRE_EQUAL(stream.seekg(3, istream_chunk::cur).tellg(), 6); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__seekg__size_from_zero_current__tellg_size_goodbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE_EQUAL(stream.seekg(chunk.size(), istream_chunk::cur).tellg(), to_signed(chunk.size())); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__seekg__overflow_from_three_current__unchanged_badbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE_EQUAL(stream.seekg(3, istream_chunk::beg).tellg(), 3); - BOOST_REQUIRE(stream.seekg(chunk.size(), istream_chunk::cur).tellg() == 3); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::badbit); -} - -// istream_chunk::end - -BOOST_AUTO_TEST_CASE(istream__seekg__zero_from_end__tellg_size_goodbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE_EQUAL(stream.seekg(3, istream_chunk::beg).tellg(), 3); - BOOST_REQUIRE_EQUAL(stream.seekg(0, istream_chunk::end).tellg(), to_signed(chunk.size())); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__seekg__negative_three_from_end__tellg_size_less_three_goodbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE_EQUAL(stream.seekg(3, istream_chunk::beg).tellg(), 3); - BOOST_REQUIRE_EQUAL(stream.seekg(-3, istream_chunk::end).tellg(), to_signed(chunk.size()) - 3); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__seekg__negative_size_from_end__tellg_zero_goodbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE(is_zero(stream.seekg(-to_signed(chunk.size()), istream_chunk::end).tellg())); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__seekg__underflow_from_end__unchanged_badbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE(is_zero(stream.seekg(add1(chunk.size()), istream_chunk::end).tellg())); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::badbit); -} - -// peek - -BOOST_AUTO_TEST_CASE(istream__peek__empty__eof_badbit) -{ - constexpr auto eof = std::char_traits::eof(); - - istream_chunk stream{ {} }; - BOOST_REQUIRE_EQUAL(stream.peek(), eof); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::badbit); -} - -BOOST_AUTO_TEST_CASE(istream__peek__chunk__no_advance_expected_goodbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE_EQUAL(stream.peek(), 0x00); - BOOST_REQUIRE(is_zero(stream.tellg())); - BOOST_REQUIRE_EQUAL(stream.peek(), 0x00); - BOOST_REQUIRE(is_zero(stream.tellg())); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__peek__end__eof_badbit) -{ - constexpr auto eof = std::char_traits::eof(); - - istream_chunk stream{ chunk }; - BOOST_REQUIRE_EQUAL(stream.seekg(0, istream_chunk::end).tellg(), to_signed(chunk.size())); - BOOST_REQUIRE_EQUAL(stream.peek(), eof); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::badbit); -} - -BOOST_AUTO_TEST_CASE(istream__peek__chunk__advance_expected_goodbit) -{ - istream_chunk stream{ chunk }; - BOOST_REQUIRE_EQUAL(stream.peek(), 0x00); - BOOST_REQUIRE_EQUAL(stream.seekg(1, istream_chunk::cur).tellg(), 1); - BOOST_REQUIRE_EQUAL(stream.peek(), 0x01); - BOOST_REQUIRE_EQUAL(stream.seekg(1, istream_chunk::cur).tellg(), 2); - BOOST_REQUIRE_EQUAL(stream.peek(), 0x02); - BOOST_REQUIRE_EQUAL(stream.seekg(1, istream_chunk::cur).tellg(), 3); - BOOST_REQUIRE_EQUAL(stream.peek(), 0x03); - BOOST_REQUIRE_EQUAL(stream.seekg(1, istream_chunk::cur).tellg(), 4); - BOOST_REQUIRE_EQUAL(stream.peek(), 0x04); - BOOST_REQUIRE_EQUAL(stream.seekg(1, istream_chunk::cur).tellg(), 5); - BOOST_REQUIRE_EQUAL(stream.peek(), 0x05); - BOOST_REQUIRE_EQUAL(stream.seekg(1, istream_chunk::cur).tellg(), 6); - BOOST_REQUIRE_EQUAL(stream.peek(), 0x06); - BOOST_REQUIRE_EQUAL(stream.seekg(1, istream_chunk::cur).tellg(), 7); - BOOST_REQUIRE_EQUAL(stream.peek(), 0x07); - BOOST_REQUIRE_EQUAL(stream.seekg(1, istream_chunk::cur).tellg(), 8); - BOOST_REQUIRE_EQUAL(stream.peek(), 0x08); - BOOST_REQUIRE_EQUAL(stream.seekg(1, istream_chunk::cur).tellg(), 9); - BOOST_REQUIRE_EQUAL(stream.peek(), 0x09); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -// read - -BOOST_AUTO_TEST_CASE(istream__read__none_empty__goodbit) -{ - auto buffer = base16_chunk(""); - - istream_chunk stream{ {} }; - stream.read(system::pointer_cast(buffer.data()), buffer.size()); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(istream__read__underflow_empty__badbit) -{ - auto buffer = base16_chunk("00000000000000000000"); - - istream_chunk stream{ {} }; - stream.read(system::pointer_cast(buffer.data()), buffer.size()); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::badbit); -} - -BOOST_AUTO_TEST_CASE(istream__read__underflow_nonempty__badbit) -{ - auto buffer = base16_chunk("00000000000000000000000000"); - - istream_chunk stream{ chunk }; - stream.read(system::pointer_cast(buffer.data()), add1(chunk.size())); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::badbit); -} - -BOOST_AUTO_TEST_CASE(istream__read__full_buffer__goodbit) -{ - auto buffer = base16_chunk("00000000000000000000000000"); - BOOST_REQUIRE_GE(buffer.size(), chunk.size()); - BOOST_REQUIRE_NE(buffer, chunk); - - istream_chunk stream{ chunk }; - stream.read(system::pointer_cast(buffer.data()), chunk.size()); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); - buffer.resize(chunk.size()); - BOOST_REQUIRE_EQUAL(buffer, chunk); -} - -// reader - -BOOST_AUTO_TEST_CASE(istream__reader__read_8_bytes_big_endian__exected_goodbit) -{ - const auto chunk = base16_chunk("010203040506070809"); - istream_chunk stream{ chunk }; - byte_reader reader{ stream }; - BOOST_REQUIRE_EQUAL(reader.read_8_bytes_big_endian(), 0x0102030405060708_u64); - BOOST_REQUIRE(stream.rdstate() == istream_chunk::goodbit); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/stream/simple/ostream.cpp b/test/stream/simple/ostream.cpp deleted file mode 100644 index 7e2887c077..0000000000 --- a/test/stream/simple/ostream.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/** - * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#include "../../test.hpp" - -BOOST_AUTO_TEST_SUITE(ostream_tests) - -using ostream_chunk = ostream; -using pos_type = typename ostream_chunk::pos_type; -using iostate = typename ostream_chunk::iostate; -const auto chunk = base16_chunk("00010203040506070809"); - -// setstate/clear - -BOOST_AUTO_TEST_CASE(ostream__setstate__goodbit__goodbit) -{ - auto chunk = base16_chunk(""); - ostream_chunk stream{ chunk }; - stream.setstate(ostream_chunk::goodbit); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(ostream__setstate__eofbit__eofbit) -{ - auto chunk = base16_chunk("00000000000000000000000000"); - ostream_chunk stream{ chunk }; - stream.setstate(ostream_chunk::eofbit); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::eofbit); - - stream.clear(); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(ostream__setstate__failbit__failbit) -{ - auto chunk = base16_chunk(""); - ostream_chunk stream{ chunk }; - stream.setstate(ostream_chunk::failbit); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::failbit); - - stream.clear(); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(ostream__setstate__badbit__badbit) -{ - auto chunk = base16_chunk(""); - ostream_chunk stream{ chunk }; - stream.setstate(ostream_chunk::badbit); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::badbit); - - stream.clear(); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(ostream__setstate__badbit_failbit__badbit_failbit) -{ - constexpr auto badfail = ostream_chunk::failbit | ostream_chunk::badbit; - - auto chunk = base16_chunk("00000000000000000000000000"); - ostream_chunk stream{ chunk }; - stream.setstate(ostream_chunk::badbit); - stream.setstate(ostream_chunk::failbit); - BOOST_REQUIRE(stream.rdstate() == badfail); - - stream.clear(ostream_chunk::badbit); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::badbit); - - stream.clear(ostream_chunk::failbit); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::failbit); - - stream.clear(ostream_chunk::goodbit); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::goodbit); -} - -// tellp - -BOOST_AUTO_TEST_CASE(ostream__tellp__empty__zero_goodbit) -{ - auto chunk = base16_chunk(""); - ostream_chunk stream{ chunk }; - BOOST_REQUIRE(is_zero(stream.tellp())); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(ostream__tellp__initial__zero_goodbit) -{ - auto chunk = base16_chunk(""); - ostream_chunk stream{ chunk }; - BOOST_REQUIRE(is_zero(stream.tellp())); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::goodbit); -} - -// write - -BOOST_AUTO_TEST_CASE(ostream__write__none_empty__goodbit) -{ - const auto buffer = base16_chunk(""); - auto chunk = base16_chunk(""); - ostream_chunk stream{ chunk }; - stream.write(system::pointer_cast(buffer.data()), buffer.size()); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::goodbit); -} - -BOOST_AUTO_TEST_CASE(ostream__write__overflow_empty__badbit) -{ - const auto buffer = base16_chunk("00010203040506070809"); - auto chunk = base16_chunk(""); - ostream_chunk stream{ chunk }; - stream.write(system::pointer_cast(buffer.data()), buffer.size()); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::badbit); -} - -BOOST_AUTO_TEST_CASE(ostream__write__overflow_nonempty__badbit) -{ - const auto buffer = base16_chunk("00010203040506070809"); - auto chunk = base16_chunk("000000000000"); - ostream_chunk stream{ chunk }; - stream.write(system::pointer_cast(buffer.data()), buffer.size()); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::badbit); -} - -BOOST_AUTO_TEST_CASE(ostream__write__full_buffer__goodbit) -{ - const auto buffer = base16_chunk("00010203040506070809"); - auto chunk = base16_chunk("00000000000000000000000000"); - BOOST_REQUIRE_GE(chunk.size(), buffer.size()); - BOOST_REQUIRE_NE(buffer, chunk); - - ostream_chunk stream{ chunk }; - stream.write(system::pointer_cast(buffer.data()), buffer.size()); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::goodbit); - chunk.resize(buffer.size()); - BOOST_REQUIRE_EQUAL(buffer, chunk); -} - -// writer - -BOOST_AUTO_TEST_CASE(ostream__writer__write_8_bytes_big_endian__exected_goodbit) -{ - const auto expected = base16_chunk("010203040506070800"); - auto chunk = base16_chunk("000000000000000000"); - ostream_chunk stream{ chunk }; - byte_writer writer{ stream }; - writer.write_8_bytes_big_endian(0x0102030405060708_u64); - BOOST_REQUIRE(stream.rdstate() == ostream_chunk::goodbit); - BOOST_REQUIRE_EQUAL(chunk, expected); -} - -BOOST_AUTO_TEST_SUITE_END()