#pragma once #include "tl/detail/prologue.h" #include "tl/hash_map.h" #include namespace tl { template struct identifier { using underlying_type = T; constexpr identifier() noexcept = default; explicit constexpr identifier(T value) noexcept : m_value(std::move(value)) {} constexpr T value() const noexcept { return m_value; } constexpr bool is_valid() const noexcept { return m_value != invalid_value; } //inline static identifier invalid() noexcept { return identifier(); } auto operator<=>(const identifier& other) const noexcept { return m_value <=> other.value(); } auto operator<=>(const T& other) const noexcept { return m_value <=> other; } bool operator==(const identifier& other) const noexcept { return m_value == other.value(); } bool operator==(const T& other) const noexcept { return m_value == other; } private: T m_value = invalid_value; }; } #define TL_DECLARE_INTEGRAL_ID(NAME, TYPE, INVALID_VALUE) \ struct NAME##_tag {};\ using NAME = tl::identifier; template struct std::formatter> { constexpr auto parse(format_parse_context& ctx) noexcept { return ctx.begin(); } auto format(const tl::identifier& id, std::format_context& ctx) const { return format_to(ctx.out(), "{}", id.value()); } }; template struct eastl::hash> { size_t operator()(tl::identifier const& id) const { return hash()(id.value()); } };