#pragma once

#include <cstddef>
#include <cstdint>
#include <span>
#include <string_view>

namespace ta::foundation::hash
{
    inline constexpr std::uint64_t fnv1a_offset = 14695981039346656037ull;
    inline constexpr std::uint64_t fnv1a_prime = 1099511628211ull;

    inline void fnv1a_append(std::uint64_t& hash, const std::span<const std::byte> bytes) noexcept
    {
        for (const std::byte byte : bytes)
        {
            hash ^= static_cast<std::uint8_t>(byte);
            hash *= fnv1a_prime;
        }
    }

    inline void fnv1a_append(std::uint64_t& hash, const std::string_view value) noexcept
    {
        for (const unsigned char character : value)
        {
            hash ^= character;
            hash *= fnv1a_prime;
        }
    }

    inline void fnv1a_append_field(std::uint64_t& hash, const std::string_view value) noexcept
    {
        fnv1a_append(hash, value);
        hash ^= 0xffu;
        hash *= fnv1a_prime;
    }

    [[nodiscard]] inline std::uint64_t fnv1a(const std::string_view value) noexcept
    {
        std::uint64_t hash = fnv1a_offset;
        fnv1a_append(hash, value);
        return hash;
    }
}
