//
// Created by Dan Crosby on 10/13/22.
//

#ifndef EAGLE0_BYTEHASHER_HPP
#define EAGLE0_BYTEHASHER_HPP

#include <cstdint>

// FNV-1a 64-bit constants
constexpr uint64_t FNV_PRIME = 0x00000100000001B3ULL;
constexpr uint64_t FNV_OFFSET_BASIS = 0xcbf29ce484222325ULL;

// FNV-1a algorithm: XOR first, then multiply
static inline auto MixIn(uint64_t& hash, const uint8_t byte) {
    hash ^= byte;
    hash *= FNV_PRIME;
}

// Hash an entire buffer using FNV-1a
// Fast word-at-a-time implementation - processes 8 bytes at once for better performance
// while maintaining good distribution properties for hash table use
static inline auto HashBuffer(const uint8_t* data, size_t size) -> uint64_t {
    if (data == nullptr) { return FNV_OFFSET_BASIS; }

    uint64_t hash = FNV_OFFSET_BASIS;
    const uint8_t* end = data + size;

    // Process 8 bytes at a time
    while (data + 8 <= end) {
        uint64_t word = 0;
        // Use memcpy to avoid alignment issues and let compiler optimize
        __builtin_memcpy(&word, data, sizeof(word));
        hash ^= word;
        hash *= FNV_PRIME;
        data += 8;
    }

    // Process remaining bytes
    while (data < end) {
        hash ^= static_cast<uint64_t>(*data);
        hash *= FNV_PRIME;
        data++;
    }

    return hash;
}

#endif  // EAGLE0_BYTEHASHER_HPP
