From 02a2fbef0df2714f5fa598d82765ce463321ab56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Smr=C5=BE?= Date: Mon, 8 Nov 2021 21:24:46 +0100 Subject: Storage: implement Stored using call_once --- include/erebos/storage.h | 100 ++++++++++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 35 deletions(-) (limited to 'include/erebos/storage.h') diff --git a/include/erebos/storage.h b/include/erebos/storage.h index 9d28ec7..2581dd7 100644 --- a/include/erebos/storage.h +++ b/include/erebos/storage.h @@ -9,11 +9,12 @@ #include #include #include -#include #include +#include #include #include #include +#include #include #include @@ -36,6 +37,11 @@ class Blob; template class Stored; template class Head; +using std::bind; +using std::call_once; +using std::make_unique; +using std::move; + class PartialStorage { public: @@ -346,7 +352,7 @@ std::optional> RecordT::Item::as() const template class Stored { - Stored(Ref ref, std::future && val): mref(ref), mval(std::move(val)) {} + Stored(Ref ref, T x); friend class Storage; friend class Head; public: @@ -355,51 +361,75 @@ public: Stored & operator=(const Stored &) = default; Stored & operator=(Stored &&) = default; - Stored(const Ref &); + Stored(Ref); static Stored load(const Ref &); Ref store(const Storage &) const; bool operator==(const Stored & other) const - { return mref.digest() == other.mref.digest(); } + { return p->ref.digest() == other.p->ref.digest(); } bool operator!=(const Stored & other) const - { return mref.digest() != other.mref.digest(); } + { return p->ref.digest() != other.p->ref.digest(); } bool operator<(const Stored & other) const - { return mref.digest() < other.mref.digest(); } + { return p->ref.digest() < other.p->ref.digest(); } bool operator<=(const Stored & other) const - { return mref.digest() <= other.mref.digest(); } + { return p->ref.digest() <= other.p->ref.digest(); } bool operator>(const Stored & other) const - { return mref.digest() > other.mref.digest(); } + { return p->ref.digest() > other.p->ref.digest(); } bool operator>=(const Stored & other) const - { return mref.digest() >= other.mref.digest(); } + { return p->ref.digest() >= other.p->ref.digest(); } - const T & operator*() const { return mval.get(); } - const T * operator->() const { return &mval.get(); } + void init() const; + const T & operator*() const { init(); return *p->val; } + const T * operator->() const { init(); return p->val.get(); } std::vector> previous() const; bool precedes(const Stored &) const; - const Ref & ref() const { return mref; } + const Ref & ref() const { return p->ref; } private: - Ref mref; - std::shared_future mval; + struct Priv { + const Ref ref; + mutable std::once_flag once {}; + mutable std::unique_ptr val {}; + mutable std::function init {}; + }; + std::shared_ptr p; }; +template +void Stored::init() const +{ + call_once(p->once, [this]() { + p->val = std::make_unique(p->init()); + p->init = decltype(p->init)(); + }); +} + template Stored Storage::store(const T & val) const { - return Stored(val.store(*this), std::async(std::launch::deferred, [val] { - return val; - })); + return Stored(val.store(*this), val); } template -Stored::Stored(const Ref & ref): - mref(ref), - mval(std::async(std::launch::deferred, [ref] { - return T::load(ref); - })) -{} +Stored::Stored(Ref ref, T x): + p(new Priv { + .ref = move(ref), + .val = make_unique(move(x)), + }) +{ + call_once(p->once, [](){}); +} + +template +Stored::Stored(Ref ref): + p(new Priv { + .ref = move(ref), + }) +{ + p->init = [p = p.get()]() { return T::load(p->ref); }; +} template Stored Stored::load(const Ref & ref) @@ -410,15 +440,15 @@ Stored Stored::load(const Ref & ref) template Ref Stored::store(const Storage & st) const { - if (st == mref.storage()) - return mref; - return st.storeObject(*mref); + if (st == p->ref.storage()) + return p->ref; + return st.storeObject(*p->ref); } template std::vector> Stored::previous() const { - auto rec = mref->asRecord(); + auto rec = p->ref->asRecord(); if (!rec) return {}; @@ -429,14 +459,14 @@ std::vector> Stored::previous() const return {}; std::vector> res; - for (const auto & i : drec->items("SPREV")) + for (const Record::Item & i : drec->items("SPREV")) if (auto x = i.as()) res.push_back(*x); return res; } std::vector> res; - for (auto & i : rec->items("PREV")) + for (const Record::Item & i : rec->items("PREV")) if (auto x = i.as()) res.push_back(*x); return res; @@ -481,8 +511,10 @@ template class WatchedHead; template class Head { - Head(UUID id, Ref ref, std::future && val): - mid(id), mstored(ref, std::move(val)) {} + Head(UUID id, Stored stored): + mid(id), mstored(move(stored)) {} + Head(UUID id, Ref ref, T val): + mid(id), mstored(move(ref), move(val)) {} friend class Storage; public: Head(UUID id, Ref ref): mid(id), mstored(ref) {} @@ -568,16 +600,14 @@ Head Storage::storeHead(const T & val) const { auto ref = val.store(*this); auto id = storeHead(T::headTypeId, ref); - return Head(id, ref, std::async(std::launch::deferred, [val] { - return val; - })); + return Head(id, ref, val); } template Head Storage::storeHead(const Stored & val) const { auto id = storeHead(T::headTypeId, val.ref()); - return Head(id, val.ref(), val.mval); + return Head(id, val); } template -- cgit v1.2.3