morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
morph::reactive::Computed< T > Class Template Referencefinal

A derived value: computed lazily on first read, cached, and recomputed only after a source it read really changed. More...

#include <signal.hpp>

Inheritance diagram for morph::reactive::Computed< T >:
morph::reactive::detail::Node

Public Member Functions

template<typename F>
requires std::invocable<F&> && std::move_constructible<F> && std::convertible_to<std::invoke_result_t<F&>, T>
 Computed (Runtime &runtime, F fn, EqualityPolicy policy=EqualityPolicy::Auto)
 Constructs the Computed without computing it: the first read does.
 Computed (Computed const &)=delete
Computed & operator= (Computed const &)=delete
 Computed (Computed &&)=delete
Computed & operator= (Computed &&)=delete
T const & get () const
 Reads the value, bringing it up to date first, and subscribes the innermost tracked run.
T const & peek () const
 Reads the value, bringing it up to date first, without subscribing anything.
Public Member Functions inherited from morph::reactive::detail::Node
 Node (std::shared_ptr< RuntimeCore > core, std::size_t depth=0)
 Constructs a node. Off the owner this is reported (site::kOffOwner) and the node is not counted towards the core's live nodes, whose counter belongs to the owner.
virtual ~Node ()
 Unlinks this node from its sources and observers, drops every reference the core holds to it, and tells a pull running on it that it is gone.
 Node (Node const &)=delete
Node & operator= (Node const &)=delete
 Node (Node &&)=delete
Node & operator= (Node &&)=delete
void markStale (Colour colour)
 Push phase: raises this node to colour and marks its observers Check.
bool updateIfNecessary ()
 Pull phase: brings this node up to date, recomputing only if a source really changed.
std::size_t countRun (std::uint64_t epoch) noexcept
 Counts one run of this Effect in the flush numbered epoch.
std::size_t depth () const noexcept
 How deeply the scope owning this node is nested; the flush runs shallower Effects first.
bool runsAfter (Node const &other) const noexcept
 Whether this node runs after other when both are queued: it is deeper, or as deep and newer.
std::uint64_t creationOrder () const noexcept
 Where this node stands in its runtime's creation order; among Effects of one depth, the flush runs older ones first.
void settle () noexcept
 Marks this node Clean without running it (a dropped queue entry).

Additional Inherited Members

Protected Member Functions inherited from morph::reactive::detail::Node
RuntimeCore & core () const noexcept
 The runtime core.
bool bornOnOwner () const noexcept
 Whether this node was constructed on the owner; one that was not is refused its work.
void trackRead () const
 Registers this node as a source of the innermost tracked run, if any.
void forceDirty () noexcept
 Marks this node Dirty, so the next pull recomputes it.
bool isPulling () const noexcept
 Whether a pull is bringing this node up to date right now. A read of the node from inside that pull can only come from its own run or from a source's run that reads it: a cycle.
void markObserversStale (Colour colour)
 Marks every observer of this node colour.
void adoptSources (std::vector< Node * > fresh)
 Replaces this node's sources with fresh, unlinking the ones no longer read.
void mergeSources (std::vector< Node * > fresh)
 Adds fresh to this node's sources without dropping any: what a failed run keeps.

Detailed Description

template<typename T>
class morph::reactive::Computed< T >

A derived value: computed lazily on first read, cached, and recomputed only after a source it read really changed.

Observers are notified when the result changes. When == is usable for T (kEqualityUsable) and the policy is EqualityPolicy::Auto, an equal result stops propagation; otherwise every recomputation propagates.

A computation that throws leaves the Computed failed, and that is a change: observers re-run. While it is failed, a read behaves as follows:

  • the first read after the failing run rethrows that run's exception without computing again;
  • every later read retries the computation, returning its value if it now succeeds and rethrowing if it fails again.

A retry that fails again counts as unchanged and notifies nobody, so readers that retry do not wake each other. A failure after a source changed always propagates, as does a recovery, even to the value the Computed had before it failed, because its observers last saw a failure. A retry that recovers outside a flush posts one, so the observers it wakes run. A failed run keeps every source it has read, before and during that run, so a later change to any of them recomputes it.

Writing a signal inside the computation is reported and refused. So is reading the Computed while it is being brought up to date: from inside its own computation, or from the computation of a node it reads (a cycle, which may form only after the first evaluation). Such a read throws std::logic_error.

A computation may destroy its own Computed: the callable stays alive until it returns, and the Computed is not touched afterwards.

Template Parameters
TThe value type; move-constructible. It need not be default-constructible.

Definition at line 168 of file signal.hpp.

Constructor & Destructor Documentation

◆ Computed()

template<typename T>
template<typename F>
requires std::invocable<F&> && std::move_constructible<F> && std::convertible_to<std::invoke_result_t<F&>, T>
morph::reactive::Computed< T >::Computed ( Runtime & runtime,
F fn,
EqualityPolicy policy = EqualityPolicy::Auto )
inline

Constructs the Computed without computing it: the first read does.

Template Parameters
FA callable taking no arguments and returning something convertible to T; it may be move-only.
Parameters
runtimeThe runtime this computed belongs to.
fnThe computation; every signal or computed it reads becomes a dependency.
policyWhether a result equal to the last one stops propagation.

Definition at line 178 of file signal.hpp.

Member Function Documentation

◆ get()

template<typename T>
T const & morph::reactive::Computed< T >::get ( ) const
inlinenodiscard

Reads the value, bringing it up to date first, and subscribes the innermost tracked run.

Off the owner the read is reported (detail::site::kOffOwner) and refused: it recomputes nothing and subscribes nothing, and returns the value the last successful computation produced, read without synchronisation against the owner.

Returns
The current value; valid until the next recomputation.
Exceptions
Whateverthe computation throws. std::logic_error when the Computed is read while it is being brought up to date (reported, detail::site::kComputedReadsItself), when its computation destroys it, or off the owner when it has never been computed successfully.

Definition at line 198 of file signal.hpp.

◆ peek()

template<typename T>
T const & morph::reactive::Computed< T >::peek ( ) const
inlinenodiscard

Reads the value, bringing it up to date first, without subscribing anything.

Off the owner it behaves as get() does there.

Returns
The current value; valid until the next recomputation.
Exceptions
Whateverget() throws.

Definition at line 212 of file signal.hpp.


The documentation for this class was generated from the following file: