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; |