Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include <cstdint>
- #include <functional>
- #include <limits>
- #include <memory>
- #include <queue>
- #include <string_view>
- #include <unordered_map>
- #include <utility>
- constexpr auto kInvalidRegistryId = std::numeric_limits<uint32_t>::max();
- template <class T>
- class RonlyRegistry {
- protected:
- std::unordered_map<std::string_view, T*> mLookup;
- std::vector<std::unique_ptr<T>> mContents;
- public:
- T* lookup(std::string_view name) {
- auto iter = this->mLookup.find(name);
- if (iter != this->mLookup.end()) {
- return iter->second;
- } else {
- return nullptr;
- }
- }
- T* lookup(uint32_t id) {
- if (id < this->mContents.size()) {
- return this->mContents[id].get();
- } else {
- return nullptr;
- }
- }
- const std::unordered_map<std::string_view, T*>& getLookupTable() const {
- return this->mLookup;
- }
- };
- template <class T>
- class RwRegistry : public RonlyRegistry<T> {
- protected:
- std::queue<uint32_t> mUnusedIDs;
- public:
- std::pair<uint32_t, T*> registerItem(T value) {
- if (this->mLookup.find(value.Name) != this->mLookup.end()) {
- // Register failed, entry with name already exists
- return { 0, nullptr };
- }
- if (this->mUnusedIDs.empty()) {
- this->mContents.push_back(std::unique_ptr<T>(new T(std::move(value))));
- T* ref = this->mContents.back().get();
- this->mLookup.insert({ ref->Name, ref });
- return { static_cast<uint32_t>(this->mContents.size() - 1), ref };
- } else {
- uint32_t id = this->mUnusedIDs.front();
- this->mUnusedIDs.pop();
- this->mContents[id] = std::unique_ptr<T>(new T(std::move(value)));
- T* ref = this->mContents[id].get();
- this->mLookup.insert({ ref->Name, ref });
- return { id, ref };
- }
- }
- void unregisterItem(uint32_t id) {
- if (id >= this->mContents.size()) return;
- if (auto& content = this->mContents[id]) {
- this->mLookup.erase(content.Name);
- this->mContents.erase(id);
- this->mUnusedIDs.push(id);
- }
- }
- void unregisterItem(std::string_view name) {
- auto iter = this->mLookup.find(name);
- if (iter == this->mLookup.end()) {
- return;
- }
- auto& content = *iter->second;
- // Only erases lookup, `content` is still valid
- this->mLookup.erase(name);
- uint32_t id = content.TypeId;
- this->mContents[id] = nullptr;
- this->mUnusedIDs.push(id);
- }
- };
- #define MAKE_BASIC_REGISTRY_TOOLS(ItemType) \
- static RonlyRegistry<ItemType>& getRegistryView(); \
- static ItemType* registerItem(ItemType item); \
- static void unregisterItem(std::string_view name)
- #define MAKE_BASIC_REGISTRY_TOOLS_IMPL(ItemType) \
- static RwRegistry<ItemType>& get##ItemType##Registry() { \
- static RwRegistry<ItemType> reg; \
- return reg; \
- } \
- RonlyRegistry<ItemType>& ItemType::getRegistryView() { \
- return ::get##ItemType##Registry(); \
- } \
- ItemType* ItemType::registerItem(ItemType item) { \
- auto [id, entry] = ::get##ItemType##Registry().registerItem(std::move(item)); \
- if (entry) { \
- entry->typeId = id; \
- return entry; \
- } else { \
- return nullptr; \
- } \
- } \
- void ItemType::unregisterItem(std::string_view name) { \
- ::get##ItemType##Registry().unregisterItem(name); \
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement