diff options
author | Roman Smrž <roman.smrz@seznam.cz> | 2023-06-17 21:58:32 +0200 |
---|---|---|
committer | Roman Smrž <roman.smrz@seznam.cz> | 2023-06-18 22:41:23 +0200 |
commit | e7d6aafd3c9353d9e6169ca775cf1dae618238cd (patch) | |
tree | 6df8f296d7db8dd9e7d23f5774009ccc5ee269a7 | |
parent | 2130d07cbf91e016fd21a730a8449dd4bd34a093 (diff) |
Storage: iterable type for record item list
-rw-r--r-- | include/erebos/storage.h | 187 | ||||
-rw-r--r-- | src/attach.cpp | 7 | ||||
-rw-r--r-- | src/channel.cpp | 7 | ||||
-rw-r--r-- | src/contact.cpp | 14 | ||||
-rw-r--r-- | src/identity.cpp | 7 | ||||
-rw-r--r-- | src/message.cpp | 7 | ||||
-rw-r--r-- | src/pubkey.h | 7 | ||||
-rw-r--r-- | src/set.cpp | 14 | ||||
-rw-r--r-- | src/state.cpp | 14 | ||||
-rw-r--r-- | src/storage.cpp | 165 |
10 files changed, 284 insertions, 145 deletions
diff --git a/include/erebos/storage.h b/include/erebos/storage.h index 3a3073d..32049db 100644 --- a/include/erebos/storage.h +++ b/include/erebos/storage.h @@ -40,8 +40,12 @@ template<typename T> class Head; using std::bind; using std::call_once; using std::make_unique; +using std::monostate; using std::move; +using std::optional; +using std::shared_ptr; using std::string; +using std::variant; using std::vector; class PartialStorage @@ -222,54 +226,8 @@ template<class S> class RecordT { public: - class Item { - public: - struct UnknownType - { - std::string type; - std::string value; - }; - - struct Empty {}; - - typedef std::variant< - std::monostate, - Empty, - int, - std::string, - std::vector<uint8_t>, - ZonedTime, - UUID, - typename S::Ref, - UnknownType> Variant; - - Item(const std::string & name): - Item(name, std::monostate()) {} - Item(const std::string & name, Variant value): - name(name), value(value) {} - template<typename T> - Item(const std::string & name, const Stored<T> & value): - Item(name, value.ref()) {} - - Item(const Item &) = default; - Item & operator=(const Item &) = delete; - - operator bool() const; - - std::optional<Empty> asEmpty() const; - std::optional<int> asInteger() const; - std::optional<std::string> asText() const; - std::optional<std::vector<uint8_t>> asBinary() const; - std::optional<ZonedTime> asDate() const; - std::optional<UUID> asUUID() const; - std::optional<typename S::Ref> asRef() const; - std::optional<UnknownType> asUnknown() const; - - template<typename T> std::optional<Stored<T>> as() const; - - const std::string name; - const Variant value; - }; + class Item; + class Items; private: RecordT(const std::shared_ptr<std::vector<Item>> & ptr): @@ -280,10 +238,10 @@ public: RecordT(std::vector<Item> &&); std::vector<uint8_t> encode() const; - const std::vector<Item> & items() const; + Items items() const; Item item(const std::string & name) const; Item operator[](const std::string & name) const; - std::vector<Item> items(const std::string & name) const; + Items items(const std::string & name) const; private: friend ObjectT<S>; @@ -295,6 +253,123 @@ private: const std::shared_ptr<const std::vector<Item>> ptr; }; +template<class S> +class RecordT<S>::Item +{ +public: + struct UnknownType + { + string type; + string value; + }; + + struct Empty {}; + + using Integer = int; + using Text = string; + using Binary = vector<uint8_t>; + using Date = ZonedTime; + using UUID = erebos::UUID; + using Ref = typename S::Ref; + + using Variant = variant< + monostate, + Empty, + int, + string, + vector<uint8_t>, + ZonedTime, + UUID, + typename S::Ref, + UnknownType>; + + Item(const string & name): + Item(name, monostate()) {} + Item(const string & name, Variant value): + name(name), value(value) {} + template<typename T> + Item(const string & name, const Stored<T> & value): + Item(name, value.ref()) {} + + Item(const Item &) = default; + Item & operator=(const Item &) = delete; + + operator bool() const; + + optional<Empty> asEmpty() const; + optional<Integer> asInteger() const; + optional<Text> asText() const; + optional<Binary> asBinary() const; + optional<Date> asDate() const; + optional<UUID> asUUID() const; + optional<Ref> asRef() const; + optional<UnknownType> asUnknown() const; + + template<typename T> optional<Stored<T>> as() const; + + const string name; + const Variant value; +}; + +template<class S> +class RecordT<S>::Items +{ +public: + using Empty = typename Item::Empty; + using Integer = typename Item::Integer; + using Text = typename Item::Text; + using Binary = typename Item::Binary; + using Date = typename Item::Date; + using UUID = typename Item::UUID; + using Ref = typename Item::Ref; + using UnknownType = typename Item::UnknownType; + + Items(shared_ptr<const vector<Item>> items); + Items(shared_ptr<const vector<Item>> items, string filter); + + class Iterator + { + Iterator(const Items & source, size_t idx); + friend Items; + public: + using iterator_category = std::forward_iterator_tag; + using value_type = Item; + using difference_type = ssize_t; + using pointer = const Item *; + using reference = const Item &; + + Iterator(const Iterator &) = default; + ~Iterator() = default; + Iterator & operator=(const Iterator &) = default; + Iterator & operator++(); + value_type operator*() const { return (*source.items)[idx]; } + bool operator==(const Iterator & other) const { return idx == other.idx; } + bool operator!=(const Iterator & other) const { return idx != other.idx; } + + private: + const Items & source; + size_t idx; + }; + + Iterator begin() const; + Iterator end() const; + + vector<Empty> asEmpty() const; + vector<Integer> asInteger() const; + vector<Text> asText() const; + vector<Binary> asBinary() const; + vector<Date> asDate() const; + vector<UUID> asUUID() const; + vector<Ref> asRef() const; + vector<UnknownType> asUnknown() const; + + template<typename T> vector<Stored<T>> as() const; + +private: + const shared_ptr<const vector<Item>> items; + const optional<string> filter; +}; + extern template class RecordT<Storage>; extern template class RecordT<PartialStorage>; @@ -367,6 +442,18 @@ std::optional<Stored<T>> RecordT<S>::Item::as() const return std::nullopt; } +template<class S> +template<typename T> +vector<Stored<T>> RecordT<S>::Items::as() const +{ + auto refs = asRef(); + vector<Stored<T>> res; + res.reserve(refs.size()); + for (const auto & ref : refs) + res.push_back(Stored<T>::load(ref)); + return res; +} + class Generation { public: diff --git a/src/attach.cpp b/src/attach.cpp index 4bf06b1..74bc875 100644 --- a/src/attach.cpp +++ b/src/attach.cpp @@ -105,14 +105,9 @@ AttachIdentity AttachIdentity::load(const Ref & ref) .keys = {}, }; - vector<vector<uint8_t>> keys; - for (auto s : rec->items("skey")) - if (const auto & b = s.asBinary()) - keys.push_back(*b); - return AttachIdentity { .identity = *rec->item("identity").as<Signed<IdentityData>>(), - .keys = keys, + .keys = rec->items("skey").asBinary(), }; } diff --git a/src/channel.cpp b/src/channel.cpp index 08db911..b317f3d 100644 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -26,15 +26,10 @@ Ref ChannelRequestData::store(const Storage & st) const ChannelRequestData ChannelRequestData::load(const Ref & ref) { if (auto rec = ref->asRecord()) { - remove_const<decltype(peers)>::type peers; - for (const auto & i : rec->items("peer")) - if (auto p = i.as<Signed<IdentityData>>()) - peers.push_back(*p); - if (rec->item("enc").asText() == "aes-128-gcm") if (auto key = rec->item("key").as<PublicKexKey>()) return ChannelRequestData { - .peers = std::move(peers), + .peers = rec->items("peer").as<Signed<IdentityData>>(), .key = *key, }; } diff --git a/src/contact.cpp b/src/contact.cpp index 0050f95..01aa710 100644 --- a/src/contact.cpp +++ b/src/contact.cpp @@ -111,19 +111,9 @@ ContactData ContactData::load(const Ref & ref) if (!rec) return ContactData(); - vector<Stored<ContactData>> prev; - for (const auto & x : rec->items("PREV")) - if (const auto & p = x.as<ContactData>()) - prev.push_back(*p); - - vector<Stored<Signed<IdentityData>>> identity; - for (const auto & x : rec->items("identity")) - if (const auto & i = x.asRef()) - identity.push_back(*i); - return ContactData { - .prev = std::move(prev), - .identity = std::move(identity), + .prev = rec->items("PREV").as<ContactData>(), + .identity = rec->items("identity").as<Signed<IdentityData>>(), .name = rec->item("name").asText(), }; } diff --git a/src/identity.cpp b/src/identity.cpp index 9077db2..3b8d3bf 100644 --- a/src/identity.cpp +++ b/src/identity.cpp @@ -239,14 +239,9 @@ void Identity::Builder::owner(const Identity & val) IdentityData IdentityData::load(const Ref & ref) { if (auto rec = ref->asRecord()) { - vector<Stored<Signed<IdentityData>>> prev; - for (auto p : rec->items("SPREV")) - if (const auto & x = p.as<Signed<IdentityData>>()) - prev.push_back(x.value()); - if (auto keyIdentity = rec->item("key-id").as<PublicKey>()) return IdentityData { - .prev = std::move(prev), + .prev = rec->items("SPREV").as<Signed<IdentityData>>(), .name = rec->item("name").asText(), .owner = rec->item("owner").as<Signed<IdentityData>>(), .keyIdentity = keyIdentity.value(), diff --git a/src/message.cpp b/src/message.cpp index ff8e05b..06ee8ad 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -55,15 +55,10 @@ DirectMessageData DirectMessageData::load(const Ref & ref) if (!rec) return DirectMessageData(); - vector<Stored<DirectMessageData>> prev; - for (auto p : rec->items("PREV")) - if (const auto & x = p.as<DirectMessageData>()) - prev.push_back(*x); - auto fref = rec->item("from").asRef(); return DirectMessageData { - .prev = std::move(prev), + .prev = rec->items("PREV").as<DirectMessageData>(), .from = fref ? Identity::load(*fref) : nullopt, .time = *rec->item("time").asDate(), .text = rec->item("text").asText().value(), diff --git a/src/pubkey.h b/src/pubkey.h index 5cb693b..ca662ba 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -110,10 +110,9 @@ Signed<T> Signed<T>::load(const Ref & ref) if (auto rec = ref->asRecord()) if (auto data = rec->item("SDATA").as<T>()) { vector<Stored<Signature>> sigs; - for (auto item : rec->items("sig")) - if (auto sig = item.as<Signature>()) - if (sig.value()->verify(data.value().ref())) - sigs.push_back(sig.value()); + for (const auto & sig : rec->items("sig").as<Signature>()) + if (sig->verify(data.value().ref())) + sigs.push_back(sig); return Signed(*data, sigs); } diff --git a/src/set.cpp b/src/set.cpp index d224af3..ce343d8 100644 --- a/src/set.cpp +++ b/src/set.cpp @@ -153,19 +153,9 @@ vector<Ref> SetBase::store() const SetItem SetItem::load(const Ref & ref) { if (auto rec = ref->asRecord()) { - vector<Stored<SetItem>> prev; - for (auto p : rec->items("PREV")) - if (const auto & x = p.as<SetItem>()) - prev.push_back(*x); - - vector<Ref> item; - for (auto i : rec->items("item")) - if (const auto & x = i.asRef()) - item.push_back(*x); - return SetItem { - .prev = std::move(prev), - .item = std::move(item), + .prev = rec->items("PREV").as<SetItem>(), + .item = rec->items("item").asRef(), }; } diff --git a/src/state.cpp b/src/state.cpp index 6ad9f89..8e5dcad 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -22,9 +22,7 @@ LocalState::LocalState(const Ref & ref): if (auto x = rec->item("id").asRef()) p->identity = Identity::load(*x); - for (auto i : rec->items("shared")) - if (const auto & x = i.as<SharedData>()) - p->shared.tip.push_back(*x); + p->shared.tip = rec->items("shared").as<SharedData>(); if (p->identity) { vector<Stored<Signed<IdentityData>>> updates; @@ -158,16 +156,10 @@ SharedData::SharedData(const Ref & ref) if (!rec) return; - for (auto i : rec->items("PREV")) - if (const auto & x = i.as<SharedData>()) - prev.push_back(*x); - + prev = rec->items("PREV").as<SharedData>(); if (auto x = rec->item("type").asUUID()) type = *x; - - for (auto i : rec->items("value")) - if (const auto & x = i.asRef()) - value.push_back(*x); + value = rec->items("value").asRef(); } Ref SharedData::store(const Storage & st) const diff --git a/src/storage.cpp b/src/storage.cpp index fb3698c..4e56b2e 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -789,10 +789,9 @@ optional<Digest> Storage::Priv::copy(const ObjectT<S> & pobj, vector<Digest> * m { bool fail = false; if (auto rec = pobj.asRecord()) - for (const auto & item : rec->items()) - if (auto r = item.asRef()) - if (!copy<S>(*r, missing)) - fail = true; + for (const auto & r : rec->items().asRef()) + if (!copy<S>(r, missing)) + fail = true; if (fail) return nullopt; @@ -1032,24 +1031,13 @@ vector<Ref> Ref::previous() const if (!rec) return {}; - vector<Ref> res; - - auto sdata = rec->item("SDATA").asRef(); - if (sdata) { - auto drec = sdata.value()->asRecord(); - if (!drec) - return {}; - - for (const Record::Item & i : drec->items("SPREV")) - if (auto x = i.asRef()) - res.push_back(*x); - return res; + if (auto sdata = rec->item("SDATA").asRef()) { + if (auto drec = sdata.value()->asRecord()) + return drec->items("SPREV").asRef(); + return {}; } - for (const Record::Item & i : rec->items("PREV")) - if (auto x = i.asRef()) - res.push_back(*x); - return res; + return rec->items("PREV").asRef(); } Generation Ref::generation() const @@ -1177,6 +1165,125 @@ optional<typename RecordT<S>::Item::UnknownType> RecordT<S>::Item::asUnknown() c return nullopt; } +template<class S> +RecordT<S>::Items::Items(shared_ptr<const vector<Item>> items): + items(move(items)), filter(nullopt) +{} + +template<class S> +RecordT<S>::Items::Items(shared_ptr<const vector<Item>> items, string filter): + items(move(items)), filter(move(filter)) +{} + +template<class S> +RecordT<S>::Items::Iterator::Iterator(const Items & source, size_t idx): + source(source), idx(idx) +{} + +template<class S> +typename RecordT<S>::Items::Iterator & RecordT<S>::Items::Iterator::operator++() +{ + const auto & items = *source.items; + do { + idx++; + } while (idx < items.size() && + source.filter && + items[idx].name != *source.filter); + return *this; +} + +template<class S> +typename RecordT<S>::Items::Iterator RecordT<S>::Items::begin() const +{ + return ++Iterator(*this, -1); +} + +template<class S> +typename RecordT<S>::Items::Iterator RecordT<S>::Items::end() const +{ + return Iterator(*this, items->size()); +} + +template<class S> +vector<typename RecordT<S>::Item::Empty> RecordT<S>::Items::asEmpty() const +{ + vector<Empty> res; + for (const auto & item : *this) + if (holds_alternative<Empty>(item.value)) + res.push_back(std::get<Empty>(item.value)); + return res; +} + +template<class S> +vector<typename RecordT<S>::Item::Integer> RecordT<S>::Items::asInteger() const +{ + vector<Integer> res; + for (const auto & item : *this) + if (holds_alternative<Integer>(item.value)) + res.push_back(std::get<Integer>(item.value)); + return res; +} + +template<class S> +vector<typename RecordT<S>::Item::Text> RecordT<S>::Items::asText() const +{ + vector<Text> res; + for (const auto & item : *this) + if (holds_alternative<Text>(item.value)) + res.push_back(std::get<Text>(item.value)); + return res; +} + +template<class S> +vector<typename RecordT<S>::Item::Binary> RecordT<S>::Items::asBinary() const +{ + vector<Binary> res; + for (const auto & item : *this) + if (holds_alternative<Binary>(item.value)) + res.push_back(std::get<Binary>(item.value)); + return res; +} + +template<class S> +vector<typename RecordT<S>::Item::Date> RecordT<S>::Items::asDate() const +{ + vector<Date> res; + for (const auto & item : *this) + if (holds_alternative<Date>(item.value)) + res.push_back(std::get<Date>(item.value)); + return res; +} + +template<class S> +vector<typename RecordT<S>::Item::UUID> RecordT<S>::Items::asUUID() const +{ + vector<UUID> res; + for (const auto & item : *this) + if (holds_alternative<UUID>(item.value)) + res.push_back(std::get<UUID>(item.value)); + return res; +} + +template<class S> +vector<typename RecordT<S>::Item::Ref> RecordT<S>::Items::asRef() const +{ + vector<Ref> res; + for (const auto & item : *this) + if (holds_alternative<Ref>(item.value)) + res.push_back(std::get<Ref>(item.value)); + return res; +} + +template<class S> +vector<typename RecordT<S>::Item::UnknownType> RecordT<S>::Items::asUnknown() const +{ + vector<UnknownType> res; + for (const auto & item : *this) + if (holds_alternative<UnknownType>(item.value)) + res.push_back(std::get<UnknownType>(item.value)); + return res; +} + template<class S> RecordT<S>::RecordT(const vector<Item> & from): @@ -1274,9 +1381,9 @@ vector<uint8_t> RecordT<S>::encode() const } template<class S> -const vector<typename RecordT<S>::Item> & RecordT<S>::items() const +typename RecordT<S>::Items RecordT<S>::items() const { - return *ptr; + return Items(ptr); } template<class S> @@ -1296,14 +1403,9 @@ typename RecordT<S>::Item RecordT<S>::operator[](const string & name) const } template<class S> -vector<typename RecordT<S>::Item> RecordT<S>::items(const string & name) const +typename RecordT<S>::Items RecordT<S>::items(const string & name) const { - vector<Item> res; - for (auto item : *ptr) { - if (item.name == name) - res.push_back(item); - } - return res; + return Items(ptr, name); } template<class S> @@ -1544,9 +1646,8 @@ vector<Stored<Object>> erebos::collectStoredObjects(const Stored<Object> & from) res.push_back(cur); if (auto rec = cur->asRecord()) - for (const auto & item : rec->items()) - if (auto ref = item.asRef()) - queue.push_back(Stored<Object>::load(*ref)); + for (const auto & ref : rec->items().asRef()) + queue.push_back(Stored<Object>::load(ref)); } return res; |