aboutsummaryrefslogtreecommitdiff
path: root/core/src/Model/Items.hpp
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2021-03-31 20:19:18 -0700
committerrtk0c <[email protected]>2021-03-31 20:19:18 -0700
commit44f5fa5c8f258e8fc1f7d7e2e45e0485bd6cc490 (patch)
tree3f09a1cce46d38f5a8c6266150e67af3802d4b95 /core/src/Model/Items.hpp
parent31950890c939862f79c817053c106bf711c63a64 (diff)
Complete items tab (UI and serialization)
Diffstat (limited to 'core/src/Model/Items.hpp')
-rw-r--r--core/src/Model/Items.hpp209
1 files changed, 142 insertions, 67 deletions
diff --git a/core/src/Model/Items.hpp b/core/src/Model/Items.hpp
index 0c7be41..e20a290 100644
--- a/core/src/Model/Items.hpp
+++ b/core/src/Model/Items.hpp
@@ -1,54 +1,21 @@
#pragma once
+#include "cplt_fwd.hpp"
+
+#include <json/reader.h>
+#include <json/value.h>
+#include <json/writer.h>
#include <tsl/array_map.h>
#include <cstddef>
+#include <limits>
#include <stdexcept>
#include <string>
#include <string_view>
+#include <utility>
#include <vector>
-/// Pointers and references returned by accessors are valid as long as no non-const functions have been called.
template <class T>
class ItemList {
-public:
- class Iterator {
- private:
- typename std::vector<T>::const_iterator mBackingIter;
-
- public:
- Iterator(typename std::vector<T>::const_iterator it)
- : mBackingIter{ it } {
- }
-
- Iterator& operator++() {
- ++mBackingIter;
- return *this;
- }
-
- Iterator& operator++(int) {
- auto tmp = *this;
- ++mBackingIter;
- return tmp;
- }
-
- Iterator& operator--() {
- --mBackingIter;
- return *this;
- }
-
- Iterator& operator--(int) {
- auto tmp = *this;
- --mBackingIter;
- return tmp;
- }
-
- const T& operator*() const {
- return *mBackingIter;
- }
-
- friend bool operator==(const Iterator&, const Iterator&) = default;
- };
-
private:
std::vector<T> mStorage;
tsl::array_map<char, size_t> mNameLookup;
@@ -61,9 +28,28 @@ public:
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>(args)...);
+ mNameLookup.insert(name, i);
+ return mStorage[i];
+ }
+ }
+
size_t id = mStorage.size();
mNameLookup.insert(name, id);
- return mStorage.emplace_back(id, std::move(name), std::forward<Args>(args)...);
+ mStorage.emplace_back(*this, id, std::move(name), std::forward<Args>(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 {
@@ -79,68 +65,157 @@ public:
}
}
- Iterator begin() const {
- return Iterator(mStorage.begin());
+ 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;
}
- Iterator end() const {
- return Iterator(mStorage.end());
+ 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 <class TSelf>
+ friend class ItemBase;
+
+ void UpdateItemName(const T& item, const std::string& newName) {
+ mNameLookup.erase(item.GetName());
+ mNameLookup.insert(newName, item.GetId());
}
};
+template <class TSelf>
class ItemBase {
private:
+ ItemList<TSelf>* mList;
size_t mId;
+ std::string mName;
public:
- ItemBase();
- ItemBase(size_t id);
+ ItemBase(ItemList<TSelf>& list, size_t id = std::numeric_limits<size_t>::max(), std::string name = "")
+ : mList{ &list }
+ , mId{ id }
+ , mName{ std::move(name) } {
+ }
- bool IsInvalid() const;
- size_t GetId() const;
+ bool IsInvalid() const {
+ return mId == std::numeric_limits<size_t>::max();
+ }
+
+ ItemList<TSelf>& 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<TSelf&>(*this), name);
+ mName = std::move(name);
+ }
};
-class ProductItem : public ItemBase {
+class ProductItem : public ItemBase<ProductItem> {
private:
- std::string mName;
std::string mDescription;
public:
- ProductItem() {}
- ProductItem(size_t id, std::string name);
+ using ItemBase::ItemBase;
- const std::string& GetName() const;
- void SetName(std::string mName);
const std::string& GetDescription() const;
void SetDescription(std::string description);
+
+ Json::Value Serialize() const;
+ void Deserialize(const Json::Value& elm);
};
-class FactoryItem : public ItemBase {
+class FactoryItem : public ItemBase<FactoryItem> {
private:
- std::string mName;
std::string mDescription;
+ std::string mEmail;
public:
- FactoryItem() {}
- FactoryItem(size_t id, std::string name);
+ using ItemBase::ItemBase;
- const std::string& GetName() const;
- void SetName(std::string name);
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 {
+class CustomerItem : public ItemBase<CustomerItem> {
private:
- std::string mName;
std::string mDescription;
+ std::string mEmail;
public:
- CustomerItem() {}
- CustomerItem(size_t id, std::string name);
+ using ItemBase::ItemBase;
- const std::string& GetName() const;
- void SetName(std::string name);
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);
};