#pragma once namespace id { struct uuid { //TODO: constexpr uuid_v4 impl constexpr uuid v4() noexcept { //TODO: Generate new UUID at compile time? } }; struct unique_ref { uuid id; constexpr friend auto operator<=>(unique_ref const& a, unique_ref const& b) noexcept = default; }; struct unique { constexpr unique() noexcept : m_id(uuid::v4()) {} constexpr unique(const unique&) noexcept : unique() {} constexpr unique(unique&&) noexcept = default; constexpr unique& operator=(unique&&) noexcept = default; constexpr unique& operator=(unique const& b) noexcept { if(this != std::addressof(b)) m_id = uuid::v4(); return *this; } constexpr virtual ~unique() = default; template T, std::derived_from U> constexpr friend bool operator==(T const& a, U const& b) noexcept { return static_cast(a) == static_cast(b); } template T, std::derived_from U> constexpr friend bool operator!=(T const& a, U const& b) noexcept { return !(a == b); } constexpr friend bool operator==(unique const& a, unique const& b) noexcept { return a.unique_id() == b.unique_id(); } constexpr friend bool operator!=(unique const& a, unique const& b) noexcept { return a.unique_id() != b.unique_id(); } constexpr unique_ref unique_id() const noexcept { return { m_id }; } protected: constexpr uuid& raw_id() noexcept { return m_id; } constexpr uuid const& raw_id() const noexcept { return m_id; } constexpr explicit unique(std::convertible_to auto&& id) : m_id(std::move(id)) {} private: uuid m_id; }; }