Skip to content

<xstd/misc/concepts/hash_algorithm.hpp>

xstd::hash_algorithm

template<class H>
concept hash_algorithm =
  semiregular<H> and
  constructible_from<H, uint64_t> and
  constructible_from<H, const unsigned char*, size_t> and
  requires(H& h, const void* p, size_t n) {
    typename H::result_type;
    h.update(p, n);
    { h.result() } -> same_as<typename H::result_type>;
  } and
  ((unsigned_integral<typename H::result_type> and not same_as<typename H::result_type, bool>) or
   (boost::hash2::has_constant_size<typename H::result_type>::value and
    ranges::contiguous_range<typename H::result_type> and
    same_as<ranges::range_value_t<typename H::result_type>, unsigned char>)) and
  (not requires { H::block_size; } or same_as<remove_cv_t<decltype(H::block_size)>, size_t>);

A Boost.Hash2 hash algorithm: seeded by an integer or by bytes, updated with bytes, and finished with a result that is an unsigned integer or a fixed-size byte array.

Semantic requirements

A type models it if it meets Boost.Hash2's documented requirements on an algorithm:

  • the split of a message into calls to update does not affect the result;
  • a copy is equivalent to the original;
  • seed 0, and an empty byte seed, are default construction, and distinct seeds give distinct states;
  • each further call to result continues a sequence that an equal state repeats.

Models

  • Every Boost.Hash2 algorithm models it.
  • Each form a result and a block size take in Hash2 satisfies it: an unsigned integer or a fixed-size byte array, with a block size or none.
  • A hasher, which hashes a key rather than updating with bytes, does not satisfy it.
  • A bool result is turned away.
  • A block_size of a type other than size_t is turned away.

Example

#include <xstd/misc/concepts/hash_algorithm.hpp> // hash_algorithm
#include <xstd/misc/functional/hash.hpp>         // hash
#include <boost/hash2/fnv1a.hpp>                 // fnv1a_32
#include <boost/hash2/xxhash.hpp>                // xxhash_32
#include <functional>                            // hash
#include <iomanip>                               // setfill, setw
#include <iostream>                              // boolalpha, cout, hex
#include <string_view>                           // string_view

// Hashes the bytes of a message under any Boost.Hash2 algorithm, unseeded.
template<xstd::hash_algorithm H>
[[nodiscard]] auto hash_bytes(std::string_view message)
        -> typename H::result_type
{
        auto h = H();
        h.update(message.data(), message.size());
        return h.result();
}

auto main() -> int
{
        std::cout << std::hex << std::setfill('0');
        std::cout << "fnv1a_32(\"xstd\")  = " << std::setw(8) << hash_bytes<boost::hash2::fnv1a_32>("xstd") << '\n';
        std::cout << "xxhash_32(\"xstd\") = " << std::setw(8) << hash_bytes<boost::hash2::xxhash_32>("xstd") << '\n';

        // A hasher takes a key where an algorithm takes bytes, so neither the standard's nor this library's is one.
        std::cout << std::boolalpha;
        std::cout << "hash_algorithm<boost::hash2::xxhash_32> is " << xstd::hash_algorithm<boost::hash2::xxhash_32> << '\n';
        std::cout << "hash_algorithm<std::hash<int>> is " << xstd::hash_algorithm<std::hash<int>> << '\n';
        std::cout << "hash_algorithm<xstd::hash<int>> is " << xstd::hash_algorithm<xstd::hash<int>> << '\n';
}

Output:

fnv1a_32("xstd")  = ff2ae354
xxhash_32("xstd") = d49153c1
hash_algorithm<boost::hash2::xxhash_32> is true
hash_algorithm<std::hash<int>> is false
hash_algorithm<xstd::hash<int>> is false

See also

Entity Relation
hash constrains H64 and H32 on it
digest constrains H on it
hash_algorithm_is_avalanching whether a model avalanches