/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright 2015 Danny Robson <danny@nerdcruft.net>
 */

#pragma once

#include "../../view.hpp"

#include <array>
#include <cstddef>
#include <cstdint>

// Austin Appleby's MurmurHash3
namespace cruft::hash {
    namespace detail::murmur3 {
        template <size_t DigestBits, size_t ArchBits>
        struct digest_type { };

        template <> struct digest_type< 32,32> { using type = uint32_t; };
        template <> struct digest_type<128,32> { using type = std::array<uint32_t,4>; };
        template <> struct digest_type<128,64> { using type = std::array<uint64_t,2>; };
    };

    template <size_t DigestBits, size_t ArchBits>
    class murmur3 {
    public:
        murmur3 (uint32_t _seed):
            m_seed (_seed)
        { ; }

        static_assert (DigestBits % 8 == 0);

        using digest_t = typename detail::murmur3::digest_type<DigestBits,ArchBits>::type;

        static uint32_t mix (uint32_t);
        static uint64_t mix (uint64_t);

        digest_t
        operator() (cruft::view<const uint8_t*> data) const noexcept;

    private:
        uint32_t m_seed;
    };

    using murmur3_32      = murmur3< 32,32>;
    using murmur3_128_x86 = murmur3<128,32>;
    using murmur3_128_x64 = murmur3<128,64>;
}