Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions benchmark/buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <boost/hash2/fnv1a.hpp>
#include <boost/hash2/siphash.hpp>
#include <boost/hash2/xxhash.hpp>
#include <boost/hash2/xxh3.hpp>
#include <boost/hash2/md5.hpp>
#include <boost/hash2/sha1.hpp>
#include <boost/hash2/sha2.hpp>
Expand Down Expand Up @@ -51,6 +52,7 @@ void test( int N, int M )
test_<fnv1a_64>( data, N, M );
test_<xxhash_32>( data, N, M );
test_<xxhash_64>( data, N, M );
test_<xxh3_128>( data, N, M );
test_<siphash_32>( data, N, M );
test_<siphash_64>( data, N, M );
test_<md5_128>( data, N, M );
Expand Down
99 changes: 99 additions & 0 deletions include/boost/hash2/detail/byteswap.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#ifndef BOOST_HASH2_DETAIL_BYTESWAP_HPP_INCLUDED
#define BOOST_HASH2_DETAIL_BYTESWAP_HPP_INCLUDED

// Copyright 2025 Christian Mazakas
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

#include <boost/hash2/detail/is_constant_evaluated.hpp>
#include <boost/config.hpp>
#include <cstdint>

#if defined(BOOST_MSVC)
#include <intrin.h>
#endif

namespace boost
{
namespace hash2
{
namespace detail
{

#if defined(BOOST_GCC) || defined(BOOST_CLANG)

BOOST_CXX14_CONSTEXPR inline std::uint32_t byteswap_impl( std::uint32_t x ) noexcept
{
return __builtin_bswap32( x );
}

BOOST_CXX14_CONSTEXPR inline std::uint64_t byteswap_impl( std::uint64_t x ) noexcept
{
return __builtin_bswap64( x );
}

#elif defined(BOOST_MSVC)

BOOST_CXX14_CONSTEXPR inline std::uint32_t byteswap_impl( std::uint32_t x ) noexcept
{
if( !detail::is_constant_evaluated() )
{
return _byteswap_ulong( x );
}
else
{
// copy-paste the approach used by Core in bit.hpp
std::uint32_t step16 = x << 16 | x >> 16;
return ( ( step16 << 8 ) & 0xff00ff00 ) | ( ( step16 >> 8 ) & 0x00ff00ff );
}
}

BOOST_CXX14_CONSTEXPR inline std::uint64_t byteswap_impl( std::uint64_t x ) noexcept
{
if( !detail::is_constant_evaluated() )
{
return _byteswap_uint64( x );
}
else
{
// copy-paste the approach used by Core in bit.hpp
std::::uint64_t step32 = x << 32 | x >> 32;
std::::uint64_t step16 = ( step32 & 0x0000ffff0000ffffull ) << 16 | ( step32 & 0xffff0000ffff0000ull ) >> 16;
return ( step16 & 0x00ff00ff00ff00ffull ) << 8 | ( step16 & 0xff00ff00ff00ff00ull ) >> 8;
}
}

#else

BOOST_CXX14_CONSTEXPR inline std::uint32_t byteswap_impl( std::uint32_t x ) noexcept
{
// copy-paste the approach used by Core in bit.hpp
std::uint32_t step16 = x << 16 | x >> 16;
return ( ( step16 << 8 ) & 0xff00ff00 ) | ( ( step16 >> 8 ) & 0x00ff00ff );
}

BOOST_CXX14_CONSTEXPR inline std::uint64_t byteswap_impl( std::uint64_t x ) noexcept
{
// copy-paste the approach used by Core in bit.hpp
std::::uint64_t step32 = x << 32 | x >> 32;
std::::uint64_t step16 = ( step32 & 0x0000ffff0000ffffull ) << 16 | ( step32 & 0xffff0000ffff0000ull ) >> 16;
return ( step16 & 0x00ff00ff00ff00ffull ) << 8 | ( step16 & 0xff00ff00ff00ff00ull ) >> 8;
}

#endif

BOOST_CXX14_CONSTEXPR inline std::uint32_t byteswap( std::uint32_t x ) noexcept
{
return byteswap_impl( x );
}

BOOST_CXX14_CONSTEXPR inline std::uint64_t byteswap( std::uint64_t x ) noexcept
{
return byteswap_impl( x );
}

} // namespace detail
} // namespace hash2
} // namespace boost

#endif // #ifndef BOOST_HASH2_DETAIL_BYTESWAP_HPP_INCLUDED
129 changes: 129 additions & 0 deletions include/boost/hash2/detail/mul128.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#ifndef BOOST_HASH2_DETAIL_MUL128_HPP_INCLUDED
#define BOOST_HASH2_DETAIL_MUL128_HPP_INCLUDED

