Skip to content

Commit

Permalink
Add test/append_byte_sized_cx.cpp
Browse files Browse the repository at this point in the history
  • Loading branch information
pdimov committed Nov 3, 2024
1 parent 414ec5b commit 8669a78
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 33 deletions.
113 changes: 91 additions & 22 deletions include/boost/hash2/hash_append.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <boost/hash2/is_contiguously_hashable.hpp>
#include <boost/hash2/get_integral_result.hpp>
#include <boost/hash2/flavor.hpp>
#include <boost/hash2/detail/is_constant_evaluated.hpp>
#include <boost/hash2/detail/reverse.hpp>
#include <boost/hash2/detail/has_tag_invoke.hpp>
#include <boost/container_hash/is_range.hpp>
Expand Down Expand Up @@ -43,7 +44,7 @@ namespace hash2
namespace detail
{

template<class Hash, class Flavor, class It> void hash_append_range_( Hash& h, Flavor const& f, It first, It last )
template<class Hash, class Flavor, class It> BOOST_CXX14_CONSTEXPR void hash_append_range_( Hash& h, Flavor const& f, It first, It last )
{
for( ; first != last; ++first )
{
Expand All @@ -52,34 +53,45 @@ template<class Hash, class Flavor, class It> void hash_append_range_( Hash& h, F
}
}

template<class Hash, class Flavor> void hash_append_range_( Hash& h, Flavor const& /*f*/, unsigned char* first, unsigned char* last )
template<class Hash, class Flavor> BOOST_CXX14_CONSTEXPR void hash_append_range_( Hash& h, Flavor const& /*f*/, unsigned char* first, unsigned char* last )
{
h.update( first, last - first );
}

template<class Hash, class Flavor> void hash_append_range_( Hash& h, Flavor const& /*f*/, unsigned char const* first, unsigned char const* last )
template<class Hash, class Flavor> BOOST_CXX14_CONSTEXPR void hash_append_range_( Hash& h, Flavor const& /*f*/, unsigned char const* first, unsigned char const* last )
{
h.update( first, last - first );
}

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if<
is_contiguously_hashable<T, Flavor::byte_order>::value, void >::type
hash_append_range_( Hash& h, Flavor const& /*f*/, T* first, T* last )
hash_append_range_( Hash& h, Flavor const& f, T* first, T* last )
{
h.update( first, (last - first) * sizeof(T) );
if( !detail::is_constant_evaluated() )
{
h.update( first, (last - first) * sizeof(T) );
}
else
{
for( ; first != last; ++first )
{
hash2::hash_append( h, f, *first );
}
}
}

} // namespace detail

template<class Hash, class Flavor = default_flavor, class It> void hash_append_range( Hash& h, Flavor const& f, It first, It last )
template<class Hash, class Flavor = default_flavor, class It> BOOST_CXX14_CONSTEXPR void hash_append_range( Hash& h, Flavor const& f, It first, It last )
{
detail::hash_append_range_( h, f, first, last );
}

// hash_append_size

template<class Hash, class Flavor = default_flavor, class T> void hash_append_size( Hash& h, Flavor const& f, T const& v )
template<class Hash, class Flavor = default_flavor, class T> BOOST_CXX14_CONSTEXPR void hash_append_size( Hash& h, Flavor const& f, T const& v )
{
hash2::hash_append( h, f, static_cast<typename Flavor::size_type>( v ) );
}
Expand All @@ -89,7 +101,7 @@ template<class Hash, class Flavor = default_flavor, class T> void hash_append_si
namespace detail
{

template<class Hash, class Flavor, class It> void hash_append_sized_range_( Hash& h, Flavor const& f, It first, It last, std::input_iterator_tag )
template<class Hash, class Flavor, class It> void BOOST_CXX14_CONSTEXPR hash_append_sized_range_( Hash& h, Flavor const& f, It first, It last, std::input_iterator_tag )
{
typename std::iterator_traits<It>::difference_type m = 0;

Expand All @@ -101,22 +113,22 @@ template<class Hash, class Flavor, class It> void hash_append_sized_range_( Hash
hash2::hash_append_size( h, f, m );
}

template<class Hash, class Flavor, class It> void hash_append_sized_range_( Hash& h, Flavor const& f, It first, It last, std::random_access_iterator_tag )
template<class Hash, class Flavor, class It> BOOST_CXX14_CONSTEXPR void hash_append_sized_range_( Hash& h, Flavor const& f, It first, It last, std::random_access_iterator_tag )
{
hash2::hash_append_range( h, f, first, last );
hash2::hash_append_size( h, f, last - first );
}

} // namespace detail

template<class Hash, class Flavor = default_flavor, class It> void hash_append_sized_range( Hash& h, Flavor const& f, It first, It last )
template<class Hash, class Flavor = default_flavor, class It> BOOST_CXX14_CONSTEXPR void hash_append_sized_range( Hash& h, Flavor const& f, It first, It last )
{
detail::hash_append_sized_range_( h, f, first, last, typename std::iterator_traits<It>::iterator_category() );
}

// hash_append_unordered_range

template<class Hash, class Flavor = default_flavor, class It> void hash_append_unordered_range( Hash& h, Flavor const& f, It first, It last )
template<class Hash, class Flavor = default_flavor, class It> BOOST_CXX14_CONSTEXPR void hash_append_unordered_range( Hash& h, Flavor const& f, It first, It last )
{
typename std::iterator_traits<It>::difference_type m = 0;

Expand All @@ -136,24 +148,38 @@ template<class Hash, class Flavor = default_flavor, class It> void hash_append_u

// do_hash_append

// contiguously hashable (this includes unsigned char const&)
// integral types, sizeof(T) == 1

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if< std::is_integral<T>::value && sizeof(T) == 1, void >::type
do_hash_append( Hash& h, Flavor const& /*f*/, T const& v )
{
unsigned char w = static_cast<unsigned char>( v );
h.update( &w, 1 );
}

// integral types, sizeof(T) != 1, matching endianness
// not yet constexpr

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if<
is_contiguously_hashable<T, Flavor::byte_order>::value, void >::type
std::is_integral<T>::value && sizeof(T) != 1 && Flavor::byte_order == endian::native,
void>::type
do_hash_append( Hash& h, Flavor const& /*f*/, T const& v )
{
h.update( &v, sizeof(T) );
}

// trivially equality comparable, scalar, but not contiguously hashable (because of endianness)
// integral types, sizeof(T) != 1, non-matching endianness
// not yet constexpr

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if<
is_trivially_equality_comparable<T>::value &&
std::is_scalar<T>::value &&
Flavor::byte_order != endian::native && !is_endian_independent<T>::value
, void >::type
std::is_integral<T>::value && sizeof(T) != 1 && Flavor::byte_order != endian::native,
void >::type
do_hash_append( Hash& h, Flavor const& /*f*/, T const& v )
{
constexpr auto N = sizeof(T);
Expand All @@ -164,9 +190,43 @@ template<class Hash, class Flavor, class T>
h.update( tmp, N );
}

// enum types

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if< std::is_enum<T>::value, void >::type
do_hash_append( Hash& h, Flavor const& f, T const& v )
{
hash2::hash_append( h, f, static_cast<typename std::underlying_type<T>::type>( v ) );
}

// pointer types
// not constexpr

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if< std::is_pointer<T>::value, void >::type
do_hash_append( Hash& h, Flavor const& f, T const& v )
{
hash2::hash_append( h, f, reinterpret_cast<std::uintptr_t>( v ) );
}

// contiguously hashable, non-scalar

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if<
is_contiguously_hashable<T, Flavor::byte_order>::value && !std::is_scalar<T>::value,
void>::type
do_hash_append( Hash& h, Flavor const& /*f*/, T const& v )
{
h.update( &v, sizeof(T) );
}

// floating point

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if< std::is_floating_point<T>::value && Flavor::byte_order == endian::native, void >::type
do_hash_append( Hash& h, Flavor const& /*f*/, T const& v )
{
Expand All @@ -175,6 +235,7 @@ template<class Hash, class Flavor, class T>
}

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if< std::is_floating_point<T>::value && Flavor::byte_order != endian::native, void >::type
do_hash_append( Hash& h, Flavor const& /*f*/, T const& v )
{
Expand All @@ -190,6 +251,7 @@ template<class Hash, class Flavor, class T>
// std::nullptr_t

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if< std::is_same<T, std::nullptr_t>::value, void >::type
do_hash_append( Hash& h, Flavor const& f, T const& v )
{
Expand All @@ -198,14 +260,15 @@ template<class Hash, class Flavor, class T>

// C arrays

template<class Hash, class Flavor, class T, std::size_t N> void do_hash_append( Hash& h, Flavor const& f, T const (&v)[ N ] )
template<class Hash, class Flavor, class T, std::size_t N> BOOST_CXX14_CONSTEXPR void do_hash_append( Hash& h, Flavor const& f, T const (&v)[ N ] )
{
hash2::hash_append_range( h, f, v + 0, v + N );
}

// contiguous containers and ranges, w/ size

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if< container_hash::is_contiguous_range<T>::value && !container_hash::is_tuple_like<T>::value, void >::type
do_hash_append( Hash& h, Flavor const& f, T const& v )
{
Expand All @@ -216,6 +279,7 @@ template<class Hash, class Flavor, class T>
// containers and ranges, w/ size

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if< container_hash::is_range<T>::value && !container_hash::is_tuple_like<T>::value && !container_hash::is_contiguous_range<T>::value && !container_hash::is_unordered_range<T>::value, void >::type
do_hash_append( Hash& h, Flavor const& f, T const& v )
{
Expand All @@ -225,6 +289,7 @@ template<class Hash, class Flavor, class T>
// std::array (both range and tuple-like)

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if< container_hash::is_range<T>::value && container_hash::is_tuple_like<T>::value, void >::type
do_hash_append( Hash& h, Flavor const& f, T const& v )
{
Expand All @@ -233,14 +298,15 @@ template<class Hash, class Flavor, class T>

// boost::array (constant size, but not tuple-like)

template<class Hash, class Flavor, class T, std::size_t N> void do_hash_append( Hash& h, Flavor const& f, boost::array<T, N> const& v )
template<class Hash, class Flavor, class T, std::size_t N> BOOST_CXX14_CONSTEXPR void do_hash_append( Hash& h, Flavor const& f, boost::array<T, N> const& v )
{
hash2::hash_append_range( h, f, v.begin(), v.end() );
}

// unordered containers (is_unordered_range implies is_range)

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if< container_hash::is_unordered_range<T>::value, void >::type
do_hash_append( Hash& h, Flavor const& f, T const& v )
{
Expand All @@ -252,7 +318,7 @@ template<class Hash, class Flavor, class T>
namespace detail
{

template<class Hash, class Flavor, class T, std::size_t... J> void hash_append_tuple( Hash& h, Flavor const& f, T const& v, boost::mp11::integer_sequence<std::size_t, J...> )
template<class Hash, class Flavor, class T, std::size_t... J> BOOST_CXX14_CONSTEXPR void hash_append_tuple( Hash& h, Flavor const& f, T const& v, boost::mp11::integer_sequence<std::size_t, J...> )
{
using std::get;
int a[] = { 0, ((void)hash2::hash_append( h, f, get<J>(v) ), 0)... };
Expand All @@ -262,6 +328,7 @@ template<class Hash, class Flavor, class T, std::size_t... J> void hash_append_t
} // namespace detail

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if< !container_hash::is_range<T>::value && container_hash::is_tuple_like<T>::value, void >::type
do_hash_append( Hash& h, Flavor const& f, T const& v )
{
Expand All @@ -279,6 +346,7 @@ template<class Hash, class Flavor, class T>
#endif

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if< container_hash::is_described_class<T>::value, void >::type
do_hash_append( Hash& h, Flavor const& f, T const& v )
{
Expand Down Expand Up @@ -326,6 +394,7 @@ struct hash_append_tag
};

template<class Hash, class Flavor, class T>
BOOST_CXX14_CONSTEXPR
typename std::enable_if< detail::has_tag_invoke<T>::value, void >::type
do_hash_append( Hash& h, Flavor const& f, T const& v )
{
Expand All @@ -334,7 +403,7 @@ template<class Hash, class Flavor, class T>

// hash_append

template<class Hash, class Flavor = default_flavor, class T> void hash_append( Hash& h, Flavor const& f, T const& v )
template<class Hash, class Flavor = default_flavor, class T> BOOST_CXX14_CONSTEXPR void hash_append( Hash& h, Flavor const& f, T const& v )
{
do_hash_append( h, f, v );
}
Expand Down
20 changes: 10 additions & 10 deletions include/boost/hash2/hash_append_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ namespace hash2

struct default_flavor;

template<class Hash, class Flavor = default_flavor, class T> void hash_append( Hash& h, Flavor const& f, T const& v );
template<class Hash, class Flavor = default_flavor, class It> void hash_append_range( Hash& h, Flavor const& f, It first, It last );
template<class Hash, class Flavor = default_flavor, class T> void hash_append_size( Hash& h, Flavor const& f, T const& v );
template<class Hash, class Flavor = default_flavor, class It> void hash_append_sized_range( Hash& h, Flavor const& f, It first, It last );
template<class Hash, class Flavor = default_flavor, class It> void hash_append_unordered_range( Hash& h, Flavor const& f, It first, It last );
template<class Hash, class Flavor = default_flavor, class T> BOOST_CXX14_CONSTEXPR void hash_append( Hash& h, Flavor const& f, T const& v );
template<class Hash, class Flavor = default_flavor, class It> BOOST_CXX14_CONSTEXPR void hash_append_range( Hash& h, Flavor const& f, It first, It last );
template<class Hash, class Flavor = default_flavor, class T> BOOST_CXX14_CONSTEXPR void hash_append_size( Hash& h, Flavor const& f, T const& v );
template<class Hash, class Flavor = default_flavor, class It> BOOST_CXX14_CONSTEXPR void hash_append_sized_range( Hash& h, Flavor const& f, It first, It last );
template<class Hash, class Flavor = default_flavor, class It> BOOST_CXX14_CONSTEXPR void hash_append_unordered_range( Hash& h, Flavor const& f, It first, It last );

#else

template<class Hash, class Flavor, class T> void hash_append( Hash& h, Flavor const& f, T const& v );
template<class Hash, class Flavor, class It> void hash_append_range( Hash& h, Flavor const& f, It first, It last );
template<class Hash, class Flavor, class T> void hash_append_size( Hash& h, Flavor const& f, T const& v );
template<class Hash, class Flavor, class It> void hash_append_sized_range( Hash& h, Flavor const& f, It first, It last );
template<class Hash, class Flavor, class It> void hash_append_unordered_range( Hash& h, Flavor const& f, It first, It last );
template<class Hash, class Flavor, class T> BOOST_CXX14_CONSTEXPR void hash_append( Hash& h, Flavor const& f, T const& v );
template<class Hash, class Flavor, class It> BOOST_CXX14_CONSTEXPR void hash_append_range( Hash& h, Flavor const& f, It first, It last );
template<class Hash, class Flavor, class T> BOOST_CXX14_CONSTEXPR void hash_append_size( Hash& h, Flavor const& f, T const& v );
template<class Hash, class Flavor, class It> BOOST_CXX14_CONSTEXPR void hash_append_sized_range( Hash& h, Flavor const& f, It first, It last );
template<class Hash, class Flavor, class It> BOOST_CXX14_CONSTEXPR void hash_append_unordered_range( Hash& h, Flavor const& f, It first, It last );

#endif

Expand Down
4 changes: 4 additions & 0 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ run hash_append_5.cpp ;
run hash_append_range.cpp ;
run hash_append_range_2.cpp ;

# hash_append, constexpr

compile append_byte_sized_cx.cpp ;

# non-cryptographic

run fnv1a.cpp ;
Expand Down
56 changes: 56 additions & 0 deletions test/append_byte_sized_cx.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2024 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

#include <boost/hash2/hash_append.hpp>
#include <boost/hash2/fnv1a.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>

#if defined(BOOST_NO_CXX14_CONSTEXPR)

BOOST_PRAGMA_MESSAGE( "Test skipped, because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}

#else

#if defined(BOOST_MSVC) && BOOST_MSVC < 1920
# pragma warning(disable: 4307) // integral constant overflow
#endif

#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)

using namespace boost::hash2;

template<class T> BOOST_CXX14_CONSTEXPR std::uint32_t test()
{
T v[ 95 ] = {};

fnv1a_32 h;
hash_append( h, {}, v );

return h.result();
}

enum E: unsigned char {};

int main()
{
constexpr std::uint32_t r = 409807047;

STATIC_ASSERT( test<bool>() == r );
STATIC_ASSERT( test<char>() == r );
STATIC_ASSERT( test<signed char>() == r );
STATIC_ASSERT( test<unsigned char>() == r );
STATIC_ASSERT( test<E>() == r );

#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
STATIC_ASSERT( test<std::byte>() == r );
#endif

#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
STATIC_ASSERT( test<char8_t>() == r );
#endif
}

#endif
Loading

0 comments on commit 8669a78

Please sign in to comment.