#pragma once #include "cplt_fwd.hpp" #include #include #include #include #include #include #include #include #include #include #include template class ItemList { private: std::vector mStorage; tsl::array_map mNameLookup; public: template T& Insert(std::string name, Args... args) { auto iter = mNameLookup.find(name); if (iter != mNameLookup.end()) { throw std::runtime_error("Duplicate key."); } for (size_t i = 0; i < mStorage.size(); ++i) { if (mStorage[i].IsInvalid()) { mStorage[i] = T(*this, i, std::move(name), std::forward(args)...); mNameLookup.insert(name, i); return mStorage[i]; } } size_t id = mStorage.size(); mNameLookup.insert(name, id); mStorage.emplace_back(*this, id, std::move(name), std::forward(args)...); return mStorage[id]; } void Remove(size_t index) { auto& item = mStorage[index]; mNameLookup.erase(item.GetName()); mStorage[index] = T(*this); } T* Find(size_t id) { return &mStorage[id]; } const T* Find(size_t id) const { return &mStorage[id]; } const T* Find(std::string_view name) const { auto iter = mNameLookup.find(name); if (iter != mNameLookup.end()) { return &mStorage[iter.value()]; } else { return nullptr; } } Json::Value Serialize() const { Json::Value items(Json::arrayValue); for (auto& item : mStorage) { if (!item.IsInvalid()) { auto elm = item.Serialize(); elm["Id"] = item.GetId(); elm["Name"] = item.GetName(); items.append(elm); } } Json::Value root; root["MaxItemId"] = mStorage.size(); root["Items"] = std::move(items); return root; } ItemList() = default; ItemList(const Json::Value& root) { constexpr const char* kMessage = "Failed to load item list from JSON."; auto& itemCount = root["MaxItemId"]; if (!itemCount.isIntegral()) throw std::runtime_error(kMessage); mStorage.resize(itemCount.asInt64(), T(*this)); auto& items = root["Items"]; if (!items.isArray()) throw std::runtime_error(kMessage); for (auto& elm : items) { if (!elm.isObject()) throw std::runtime_error(kMessage); auto& id = elm["Id"]; if (!id.isIntegral()) throw std::runtime_error(kMessage); auto& name = elm["Name"]; if (!name.isString()) throw std::runtime_error(kMessage); size_t iid = id.asInt64(); mStorage[iid] = T(*this, iid, name.asString()); mStorage[iid].Deserialize(elm); } } typename decltype(mStorage)::iterator begin() { return mStorage.begin(); } typename decltype(mStorage)::iterator end() { return mStorage.end(); } typename decltype(mStorage)::const_iterator begin() const { return mStorage.begin(); } typename decltype(mStorage)::const_iterator end() const { return mStorage.end(); } private: template friend class ItemBase; void UpdateItemName(const T& item, const std::string& newName) { mNameLookup.erase(item.GetName()); mNameLookup.insert(newName, item.GetId()); } }; template class ItemBase { private: ItemList* mList; size_t mId; std::string mName; public: ItemBase(ItemList& list, size_t id = std::numeric_limits::max(), std::string name = "") : mList{ &list } , mId{ id } , mName{ std::move(name) } { } bool IsInvalid() const { return mId == std::numeric_limits::max(); } ItemList& GetList() const { return *mList; } size_t GetId() const { return mId; } const std::string& GetName() const { return mName; } void SetName(std::string name) { mList->UpdateItemName(static_cast(*this), name); mName = std::move(name); } }; class ProductItem : public ItemBase { private: std::string mDescription; int mStock = 0; public: using ItemBase::ItemBase; const std::string& GetDescription() const; void SetDescription(std::string description); int GetStock() const; void SetStock(int stock); Json::Value Serialize() const; void Deserialize(const Json::Value& elm); }; class FactoryItem : public ItemBase { private: std::string mDescription; std::string mEmail; public: using ItemBase::ItemBase; const std::string& GetDescription() const; void SetDescription(std::string description); const std::string& GetEmail() const; void SetEmail(std::string email); Json::Value Serialize() const; void Deserialize(const Json::Value& elm); }; class CustomerItem : public ItemBase { private: std::string mDescription; std::string mEmail; public: using ItemBase::ItemBase; const std::string& GetDescription() const; void SetDescription(std::string description); const std::string& GetEmail() const; void SetEmail(std::string email); Json::Value Serialize() const; void Deserialize(const Json::Value& elm); };