// Copyright 2025 Christian Mazakas
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

#include <boost/hash2/detail/is_constant_evaluated.hpp>
#include <boost/config.hpp>
#include <cstdint>

#if defined(BOOST_MSVC)
#include <intrin.h>
#endif

namespace boost
{
namespace hash2
{
namespace detail
{

struct uint128_t
{
std::uint64_t low;
std::uint64_t high;
};

#if defined(BOOST_HAS_INT128)

BOOST_CXX14_CONSTEXPR inline uint128_t mul128_impl( std::uint64_t x, std::uint64_t y ) noexcept
{
__uint128_t product = __uint128_t{ x } * __uint128_t{ y };
uint128_t r = { 0, 0 };
r.low = static_cast<std::uint64_t>( product );
r.high = static_cast<std::uint64_t>( product >> 64 );
return r;
}

#elif ( defined(_M_X64) || defined(_M_IA64) ) && !defined(_M_ARM64EC)

BOOST_CXX14_CONSTEXPR inline uint128_t mul128_impl( std::uint64_t x, std::uint64_t y ) noexcept
{
if( !detail::is_constant_evaluated() )
{
uint128_t r = { 0, 0 };
std::uint64_t high_product = 0;
r.low = _umul128( x, y, &high_product );
r.high = high_product;
return r;
}
else
{
std::uint64_t lo_lo = ( x & 0xffffffff ) * ( y & 0xffffffff );
std::uint64_t hi_lo = ( x >> 32 ) * ( y & 0xffffffff );
std::uint64_t lo_hi = ( x & 0xffffffff ) * ( y >> 32 );
std::uint64_t hi_hi = ( x >> 32 ) * ( y >> 32 );

std::uint64_t cross = ( lo_lo >> 32 ) + ( hi_lo & 0xffffffff ) + lo_hi;
std::uint64_t upper = ( hi_lo >> 32 ) + ( cross >> 32 ) + hi_hi;
std::uint64_t lower = ( cross << 32 ) | ( lo_lo & 0xffffffff );

uint128_t r = { 0, 0 };
r.low = lower;
r.high = upper;
return r;
}
}

#elif defined(_M_ARM64) || defined(_M_ARM64EC)

BOOST_CXX14_CONSTEXPR inline uint128_t mul128_impl( std::uint64_t x, std::uint64_t y ) noexcept
{
if( !detail::is_constant_evaluated() )
{
uint128_t r = { 0, 0 };
r.low = x * y;
r.high = __umulh( x, y );
return r;
}
else
{
std::uint64_t lo_lo = ( x & 0xffffffff ) * ( y & 0xffffffff );
std::uint64_t hi_lo = ( x >> 32 ) * ( y & 0xffffffff );
std::uint64_t lo_hi = ( x & 0xffffffff ) * ( y >> 32 );
std::uint64_t hi_hi = ( x >> 32 ) * ( y >> 32 );

std::uint64_t cross = ( lo_lo >> 32 ) + ( hi_lo & 0xffffffff ) + lo_hi;
std::uint64_t upper = ( hi_lo >> 32 ) + ( cross >> 32 ) + hi_hi;
std::uint64_t lower = ( cross << 32 ) | ( lo_lo & 0xffffffff );

uint128_t r = { 0, 0 };
r.low = lower;
r.high = upper;
return r;
}
}

#else

BOOST_CXX14_CONSTEXPR inline uint128_t mul128_impl( std::uint64_t x, std::uint64_t y ) noexcept
{
std::uint64_t lo_lo = ( x & 0xffffffff ) * ( y & 0xffffffff );
std::uint64_t hi_lo = ( x >> 32 ) * ( y & 0xffffffff );
std::uint64_t lo_hi = ( x & 0xffffffff ) * ( y >> 32 );
std::uint64_t hi_hi = ( x >> 32 ) * ( y >> 32 );

std::uint64_t cross = ( lo_lo >> 32 ) + ( hi_lo & 0xffffffff ) + lo_hi;
std::uint64_t upper = ( hi_lo >> 32 ) + ( cross >> 32 ) + hi_hi;
std::uint64_t lower = ( cross << 32 ) | ( lo_lo & 0xffffffff );

uint128_t r = { 0, 0 };
r.low = lower;
r.high = upper;
return r;
}

#endif

BOOST_CXX14_CONSTEXPR inline uint128_t mul128( std::uint64_t x, std::uint64_t y ) noexcept
{
return mul128_impl( x, y );
}

} // namespace detail
} // namespace hash2
} // namespace boost

#endif // #ifndef BOOST_HASH2_DETAIL_MUL128_HPP_INCLUDED
Loading
Loading