diff options
-rw-r--r-- | .gitmodules | 6 | ||||
m--------- | include/boost/afio/boost-lite | 0 | ||||
m--------- | include/boost/afio/gsl-lite | 0 | ||||
m--------- | include/boost/afio/outcome | 0 | ||||
-rw-r--r-- | include/boost/afio/v2.0/algorithm/shared_fs_mutex/atomic_append.hpp | 10 | ||||
-rw-r--r-- | include/boost/afio/v2.0/algorithm/shared_fs_mutex/base.hpp | 17 | ||||
-rw-r--r-- | include/boost/afio/v2.0/algorithm/shared_fs_mutex/lock_files.hpp | 2 | ||||
-rw-r--r-- | include/boost/afio/v2.0/algorithm/shared_fs_mutex/memory_map.hpp | 2 | ||||
-rw-r--r-- | include/boost/afio/v2.0/config.hpp | 8 | ||||
-rw-r--r-- | include/boost/afio/v2.0/detail/impl/windows/utils.ipp | 527 | ||||
-rw-r--r-- | include/boost/afio/v2.0/utils.hpp | 472 | ||||
m--------- | test/kerneltest | 0 | ||||
-rw-r--r-- | test/tests/shared_fs_mutex.cpp | 5 |
13 files changed, 23 insertions, 1026 deletions
diff --git a/.gitmodules b/.gitmodules index 40de0f57..36346270 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,12 +10,6 @@ branch = master fetchRecurseSubmodules = true ignore = untracked -[submodule "include/boost/afio/gsl-lite"] - path = include/boost/afio/gsl-lite - url = https://github.com/martinmoene/gsl-lite.git - branch = master - fetchRecurseSubmodules = true - ignore = untracked [submodule "include/boost/afio/outcome"] path = include/boost/afio/outcome url = https://github.com/ned14/boost.outcome.git diff --git a/include/boost/afio/boost-lite b/include/boost/afio/boost-lite -Subproject 447601b03f68a52b181bad848e4b46b97386bf7 +Subproject fca658ace4399663912f77d52bb7dc0310c1f49 diff --git a/include/boost/afio/gsl-lite b/include/boost/afio/gsl-lite deleted file mode 160000 -Subproject f436d33188b0117c1ecaa40ad9ebadabfdc69c3 diff --git a/include/boost/afio/outcome b/include/boost/afio/outcome -Subproject bbf2bbafa512d64d79ab9e5d05adbc389c315ea +Subproject bd8560354cfd1e2e26039f411685d2111c275b7 diff --git a/include/boost/afio/v2.0/algorithm/shared_fs_mutex/atomic_append.hpp b/include/boost/afio/v2.0/algorithm/shared_fs_mutex/atomic_append.hpp index c3beb32d..d73c2c59 100644 --- a/include/boost/afio/v2.0/algorithm/shared_fs_mutex/atomic_append.hpp +++ b/include/boost/afio/v2.0/algorithm/shared_fs_mutex/atomic_append.hpp @@ -148,7 +148,7 @@ namespace algorithm else stl11::this_thread::yield(); // No timeout as this should very rarely block for any significant length of time - } while(_header.hash != utils::fast_hash::hash(((char *) &_header) + 16, sizeof(_header) - 16)); + } while(_header.hash != boost_lite::algorithm::hash::fast_hash::hash(((char *) &_header) + 16, sizeof(_header) - 16)); return make_result<void>(); } @@ -201,7 +201,7 @@ namespace algorithm header.first_known_good = sizeof(header); header.first_after_hole_punch = sizeof(header); if(!skip_hashing) - header.hash = utils::fast_hash::hash(((char *) &header) + 16, sizeof(header) - 16); + header.hash = boost_lite::algorithm::hash::fast_hash::hash(((char *) &header) + 16, sizeof(header) - 16); BOOST_OUTCOME_FILTER_ERROR(_, ret.write(0, (char *) &header, sizeof(header))); (void) _; } @@ -245,7 +245,7 @@ namespace algorithm lock_request.items = out.entities.size(); memcpy(lock_request.entities, out.entities.data(), sizeof(lock_request.entities[0]) * out.entities.size()); if(!_skip_hashing) - lock_request.hash = utils::fast_hash::hash(((char *) &lock_request) + 16, sizeof(lock_request) - 16); + lock_request.hash = boost_lite::algorithm::hash::fast_hash::hash(((char *) &lock_request) + 16, sizeof(lock_request) - 16); // My lock request will be the file's current length or higher BOOST_OUTCOME_FILTER_ERROR(my_lock_request_offset, _h.length()); { @@ -336,7 +336,7 @@ namespace algorithm // If record hash doesn't match contents it's a torn read, reload if(!_skip_hashing) { - if(record->hash != utils::fast_hash::hash(((char *) record) + 16, sizeof(atomic_append_detail::lock_request) - 16)) + if(record->hash != boost_lite::algorithm::hash::fast_hash::hash(((char *) record) + 16, sizeof(atomic_append_detail::lock_request) - 16)) goto reload; } @@ -479,7 +479,7 @@ namespace algorithm } ++_header.generation; if(!_skip_hashing) - _header.hash = utils::fast_hash::hash(((char *) &_header) + 16, sizeof(_header) - 16); + _header.hash = boost_lite::algorithm::hash::fast_hash::hash(((char *) &_header) + 16, sizeof(_header) - 16); // Rewrite the first part of the header only (void) _h.write(0, (char *) &_header, 48); } diff --git a/include/boost/afio/v2.0/algorithm/shared_fs_mutex/base.hpp b/include/boost/afio/v2.0/algorithm/shared_fs_mutex/base.hpp index 7d429a48..83e72147 100644 --- a/include/boost/afio/v2.0/algorithm/shared_fs_mutex/base.hpp +++ b/include/boost/afio/v2.0/algorithm/shared_fs_mutex/base.hpp @@ -33,7 +33,8 @@ DEALINGS IN THE SOFTWARE. #define BOOST_AFIO_SHARED_FS_MUTEX_BASE_HPP #include "../../handle.hpp" -#include "../../utils.hpp" + +#include "../boost-lite/include/algorithm/hash.hpp" //! \file base.hpp Provides algorithm::shared_fs_mutex::shared_fs_mutex @@ -47,7 +48,7 @@ namespace algorithm //! Unsigned 64 bit integer using uint64 = unsigned long long; //! Unsigned 128 bit integer - using uint128 = utils::uint128; + using uint128 = boost_lite::integers128::uint128; /*! \class shared_fs_mutex \brief Abstract base class for an object which protects shared filing system resources @@ -98,14 +99,6 @@ namespace algorithm using entities_type = span<entity_type>; protected: -#ifdef __cpp_relaxed_constexpr - static constexpr bool _entity_type_endian_check() - { - entity_type v(0, true); - return v._init != 1; - } - static_assert(_entity_type_endian_check(), "entity_type.exclusive is setting the bottom bit, endian problems?"); -#endif constexpr shared_fs_mutex() {} public: @@ -114,13 +107,13 @@ namespace algorithm //! Generates an entity id from a sequence of bytes entity_type entity_from_buffer(const char *buffer, size_t bytes, bool exclusive = true) noexcept { - uint128 hash = utils::fast_hash::hash(buffer, bytes); + uint128 hash = boost_lite::algorithm::hash::fast_hash::hash(buffer, bytes); return entity_type(hash.as_longlongs[0] ^ hash.as_longlongs[1], exclusive); } //! Generates an entity id from a string template <typename T> entity_type entity_from_string(const std::basic_string<T> &str, bool exclusive = true) noexcept { - uint128 hash = utils::fast_hash::hash(str); + uint128 hash = boost_lite::algorithm::hash::fast_hash::hash(str); return entity_type(hash.as_longlongs[0] ^ hash.as_longlongs[1], exclusive); } //! Generates a cryptographically random entity id. diff --git a/include/boost/afio/v2.0/algorithm/shared_fs_mutex/lock_files.hpp b/include/boost/afio/v2.0/algorithm/shared_fs_mutex/lock_files.hpp index 546390fe..58517b1a 100644 --- a/include/boost/afio/v2.0/algorithm/shared_fs_mutex/lock_files.hpp +++ b/include/boost/afio/v2.0/algorithm/shared_fs_mutex/lock_files.hpp @@ -133,7 +133,7 @@ namespace algorithm for(n = 0; n < out.entities.size(); n++) { auto v = out.entities[n].value; - entity_paths[n] = _path / utils::to_hex_string(span<char>((char *) &v, 8)); + entity_paths[n] = _path / boost_lite::algorithm::string::to_hex_string(span<char>((char *) &v, 8)); } _hs.resize(out.entities.size()); do diff --git a/include/boost/afio/v2.0/algorithm/shared_fs_mutex/memory_map.hpp b/include/boost/afio/v2.0/algorithm/shared_fs_mutex/memory_map.hpp index 5734dd78..ee1e995b 100644 --- a/include/boost/afio/v2.0/algorithm/shared_fs_mutex/memory_map.hpp +++ b/include/boost/afio/v2.0/algorithm/shared_fs_mutex/memory_map.hpp @@ -292,7 +292,7 @@ namespace algorithm unsigned exclusive : 1; }; // Create a cache of entities to their indices, eliding collisions where necessary - static span<_entity_idx> _hash_entities(_entity_idx alignas(16) * entity_to_idx, entities_type &entities) + static span<_entity_idx> _hash_entities(_entity_idx *entity_to_idx, entities_type &entities) { _entity_idx *ep = entity_to_idx; for(size_t n = 0; n < entities.size(); n++) diff --git a/include/boost/afio/v2.0/config.hpp b/include/boost/afio/v2.0/config.hpp index e439a27d..9fcf46d1 100644 --- a/include/boost/afio/v2.0/config.hpp +++ b/include/boost/afio/v2.0/config.hpp @@ -412,13 +412,11 @@ using BOOSTLITE_NAMESPACE::scoped_undo::undoer; BOOST_AFIO_V2_NAMESPACE_END -#if !BOOST_AFIO_HAVE_CXX17_SPAN_IMPLEMENTATION -#include "../gsl-lite/include/gsl.h" +// Bring in a span implementation +#include "../boost-lite/include/span.hpp" BOOST_AFIO_V2_NAMESPACE_BEGIN -template <class T> using span = gsl::span<T>; -using gsl::as_span; +using namespace boost_lite::span; BOOST_AFIO_V2_NAMESPACE_END -#endif #if BOOST_AFIO_LOGGING_LEVEL diff --git a/include/boost/afio/v2.0/detail/impl/windows/utils.ipp b/include/boost/afio/v2.0/detail/impl/windows/utils.ipp index b740f65f..4fb71327 100644 --- a/include/boost/afio/v2.0/detail/impl/windows/utils.ipp +++ b/include/boost/afio/v2.0/detail/impl/windows/utils.ipp @@ -142,533 +142,6 @@ namespace utils } } } - - namespace fash_hash_detail - { - using uint8 = unsigned char; - using uint32 = unsigned int; - using uint64 = unsigned long long; - static constexpr bool ALLOW_UNALIGNED_READS = true; - - static BOOST_FORCEINLINE uint64 Rot64(uint64 x, int k) { return (x << k) | (x >> (64 - k)); } - static BOOST_FORCEINLINE void Mix(const uint64 *data, uint64 &s0, uint64 &s1, uint64 &s2, uint64 &s3, uint64 &s4, uint64 &s5, uint64 &s6, uint64 &s7, uint64 &s8, uint64 &s9, uint64 &s10, uint64 &s11) - { - s0 += data[0]; - s2 ^= s10; - s11 ^= s0; - s0 = Rot64(s0, 11); - s11 += s1; - s1 += data[1]; - s3 ^= s11; - s0 ^= s1; - s1 = Rot64(s1, 32); - s0 += s2; - s2 += data[2]; - s4 ^= s0; - s1 ^= s2; - s2 = Rot64(s2, 43); - s1 += s3; - s3 += data[3]; - s5 ^= s1; - s2 ^= s3; - s3 = Rot64(s3, 31); - s2 += s4; - s4 += data[4]; - s6 ^= s2; - s3 ^= s4; - s4 = Rot64(s4, 17); - s3 += s5; - s5 += data[5]; - s7 ^= s3; - s4 ^= s5; - s5 = Rot64(s5, 28); - s4 += s6; - s6 += data[6]; - s8 ^= s4; - s5 ^= s6; - s6 = Rot64(s6, 39); - s5 += s7; - s7 += data[7]; - s9 ^= s5; - s6 ^= s7; - s7 = Rot64(s7, 57); - s6 += s8; - s8 += data[8]; - s10 ^= s6; - s7 ^= s8; - s8 = Rot64(s8, 55); - s7 += s9; - s9 += data[9]; - s11 ^= s7; - s8 ^= s9; - s9 = Rot64(s9, 54); - s8 += s10; - s10 += data[10]; - s0 ^= s8; - s9 ^= s10; - s10 = Rot64(s10, 22); - s9 += s11; - s11 += data[11]; - s1 ^= s9; - s10 ^= s11; - s11 = Rot64(s11, 46); - s10 += s0; - } - static BOOST_FORCEINLINE void EndPartial(uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3, uint64 &h4, uint64 &h5, uint64 &h6, uint64 &h7, uint64 &h8, uint64 &h9, uint64 &h10, uint64 &h11) - { - h11 += h1; - h2 ^= h11; - h1 = Rot64(h1, 44); - h0 += h2; - h3 ^= h0; - h2 = Rot64(h2, 15); - h1 += h3; - h4 ^= h1; - h3 = Rot64(h3, 34); - h2 += h4; - h5 ^= h2; - h4 = Rot64(h4, 21); - h3 += h5; - h6 ^= h3; - h5 = Rot64(h5, 38); - h4 += h6; - h7 ^= h4; - h6 = Rot64(h6, 33); - h5 += h7; - h8 ^= h5; - h7 = Rot64(h7, 10); - h6 += h8; - h9 ^= h6; - h8 = Rot64(h8, 13); - h7 += h9; - h10 ^= h7; - h9 = Rot64(h9, 38); - h8 += h10; - h11 ^= h8; - h10 = Rot64(h10, 53); - h9 += h11; - h0 ^= h9; - h11 = Rot64(h11, 42); - h10 += h0; - h1 ^= h10; - h0 = Rot64(h0, 54); - } - - static BOOST_FORCEINLINE void End(const uint64 *data, uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3, uint64 &h4, uint64 &h5, uint64 &h6, uint64 &h7, uint64 &h8, uint64 &h9, uint64 &h10, uint64 &h11) - { - h0 += data[0]; - h1 += data[1]; - h2 += data[2]; - h3 += data[3]; - h4 += data[4]; - h5 += data[5]; - h6 += data[6]; - h7 += data[7]; - h8 += data[8]; - h9 += data[9]; - h10 += data[10]; - h11 += data[11]; - EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); - EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); - EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); - } - - static BOOST_FORCEINLINE void ShortMix(uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3) - { - h2 = Rot64(h2, 50); - h2 += h3; - h0 ^= h2; - h3 = Rot64(h3, 52); - h3 += h0; - h1 ^= h3; - h0 = Rot64(h0, 30); - h0 += h1; - h2 ^= h0; - h1 = Rot64(h1, 41); - h1 += h2; - h3 ^= h1; - h2 = Rot64(h2, 54); - h2 += h3; - h0 ^= h2; - h3 = Rot64(h3, 48); - h3 += h0; - h1 ^= h3; - h0 = Rot64(h0, 38); - h0 += h1; - h2 ^= h0; - h1 = Rot64(h1, 37); - h1 += h2; - h3 ^= h1; - h2 = Rot64(h2, 62); - h2 += h3; - h0 ^= h2; - h3 = Rot64(h3, 34); - h3 += h0; - h1 ^= h3; - h0 = Rot64(h0, 5); - h0 += h1; - h2 ^= h0; - h1 = Rot64(h1, 36); - h1 += h2; - h3 ^= h1; - } - - static BOOST_FORCEINLINE void ShortEnd(uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3) - { - h3 ^= h2; - h2 = Rot64(h2, 15); - h3 += h2; - h0 ^= h3; - h3 = Rot64(h3, 52); - h0 += h3; - h1 ^= h0; - h0 = Rot64(h0, 26); - h1 += h0; - h2 ^= h1; - h1 = Rot64(h1, 51); - h2 += h1; - h3 ^= h2; - h2 = Rot64(h2, 28); - h3 += h2; - h0 ^= h3; - h3 = Rot64(h3, 9); - h0 += h3; - h1 ^= h0; - h0 = Rot64(h0, 47); - h1 += h0; - h2 ^= h1; - h1 = Rot64(h1, 54); - h2 += h1; - h3 ^= h2; - h2 = Rot64(h2, 32); - h3 += h2; - h0 ^= h3; - h3 = Rot64(h3, 25); - h0 += h3; - h1 ^= h0; - h0 = Rot64(h0, 63); - h1 += h0; - } - } - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4127) // use of ALLOW_UNALIGNED_READS -#endif - - void fast_hash::short_(uint128 &hash, const void *message, size_t length) noexcept - { - using namespace fash_hash_detail; - uint64 buf[2 * sc_numVars]; - union { - const uint8 *p8; - uint32 *p32; - uint64 *p64; - size_t i; - } u; - - u.p8 = (const uint8 *) message; - - if(!ALLOW_UNALIGNED_READS && (u.i & 0x7)) - { - memcpy(buf, message, length); - u.p64 = buf; - } - - size_t remainder = length % 32; - uint64 a = hash.as_longlongs[0]; - uint64 b = hash.as_longlongs[1]; - uint64 c = sc_const; - uint64 d = sc_const; - - if(length > 15) - { - const uint64 *end = u.p64 + (length / 32) * 4; - - // handle all complete sets of 32 bytes - for(; u.p64 < end; u.p64 += 4) - { - c += u.p64[0]; - d += u.p64[1]; - ShortMix(a, b, c, d); - a += u.p64[2]; - b += u.p64[3]; - } - - // Handle the case of 16+ remaining bytes. - if(remainder >= 16) - { - c += u.p64[0]; - d += u.p64[1]; - ShortMix(a, b, c, d); - u.p64 += 2; - remainder -= 16; - } - } - - // Handle the last 0..15 bytes, and its length - d += ((uint64) length) << 56; - switch(remainder) - { - case 15: - d += ((uint64) u.p8[14]) << 48; - case 14: - d += ((uint64) u.p8[13]) << 40; - case 13: - d += ((uint64) u.p8[12]) << 32; - case 12: - d += u.p32[2]; - c += u.p64[0]; - break; - case 11: - d += ((uint64) u.p8[10]) << 16; - case 10: - d += ((uint64) u.p8[9]) << 8; - case 9: - d += (uint64) u.p8[8]; - case 8: - c += u.p64[0]; - break; - case 7: - c += ((uint64) u.p8[6]) << 48; - case 6: - c += ((uint64) u.p8[5]) << 40; - case 5: - c += ((uint64) u.p8[4]) << 32; - case 4: - c += u.p32[0]; - break; - case 3: - c += ((uint64) u.p8[2]) << 16; - case 2: - c += ((uint64) u.p8[1]) << 8; - case 1: - c += (uint64) u.p8[0]; - break; - case 0: - c += sc_const; - d += sc_const; - } - ShortEnd(a, b, c, d); - hash.as_longlongs[0] = a; - hash.as_longlongs[1] = b; - } - - void fast_hash::add(const char *message, size_t length) noexcept - { - using namespace fash_hash_detail; - uint64 h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11; - size_t newLength = length + m_remainder; - uint8 remainder; - union { - const uint8 *p8; - uint64 *p64; - size_t i; - } u; - const uint64 *end; - - // Is this message fragment too short? If it is, stuff it away. - if(newLength < sc_bufSize) - { - memcpy(&((uint8 *) m_data)[m_remainder], message, length); - m_length = length + m_length; - m_remainder = (uint8) newLength; - return; - } - - // init the variables - if(m_length < sc_bufSize) - { - h0 = h3 = h6 = h9 = m_state[0]; - h1 = h4 = h7 = h10 = m_state[1]; - h2 = h5 = h8 = h11 = sc_const; - } - else - { - h0 = m_state[0]; - h1 = m_state[1]; - h2 = m_state[2]; - h3 = m_state[3]; - h4 = m_state[4]; - h5 = m_state[5]; - h6 = m_state[6]; - h7 = m_state[7]; - h8 = m_state[8]; - h9 = m_state[9]; - h10 = m_state[10]; - h11 = m_state[11]; - } - m_length = length + m_length; - - // if we've got anything stuffed away, use it now - if(m_remainder) - { - uint8 prefix = sc_bufSize - m_remainder; - memcpy(&(((uint8 *) m_data)[m_remainder]), message, prefix); - u.p64 = m_data; - Mix(u.p64, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); - Mix(&u.p64[sc_numVars], h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); - u.p8 = ((const uint8 *) message) + prefix; - length -= prefix; - } - else - { - u.p8 = (const uint8 *) message; - } - - // handle all whole blocks of sc_blockSize bytes - end = u.p64 + (length / sc_blockSize) * sc_numVars; - remainder = (uint8)(length - ((const uint8 *) end - u.p8)); - if(ALLOW_UNALIGNED_READS || (u.i & 0x7) == 0) - { - while(u.p64 < end) - { - Mix(u.p64, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); - u.p64 += sc_numVars; - } - } - else - { - while(u.p64 < end) - { - memcpy(m_data, u.p8, sc_blockSize); - Mix(m_data, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); - u.p64 += sc_numVars; - } - } - - // stuff away the last few bytes - m_remainder = remainder; - memcpy(m_data, end, remainder); - - // stuff away the variables - m_state[0] = h0; - m_state[1] = h1; - m_state[2] = h2; - m_state[3] = h3; - m_state[4] = h4; - m_state[5] = h5; - m_state[6] = h6; - m_state[7] = h7; - m_state[8] = h8; - m_state[9] = h9; - m_state[10] = h10; - m_state[11] = h11; - } - - uint128 fast_hash::finalise() noexcept - { - using namespace fash_hash_detail; - uint128 ret; - // init the variables - if(m_length < sc_bufSize) - { - ret.as_longlongs[0] = m_state[0]; - ret.as_longlongs[1] = m_state[1]; - short_(ret, m_data, m_length); - return ret; - } - - const uint64 *data = (const uint64 *) m_data; - uint8 remainder = m_remainder; - - uint64 h0 = m_state[0]; - uint64 h1 = m_state[1]; - uint64 h2 = m_state[2]; - uint64 h3 = m_state[3]; - uint64 h4 = m_state[4]; - uint64 h5 = m_state[5]; - uint64 h6 = m_state[6]; - uint64 h7 = m_state[7]; - uint64 h8 = m_state[8]; - uint64 h9 = m_state[9]; - uint64 h10 = m_state[10]; - uint64 h11 = m_state[11]; - - if(remainder >= sc_blockSize) - { - // m_data can contain two blocks; handle any whole first block - Mix(data, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); - data += sc_numVars; - remainder -= sc_blockSize; - } - - // mix in the last partial block, and the length mod sc_blockSize - memset(&((uint8 *) data)[remainder], 0, (sc_blockSize - remainder)); - - ((uint8 *) data)[sc_blockSize - 1] = remainder; - - // do some final mixing - End(data, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); - - ret.as_longlongs[0] = h0; - ret.as_longlongs[1] = h1; - return ret; - } - - uint128 fast_hash::hash(const char *message, size_t length, const uint128 &_ret) noexcept - { - uint128 ret(_ret); - using namespace fash_hash_detail; - if(length < sc_bufSize) - { - short_(ret, message, length); - return ret; - } - - uint64 h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11; - uint64 buf[sc_numVars]; - uint64 *end; - union { - const uint8 *p8; - uint64 *p64; - size_t i; - } u; - size_t remainder; - - h0 = h3 = h6 = h9 = ret.as_longlongs[0]; - h1 = h4 = h7 = h10 = ret.as_longlongs[1]; - h2 = h5 = h8 = h11 = sc_const; - - u.p8 = (const uint8 *) message; - end = u.p64 + (length / sc_blockSize) * sc_numVars; - - // handle all whole sc_blockSize blocks of bytes - if(ALLOW_UNALIGNED_READS || ((u.i & 0x7) == 0)) - { - while(u.p64 < end) - { - Mix(u.p64, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); - u.p64 += sc_numVars; - } - } - else - { - while(u.p64 < end) - { - memcpy(buf, u.p64, sc_blockSize); - Mix(buf, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); - u.p64 += sc_numVars; - } - } - - // handle the last partial block of sc_blockSize bytes - remainder = (length - ((const uint8 *) end - (const uint8 *) message)); - memcpy(buf, end, remainder); - memset(((uint8 *) buf) + remainder, 0, sc_blockSize - remainder); - ((uint8 *) buf)[sc_blockSize - 1] = (uint8) remainder; - - // do some final mixing - End(buf, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); - - ret.as_longlongs[0] = h0; - ret.as_longlongs[1] = h1; - return ret; - } - -#ifdef _MSC_VER -#pragma warning(pop) -#endif } BOOST_AFIO_V2_NAMESPACE_END diff --git a/include/boost/afio/v2.0/utils.hpp b/include/boost/afio/v2.0/utils.hpp index 8ff7ab02..cc482e14 100644 --- a/include/boost/afio/v2.0/utils.hpp +++ b/include/boost/afio/v2.0/utils.hpp @@ -37,6 +37,8 @@ DEALINGS IN THE SOFTWARE. #endif #include "config.hpp" +#include "../boost-lite/include/algorithm/string.hpp" + //! \file utils.hpp Provides namespace utils BOOST_AFIO_V2_NAMESPACE_EXPORT_BEGIN @@ -124,121 +126,6 @@ namespace utils */ BOOST_AFIO_HEADERS_ONLY_FUNC_SPEC void random_fill(char *buffer, size_t bytes); -/*! \brief Converts a number to a hex string. Out buffer can be same as in buffer. - -Note that the character range used is a 16 item table of: - -0123456789abcdef - -This lets one pack one byte of input into two bytes of output. - -\ingroup utils -\complexity{O(N) where N is the length of the number.} -\exceptionmodel{Throws exception if output buffer is too small for input.} -*/ -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 6293) // MSVC sanitiser warns that we wrap n in the for loop -#endif - inline size_t to_hex_string(char *out, size_t outlen, const char *_in, size_t inlen) - { - unsigned const char *in = (unsigned const char *) _in; - static constexpr char table[] = "0123456789abcdef"; - if(outlen < inlen * 2) - throw std::invalid_argument("Output buffer too small."); - for(size_t n = inlen - 2; n <= inlen - 2; n -= 2) - { - out[n * 2 + 3] = table[(in[n + 1] >> 4) & 0xf]; - out[n * 2 + 2] = table[in[n + 1] & 0xf]; - out[n * 2 + 1] = table[(in[n] >> 4) & 0xf]; - out[n * 2 + 0] = table[in[n] & 0xf]; - } - if(inlen & 1) - { - out[1] = table[(in[0] >> 4) & 0xf]; - out[0] = table[in[0] & 0xf]; - } - return inlen * 2; - } -#ifdef _MSC_VER -#pragma warning(pop) -#endif - //! \overload - inline size_t to_hex_string(span<char> out, const span<char> in) { return to_hex_string(out.data(), out.size(), in.data(), in.size()); } - //! \overload - inline std::string to_hex_string(span<char> in) - { - std::string out(in.size() * 2, ' '); - to_hex_string(const_cast<char *>(out.data()), out.size(), in.data(), in.size()); - return out; - } - - /*! \brief Converts a hex string to a number. Out buffer can be same as in buffer. - - Note that this routine is about 43% slower than to_hex_string(), half of which is due to input validation. - - \ingroup utils - \complexity{O(N) where N is the length of the string.} - \exceptionmodel{Throws exception if output buffer is too small for input or input size is not multiple of two.} - */ - inline size_t from_hex_string(char *out, size_t outlen, const char *in, size_t inlen) - { - if(inlen % 2) - throw std::invalid_argument("Input buffer not multiple of two."); - if(outlen < inlen / 2) - throw std::invalid_argument("Output buffer too small."); - bool is_invalid = false; - auto fromhex = [&is_invalid](char c) -> unsigned char { -#if 1 - // ASCII starting from 48 is 0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ - // 48 65 97 - static constexpr unsigned char table[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // +10 = 58 - 255, 255, 255, 255, 255, 255, 255, // +7 = 65 - 10, 11, 12, 13, 14, 15, // +6 = 71 - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // +26 = 97 - 10, 11, 12, 13, 14, 15}; - unsigned char r = 255; - if(c >= 48 && c <= 102) - r = table[c - 48]; - if(r == 255) - is_invalid = true; - return r; -#else - if(c >= '0' && c <= '9') - return c - '0'; - if(c >= 'a' && c <= 'f') - return c - 'a' + 10; - if(c >= 'A' && c <= 'F') - return c - 'A' + 10; - BOOST_AFIO_THROW(std::invalid_argument("Input is not hexadecimal.")); -#endif - }; - for(size_t n = 0; n < inlen / 2; n += 4) - { - unsigned char c[8]; - c[0] = fromhex(in[n * 2]); - c[1] = fromhex(in[n * 2 + 1]); - c[2] = fromhex(in[n * 2 + 2]); - c[3] = fromhex(in[n * 2 + 3]); - out[n] = (c[1] << 4) | c[0]; - c[4] = fromhex(in[n * 2 + 4]); - c[5] = fromhex(in[n * 2 + 5]); - out[n + 1] = (c[3] << 4) | c[2]; - c[6] = fromhex(in[n * 2 + 6]); - c[7] = fromhex(in[n * 2 + 7]); - out[n + 2] = (c[5] << 4) | c[4]; - out[n + 3] = (c[7] << 4) | c[6]; - } - for(size_t n = inlen / 2 - (inlen / 2) % 4; n < inlen / 2; n++) - { - unsigned char c1 = fromhex(in[n * 2]), c2 = fromhex(in[n * 2 + 1]); - out[n] = (c2 << 4) | c1; - } - if(is_invalid) - throw std::invalid_argument("Input is not hexadecimal."); - return inlen / 2; - } - /*! \brief Returns a cryptographically random string capable of being used as a filename. Essentially random_fill() + to_hex_string(). \param randomlen The number of bytes of randomness to use for the string. @@ -252,275 +139,10 @@ This lets one pack one byte of input into two bytes of output. size_t outlen = randomlen * 2; std::string ret(outlen, 0); random_fill(const_cast<char *>(ret.data()), randomlen); - to_hex_string(const_cast<char *>(ret.data()), outlen, ret.data(), randomlen); + boost_lite::algorithm::string::to_hex_string(const_cast<char *>(ret.data()), outlen, ret.data(), randomlen); return ret; } -#ifndef BOOST_AFIO_SECDEC_INTRINSICS -#if defined(__GCC__) || defined(__clang__) -#define BOOST_AFIO_SECDEC_INTRINSICS 1 -#elif defined(_MSC_VER) && (defined(_M_X64) || _M_IX86_FP == 1) -#define BOOST_AFIO_SECDEC_INTRINSICS 1 -#endif -#endif -#ifndef BOOST_AFIO_SECDEC_INTRINSICS -#define BOOST_AFIO_SECDEC_INTRINSICS 0 -#endif - /*! \class secded_ecc - \brief Calculates the single error correcting double error detecting (SECDED) Hamming Error Correcting Code for a \em blocksize block of bytes. For example, a secdec_ecc<8> would be the very common 72,64 Hamming code used in ECC RAM, or secdec_ecc<4096> would be for a 32784,32768 Hamming code. - - Did you know that some non-ECC RAM systems can see 1e-12 flips/bit/hour, which is 3.3 bits flipped in a 16Gb RAM system - per 24 hours). See Schroeder, Pinheiro and Weber (2009) 'DRAM Errors in the Wild: A Large-Scale Field Study'. - - After construction during which lookup tables are built, no state is modified and therefore this class is safe for static - storage (indeed if C++ 14 is available, the constructor is constexpr). The maximum number of bits in a code is a good four - billion, I did try limiting it to 65536 for performance but it wasn't worth it, and one might want > 8Kb blocks maybe. - As with all SECDED ECC, undefined behaviour occurs when more than two bits of error are present or the ECC supplied - is incorrect. You should combine this SECDED with a robust hash which can tell you definitively if a buffer is error - free or not rather than relying on this to correctly do so. - - The main intended use case for this routine is calculating the ECC on data being written to disc, and hence that is - where performance has been maximised. It is not expected that this routine will be frequently called on data being read - from disc i.e. only when its hash doesn't match its contents which should be very rare, and then a single bit heal using this routine is attempted - before trying again with the hash. Care was taken that really enormous SECDEDs are fast, in fact tuning was mostly - done for the 32784,32768 code which can heal one bad bit per 4Kb page as the main thing we have in mind is achieving - reliable filing system code on computers without ECC RAM and in which sustained large quantities of random disc i/o produce - a worrying number of flipped bits in a 24 hour period (anywhere between 0 and 3 on my hardware here, average is about 0.8). - - Performance of the fixed block size routine where you supply whole chunks of \em blocksize is therefore \b particularly excellent - as I spent a lot of time tuning it for Ivy Bridge and later out of order architectures: an - amazing 22 cycles per byte for the 32784,32768 code, which is a testament to modern out of order CPUs (remember SECDED inherently must work a bit - at a time, so that's just 2.75 amortised CPU cycles per bit which includes a table load, a bit test, and a conditional XOR) - i.e. it's pushing about 1.5 ops per clock cycle. On my 3.9Ghz i7-3770K here, I see about 170Mb/sec per CPU core. - - The variable length routine is necessarily much slower as it must work in single bytes, and achieves 72 cycles per byte, - or 9 cycles per bit (64Mb/sec per CPU core). - - \ingroup utils - \complexity{O(N) where N is the blocksize} - \exceptionmodel{Throws constexpr exceptions in constructor only, otherwise entirely noexcept.} - */ - template <size_t blocksize> class secded_ecc - { - public: - typedef unsigned int result_type; //!< The largest ECC which can be calculated - private: - static constexpr size_t bits_per_byte = 8; - typedef unsigned char unit_type; // The batch unit of processing - result_type bitsvalid; - // Many CPUs (x86) are slow doing variable bit shifts, so keep a table - result_type ecc_twospowers[sizeof(result_type) * bits_per_byte]; - unsigned short ecc_table[blocksize * bits_per_byte]; - static bool _is_single_bit_set(result_type x) - { -#ifndef _MSC_VER -#if defined(__i386__) || defined(__x86_64__) -#ifndef __SSE4_2__ - // Do a once off runtime check - static int have_popcnt = [] { - size_t cx, dx; -#if defined(__x86_64__) - asm("cpuid" : "=c"(cx), "=d"(dx) : "a"(1), "b"(0), "c"(0), "d"(0)); -#else - asm("pushl %%ebx\n\tcpuid\n\tpopl %%ebx\n\t" : "=c"(cx), "=d"(dx) : "a"(1), "c"(0), "d"(0)); -#endif - return (dx & (1 << 26)) != 0 /*SSE2*/ && (cx & (1 << 23)) != 0 /*POPCNT*/; - }(); - if(have_popcnt) -#endif - { - unsigned count; - asm("popcnt %1,%0" : "=r"(count) : "rm"(x) : "cc"); - return count == 1; - } -#endif - return __builtin_popcount(x) == 1; -#else - x -= (x >> 1) & 0x55555555; - x = (x & 0x33333333) + ((x >> 2) & 0x33333333); - x = (x + (x >> 4)) & 0x0f0f0f0f; - unsigned int count = (x * 0x01010101) >> 24; - return count == 1; -#if 0 - x -= (x >> 1) & 0x5555555555555555ULL; - x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL); - x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL; - unsigned long long count = (x * 0x0101010101010101ULL) >> 56; - return count == 1; -#endif -#endif - } - - public: - //! Constructs an instance, configuring the necessary lookup tables - BOOST_CXX14_CONSTEXPR secded_ecc() - { - for(size_t n = 0; n < sizeof(result_type) * bits_per_byte; n++) - ecc_twospowers[n] = ((result_type) 1 << n); - result_type length = blocksize * bits_per_byte; - // This is (data bits + parity bits + 1) <= 2^(parity bits) - for(result_type p = 1; p < sizeof(result_type) * bits_per_byte; p++) - if((length + p + 1) <= ecc_twospowers[p]) - { - bitsvalid = p; - break; - } - if((bits_per_byte - 1 + bitsvalid) / bits_per_byte > sizeof(result_type)) - throw std::runtime_error("secdec_ecc: ECC would exceed the size of result_type!"); - for(result_type i = 0; i < blocksize * bits_per_byte; i++) - { - // Make a code bit - result_type b = i + 1; -#if BOOST_AFIO_SECDEC_INTRINSICS && 0 // let constexpr do its thing -#ifdef _MSC_VER - unsigned long _topbit; - _BitScanReverse(&_topbit, b); - result_type topbit = _topbit; -#else - result_type topbit = bits_per_byte * sizeof(result_type) - __builtin_clz(b); -#endif - b += topbit; - if(b >= ecc_twospowers[topbit]) - b++; -// while(b>ecc_twospowers(_topbit+1)) _topbit++; -// b+=_topbit; -// if(b>=ecc_twospowers(_topbit)) b++; -#else - for(size_t p = 0; ecc_twospowers[p] < (b + 1); p++) - b++; -#endif - ecc_table[i] = (unsigned short) b; - if(b > (unsigned short) -1) - throw std::runtime_error("secdec_ecc: Precalculated table has exceeded its bounds"); - } - } - //! The number of bits valid in result_type - constexpr result_type result_bits_valid() const noexcept { return bitsvalid; } - //! Accumulate ECC from fixed size buffer - result_type operator()(result_type ecc, const char *buffer) const noexcept - { - if(blocksize < sizeof(unit_type) * 8) - return (*this)(ecc, buffer, blocksize); - // Process in lumps of eight - const unit_type *_buffer = (const unit_type *) buffer; - //#pragma omp parallel for reduction(^:ecc) - for(size_t i = 0; i < blocksize; i += sizeof(unit_type) * 8) - { - union { - unsigned long long v; - unit_type c[8]; - }; - result_type prefetch[8]; - v = *(unsigned long long *) (&_buffer[0 + i / sizeof(unit_type)]); // min 1 cycle -#define BOOST_AFIO_ROUND(n) \ - prefetch[0] = ecc_table[(i + 0) * 8 + n]; \ - prefetch[1] = ecc_table[(i + 1) * 8 + n]; \ - prefetch[2] = ecc_table[(i + 2) * 8 + n]; \ - prefetch[3] = ecc_table[(i + 3) * 8 + n]; \ - prefetch[4] = ecc_table[(i + 4) * 8 + n]; \ - prefetch[5] = ecc_table[(i + 5) * 8 + n]; \ - prefetch[6] = ecc_table[(i + 6) * 8 + n]; \ - prefetch[7] = ecc_table[(i + 7) * 8 + n]; \ - if(c[0] & ((unit_type) 1 << n)) \ - ecc ^= prefetch[0]; \ - if(c[1] & ((unit_type) 1 << n)) \ - ecc ^= prefetch[1]; \ - if(c[2] & ((unit_type) 1 << n)) \ - ecc ^= prefetch[2]; \ - if(c[3] & ((unit_type) 1 << n)) \ - ecc ^= prefetch[3]; \ - if(c[4] & ((unit_type) 1 << n)) \ - ecc ^= prefetch[4]; \ - if(c[5] & ((unit_type) 1 << n)) \ - ecc ^= prefetch[5]; \ - if(c[6] & ((unit_type) 1 << n)) \ - ecc ^= prefetch[6]; \ - if(c[7] & ((unit_type) 1 << n)) \ - ecc ^= prefetch[7]; - BOOST_AFIO_ROUND(0) // prefetch = min 8, bit test and xor = min 16, total = 24 - BOOST_AFIO_ROUND(1) - BOOST_AFIO_ROUND(2) - BOOST_AFIO_ROUND(3) - BOOST_AFIO_ROUND(4) - BOOST_AFIO_ROUND(5) - BOOST_AFIO_ROUND(6) - BOOST_AFIO_ROUND(7) -#undef BOOST_AFIO_ROUND // total should be 1+(8*24/3)=65 - } - return ecc; - } - result_type operator()(const char *buffer) const noexcept { return (*this)(0, buffer); } - //! Accumulate ECC from partial buffer where \em length <= \em blocksize - result_type operator()(result_type ecc, const char *buffer, size_t length) const noexcept - { - const unit_type *_buffer = (const unit_type *) buffer; - //#pragma omp parallel for reduction(^:ecc) - for(size_t i = 0; i < length; i += sizeof(unit_type)) - { - unit_type c = _buffer[i / sizeof(unit_type)]; // min 1 cycle - if(!c) // min 1 cycle - continue; - char bitset[bits_per_byte * sizeof(unit_type)]; - result_type prefetch[bits_per_byte * sizeof(unit_type)]; - // Most compilers will roll this out - for(size_t n = 0; n < bits_per_byte * sizeof(unit_type); n++) // min 16 cycles - { - bitset[n] = !!(c & ((unit_type) 1 << n)); - prefetch[n] = ecc_table[i * bits_per_byte + n]; // min 8 cycles - } - result_type localecc = 0; - for(size_t n = 0; n < bits_per_byte * sizeof(unit_type); n++) - { - if(bitset[n]) // min 8 cycles - localecc ^= prefetch[n]; // min 8 cycles - } - ecc ^= localecc; // min 1 cycle. Total cycles = min 43 cycles/byte - } - return ecc; - } - result_type operator()(const char *buffer, size_t length) const noexcept { return (*this)(0, buffer, length); } - //! Given the original ECC and the new ECC for a buffer, find the bad bit. Return (result_type)-1 if not found (e.g. ECC corrupt) - result_type find_bad_bit(result_type good_ecc, result_type bad_ecc) const noexcept - { - result_type length = blocksize * bits_per_byte, eccdiff = good_ecc ^ bad_ecc; - if(_is_single_bit_set(eccdiff)) - return (result_type) -1; - for(result_type i = 0, b = 1; i < length; i++, b++) - { - // Skip parity bits - while(_is_single_bit_set(b)) - b++; - if(b == eccdiff) - return i; - } - return (result_type) -1; - } - //! The outcomes from verify() - enum verify_status - { - corrupt = 0, //!< The buffer had more than a single bit corrupted or the ECC was invalid - okay = 1, //!< The buffer had no errors - healed = 2 //!< The buffer was healed - }; - //! Verifies and heals when possible a buffer, returning non zero if the buffer is error free - verify_status verify(char *buffer, result_type good_ecc) const noexcept - { - result_type this_ecc = (*this)(0, buffer); - if(this_ecc == good_ecc) - return verify_status::okay; // no errors - result_type badbit = find_bad_bit(good_ecc, this_ecc); - if((result_type) -1 == badbit) - return verify_status::corrupt; // parity corrupt? - buffer[badbit / bits_per_byte] ^= (unsigned char) ecc_twospowers[badbit % bits_per_byte]; - this_ecc = (*this)(0, buffer); - if(this_ecc == good_ecc) - return healed; // error healed - // Put the bit back - buffer[badbit / bits_per_byte] ^= (unsigned char) ecc_twospowers[badbit % bits_per_byte]; - return verify_status::corrupt; // more than one bit was corrupt - } - }; - namespace detail { struct large_page_allocation @@ -638,94 +260,6 @@ This lets one pack one byte of input into two bytes of output. }; }; template <class T, class U> inline bool operator==(const page_allocator<T> &, const page_allocator<U> &) noexcept { return true; } - - /*! \union uint128 - \brief An unsigned 128 bit value - */ - union alignas(16) uint128 { - unsigned char as_bytes[16]; - unsigned short as_shorts[8]; - unsigned int as_ints[4]; - unsigned long long as_longlongs[2]; -#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) -#if defined(__x86_64__) || defined(_M_X64) || defined(__SSE2__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2) - // Strongly hint to the compiler what to do here - __m128i as_m128i; -#endif -#endif - //! Default constructor, no bits set - uint128() noexcept {} - //! All bits zero constructor - constexpr uint128(std::nullptr_t) noexcept : as_longlongs{0, 0} {} - private: - static const uint128 &_allbitszero() - { - static uint128 v(nullptr); - return v; - } - - public: - explicit operator bool() const noexcept { return (*this) != _allbitszero(); } - bool operator!() const noexcept { return (*this) == _allbitszero(); } - bool operator==(const uint128 &o) const noexcept { return as_longlongs[1] == o.as_longlongs[1] && as_longlongs[0] == o.as_longlongs[0]; } - bool operator!=(const uint128 &o) const noexcept { return as_longlongs[1] != o.as_longlongs[1] || as_longlongs[0] != o.as_longlongs[0]; } - bool operator<(const uint128 &o) const noexcept { return as_longlongs[0] < o.as_longlongs[0] || (as_longlongs[0] == o.as_longlongs[0] && as_longlongs[1] < o.as_longlongs[1]); } - bool operator<=(const uint128 &o) const noexcept { return as_longlongs[0] < o.as_longlongs[0] || (as_longlongs[0] == o.as_longlongs[0] && as_longlongs[1] <= o.as_longlongs[1]); } - bool operator>(const uint128 &o) const noexcept { return as_longlongs[0] > o.as_longlongs[0] || (as_longlongs[0] == o.as_longlongs[0] && as_longlongs[1] > o.as_longlongs[1]); } - bool operator>=(const uint128 &o) const noexcept { return as_longlongs[0] > o.as_longlongs[0] || (as_longlongs[0] == o.as_longlongs[0] && as_longlongs[1] >= o.as_longlongs[1]); } - }; - static_assert(sizeof(uint128) == 16, "uint128 is not 16 bytes long!"); - static_assert(alignof(uint128) == 16, "uint128 is not aligned to 16 byte multiples!"); - - /*! \class fast_hash - \brief Fast very collision resistant uint128 hash. Currently SpookyHash @ 0.3 cycles/byte. - */ - class BOOST_AFIO_DECL fast_hash - { - using uint8 = unsigned char; - using uint64 = unsigned long long; - - // number of uint64's in internal state - static constexpr size_t sc_numVars = 12; - - // size of the internal state - static constexpr size_t sc_blockSize = sc_numVars * 8; - - // size of buffer of unhashed data, in bytes - static constexpr size_t sc_bufSize = 2 * sc_blockSize; - - // - // sc_const: a constant which: - // * is not zero - // * is odd - // * is a not-very-regular mix of 1's and 0's - // * does not need any other special mathematical properties - // - static constexpr uint64 sc_const = 0xdeadbeefdeadbeefULL; - - uint64 m_data[2 * sc_numVars]; // unhashed data, for partial messages - uint64 m_state[sc_numVars]; // internal state of the hash - size_t m_length; // total length of the input so far - uint8 m_remainder; // length of unhashed data stashed in m_data - - static void short_(uint128 &hash, const void *data, size_t bytes) noexcept; - - public: - //! Initialise the hash with an optional seed - constexpr fast_hash(const uint128 &seed = uint128(nullptr)) noexcept : m_data{0}, m_state{seed.as_longlongs[0], seed.as_longlongs[1]}, m_length(0), m_remainder(0) {} - - //! Hash input - void add(const char *data, size_t bytes) noexcept; - - //! Finalise and return hash - uint128 finalise() noexcept; - - //! Single shot hash of a sequence of bytes - static uint128 hash(const char *data, size_t bytes, const uint128 &seed = uint128(nullptr)) noexcept; - - //! Single shot hash of a span - template <typename T> static uint128 hash(const span<T> &str) noexcept { return hash((char *) str.data(), str.size() * sizeof(T)); } - }; } BOOST_AFIO_V2_NAMESPACE_END diff --git a/test/kerneltest b/test/kerneltest -Subproject 7a6d486f020c61534b1187942648641e1b1b9c2 +Subproject c6e0e8b75a2558ba56d632da9b6c8fef16c8ad7 diff --git a/test/tests/shared_fs_mutex.cpp b/test/tests/shared_fs_mutex.cpp index 87596fbf..174e06e1 100644 --- a/test/tests/shared_fs_mutex.cpp +++ b/test/tests/shared_fs_mutex.cpp @@ -8,6 +8,11 @@ File Created: Aug 2016 #include "../../include/boost/afio/afio.hpp" #include "../kerneltest/include/boost/kerneltest.hpp" +BOOST_KERNELTEST_TEST_KERNEL(unit, afio, shared_fs_mutex, entity_endian, "Tests that afio::algorithm::shared_fs_mutex::entity_type has the right endian", [] { + BOOST_AFIO_V2_NAMESPACE::algorithm::shared_fs_mutex::shared_fs_mutex::entity_type v(0, true); + BOOST_REQUIRE(v._init != 1UL); +}()) + #include <codecvt> #include <unordered_map> |