summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Smrž <roman.smrz@seznam.cz>2023-06-17 21:58:32 +0200
committerRoman Smrž <roman.smrz@seznam.cz>2023-06-18 22:41:23 +0200
commite7d6aafd3c9353d9e6169ca775cf1dae618238cd (patch)
tree6df8f296d7db8dd9e7d23f5774009ccc5ee269a7
parent2130d07cbf91e016fd21a730a8449dd4bd34a093 (diff)
Storage: iterable type for record item list
-rw-r--r--include/erebos/storage.h187
-rw-r--r--src/attach.cpp7
-rw-r--r--src/channel.cpp7
-rw-r--r--src/contact.cpp14
-rw-r--r--src/identity.cpp7
-rw-r--r--src/message.cpp7
-rw-r--r--src/pubkey.h7
-rw-r--r--src/set.cpp14
-rw-r--r--src/state.cpp14
-rw-r--r--src/storage.cpp165
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;