#pragma once
#include <whiteout/common_types.h>
#include <optional>
#include <span>
#include <string>
#include <vector>
namespace whiteout::storages::mpq {
static constexpr u32 kHashEntryEmpty = 0xFFFFFFFF;
static constexpr u32 kHashEntryDeleted = 0xFFFFFFFE;
struct HashEntry {
u32 hashA = kHashEntryEmpty; u32 hashB = kHashEntryEmpty; u16 locale = 0xFFFF; u16 platform = 0xFFFF; u32 blockIndex = kHashEntryEmpty;
[[nodiscard]] bool isEmpty() const {
return blockIndex == kHashEntryEmpty;
}
[[nodiscard]] bool isDeleted() const {
return blockIndex == kHashEntryDeleted;
}
[[nodiscard]] bool isOccupied() const {
return !isEmpty() && !isDeleted();
}
};
static_assert(sizeof(HashEntry) == 16, "HashEntry must be exactly 16 bytes");
class HashTable {
public:
HashTable() = default;
bool parse(std::span<const u8> data, u32 capacity);
void createEmpty(u32 capacity);
[[nodiscard]] std::optional<u32> lookup(const std::string& filename) const;
[[nodiscard]] std::optional<u32> lookup(const std::string& filename, u16 locale) const;
[[nodiscard]] std::optional<u32> insert(const std::string& filename, u16 locale,
u32 blockIndex);
bool remove(const std::string& filename);
bool remove(const std::string& filename, u16 locale);
[[nodiscard]] std::vector<u8> serialize() const;
[[nodiscard]] const HashEntry& entry(u32 index) const {
return m_entries[index];
}
[[nodiscard]] HashEntry& entry(u32 index) {
return m_entries[index];
}
[[nodiscard]] u32 capacity() const {
return static_cast<u32>(m_entries.size());
}
[[nodiscard]] u32 occupiedCount() const;
private:
std::vector<HashEntry> m_entries;
};
}