#pragma once #include #include #include #include #include namespace erebos { using std::optional; using std::shared_ptr; using std::vector; template struct SharedType { static const UUID id; static T(*const load)(const vector &); static vector(*const store)(const T &); }; #define DECLARE_SHARED_TYPE(T) \ template<> const UUID erebos::SharedType::id; \ template<> T(*const erebos::SharedType::load)(const std::vector &); \ template<> std::vector(*const erebos::SharedType::store) (const T &); #define DEFINE_SHARED_TYPE(T, id_, load_, store_) \ template<> const UUID erebos::SharedType::id { id_ }; \ template<> T(*const erebos::SharedType::load)(const vector &) { load_ }; \ template<> std::vector(*const erebos::SharedType::store) (const T &) { store_ }; class Identity; class LocalState { public: LocalState(); explicit LocalState(const Ref &); static LocalState load(const Ref & ref) { return LocalState(ref); } Ref store(const Storage &) const; static const UUID headTypeId; const optional & identity() const; LocalState identity(const Identity &) const; template T shared() const; template LocalState shared(const T & x) const; vector sharedRefs() const; LocalState sharedRefAdd(const Ref &) const; template static T lens(const LocalState &); private: vector lookupShared(UUID) const; LocalState updateShared(UUID, const vector &) const; struct Priv; std::shared_ptr p; }; class SharedState { public: template T get() const; template static T lens(const SharedState &); bool operator==(const SharedState &) const; bool operator!=(const SharedState &) const; private: vector lookup(UUID) const; struct Priv; SharedState(shared_ptr && p): p(std::move(p)) {} shared_ptr p; friend class LocalState; }; template T LocalState::shared() const { return SharedType::load(lookupShared(SharedType::id)); } template LocalState LocalState::shared(const T & x) const { return updateShared(SharedType::id, SharedType::store(x)); } template T SharedState::get() const { return SharedType::load(lookup(SharedType::id)); } template T SharedState::lens(const SharedState & x) { return x.get(); } }