// Copyright Epic Games, Inc. All Rights Reserved. #include #include #include #include #include #include #include #include #include #include namespace zen { ////////////////////////////////////////////////////////////////////////// namespace detail { static bool OidInitialised; static uint32_t RunId; static std::atomic_uint32_t Serial; } // namespace detail ////////////////////////////////////////////////////////////////////////// const Oid Oid::Zero = {{0u, 0u, 0u}}; const Oid Oid::Max = {{~0u, ~0u, ~0u}}; void Oid::Initialize() { if (!detail::OidInitialised) { std::random_device Rng; detail::RunId = Rng(); detail::Serial = Rng(); detail::OidInitialised = true; } } const Oid& Oid::Generate() { if (!detail::OidInitialised) { Oid::Initialize(); } const uint64_t kOffset = 1'609'459'200; // Seconds from 1970 -> 2021 const uint64_t Time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) - kOffset; OidBits[0] = ToNetworkOrder(uint32_t(Time)); OidBits[1] = ToNetworkOrder(uint32_t(++detail::Serial)); OidBits[2] = detail::RunId; return *this; } Oid Oid::NewOid() { return Oid().Generate(); } Oid Oid::FromHexString(const std::string_view String) { ZEN_ASSERT(String.size() == 2 * sizeof(Oid::OidBits)); Oid Id; if (ParseHexBytes(String.data(), String.size(), reinterpret_cast(Id.OidBits))) { return Id; } else { return Oid::Zero; } } Oid Oid::TryFromHexString(const std::string_view String, const Oid& Default) { if (String.length() != StringLength) { return Default; } Oid Id; if (ParseHexBytes(String.data(), String.size(), reinterpret_cast(Id.OidBits))) { return Id; } else { return Default; } } bool Oid::TryParse(std::string_view Str, Oid& Id) { using namespace std::literals; if (Str.size() == Oid::StringLength) { return ParseHexBytes(Str.data(), Str.size(), reinterpret_cast(Id.OidBits)); } if (Str.starts_with("0x"sv)) { return TryParse(Str.substr(2), Id); } return false; } void Oid::ToString(char OutString[StringLength]) const { ToHexBytes(reinterpret_cast(OidBits), sizeof(Oid::OidBits), OutString); OutString[StringLength] = '\0'; } std::string Oid::ToString() const { char OutString[StringLength + 1]; ToString(OutString); return std::string(OutString, StringLength); } StringBuilderBase& Oid::ToString(StringBuilderBase& OutString) const { String_t Str; ToHexBytes(reinterpret_cast(OidBits), sizeof(Oid::OidBits), Str); OutString.AppendRange(Str, &Str[StringLength]); return OutString; } Oid Oid::FromMemory(const void* Ptr) { Oid Id; memcpy(Id.OidBits, Ptr, sizeof Id); return Id; } #if ZEN_WITH_TESTS TEST_CASE("Oid") { SUBCASE("Basic") { Oid id1 = Oid::NewOid(); ZEN_UNUSED(id1); std::vector ids; std::set idset; std::unordered_map idmap; const int Count = 1000; for (int i = 0; i < Count; ++i) { Oid id; id.Generate(); ids.emplace_back(id); idset.insert(id); idmap.insert({id, i}); } CHECK(ids.size() == Count); CHECK(idset.size() == Count); // All ids should be unique CHECK(idmap.size() == Count); // Ditto } } void uid_forcelink() { } #endif } // namespace zen