#ifndef _C4_HASH_HPP_ #define _C4_HASH_HPP_ #include "c4/config.hpp" #include /** @file hash.hpp */ /** @defgroup hash Hash utils * @see http://aras-p.info/blog/2016/08/02/Hash-Functions-all-the-way-down/ */ C4_BEGIN_NAMESPACE(c4) C4_BEGIN_NAMESPACE(detail) /** @internal * @ingroup hash * @see this was taken a great answer in stackoverflow: * https://stackoverflow.com/a/34597785/5875572 * @see http://aras-p.info/blog/2016/08/02/Hash-Functions-all-the-way-down/ */ template class basic_fnv1a final { static_assert(std::is_unsigned::value, "need unsigned integer"); public: using result_type = ResultT; private: result_type state_ {}; public: C4_CONSTEXPR14 basic_fnv1a() noexcept : state_ {OffsetBasis} {} C4_CONSTEXPR14 void update(const void *const data, const size_t size) noexcept { auto cdata = static_cast(data); auto acc = this->state_; for(size_t i = 0; i < size; ++i) { const auto next = size_t(cdata[i]); acc = (acc ^ next) * Prime; } this->state_ = acc; } C4_CONSTEXPR14 result_type digest() const noexcept { return this->state_; } }; using fnv1a_32 = basic_fnv1a; using fnv1a_64 = basic_fnv1a; template struct fnv1a; template<> struct fnv1a<32> { using type = fnv1a_32; }; template<> struct fnv1a<64> { using type = fnv1a_64; }; C4_END_NAMESPACE(detail) /** @ingroup hash */ template using fnv1a_t = typename detail::fnv1a::type; /** @ingroup hash */ C4_CONSTEXPR14 inline size_t hash_bytes(const void *const data, const size_t size) noexcept { fnv1a_t fn{}; fn.update(data, size); return fn.digest(); } /** * @overload hash_bytes * @ingroup hash */ template C4_CONSTEXPR14 inline size_t hash_bytes(const char (&str)[N]) noexcept { fnv1a_t fn{}; fn.update(str, N); return fn.digest(); } C4_END_NAMESPACE(c4) #endif // _C4_HASH_HPP_