/*
 * Copyright 2015 - 2025 gary@drinkingtea.net
 *
 * 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 https://mozilla.org/MPL/2.0/.
 */

#pragma once

#if __has_include(<functional>)
#include <functional>
#else
namespace std {
template<typename T>
struct hash;
}
#endif

#include <cityhash/city.h>

#include "istring.hpp"
#include "string.hpp"
#include "stringview.hpp"
#include "types.hpp"

namespace ox {

template<typename T>
struct hash {
	[[nodiscard]]
	constexpr size_t operator()(T const&v) const noexcept {
		return std::hash<T>{}(v);
	}
};

template<>
struct hash<bool> {
	[[nodiscard]]
	constexpr size_t operator()(bool v) const noexcept {
		return static_cast<size_t>(v);
	}
};

template<>
struct hash<char> {
	[[nodiscard]]
	constexpr size_t operator()(char v) const noexcept {
		return static_cast<size_t>(v);
	}
};

template<>
struct hash<short> {
	[[nodiscard]]
	constexpr size_t operator()(short v) const noexcept {
		return static_cast<size_t>(v);
	}
};

template<>
struct hash<int> {
	[[nodiscard]]
	constexpr size_t operator()(int v) const noexcept {
		return static_cast<size_t>(v);
	}
};

template<>
struct hash<long> {
	[[nodiscard]]
	constexpr size_t operator()(long v) const noexcept {
		return static_cast<size_t>(v);
	}
};

template<>
struct hash<long long> {
	[[nodiscard]]
	constexpr size_t operator()(long long v) const noexcept {
		return static_cast<size_t>(v);
	}
};



template<>
struct hash<unsigned char> {
	[[nodiscard]]
	constexpr size_t operator()(unsigned char v) const noexcept {
		return static_cast<size_t>(v);
	}
};

template<>
struct hash<unsigned short> {
	[[nodiscard]]
	constexpr size_t operator()(unsigned short v) const noexcept {
		return static_cast<size_t>(v);
	}
};

template<>
struct hash<unsigned int> {
	[[nodiscard]]
	constexpr size_t operator()(unsigned int v) const noexcept {
		return static_cast<size_t>(v);
	}
};

template<>
struct hash<unsigned long> {
	[[nodiscard]]
	constexpr size_t operator()(unsigned long v) const noexcept {
		return static_cast<size_t>(v);
	}
};

template<>
struct hash<unsigned long long> {
	[[nodiscard]]
	constexpr size_t operator()(unsigned long long v) const noexcept {
		return static_cast<size_t>(v);
	}
};


[[nodiscard]]
constexpr auto hashString(ox::StringView const&v) noexcept {
	if constexpr(sizeof(void*) == 8) {
		return cityhash::CityHash64(v.data(), v.bytes());
	} else {
		return cityhash::CityHash32(v.data(), v.bytes());
	}
}


template<>
struct hash<ox::StringView> {
	[[nodiscard]]
	constexpr size_t operator()(ox::StringView v) const noexcept {
		return hashString(v);
	}
};

template<>
struct hash<ox::String> {
	[[nodiscard]]
	constexpr size_t operator()(ox::StringView v) const noexcept {
		return hashString(v);
	}
};

template<size_t sz>
struct hash<ox::IString<sz>> {
	[[nodiscard]]
	constexpr size_t operator()(ox::StringView v) const noexcept {
		return hashString(v);
	}
};

template<>
struct hash<const char*> {
	[[nodiscard]]
	constexpr size_t operator()(ox::StringView v) const noexcept {
		return hashString(v);
	}
};

}
