Aria 2.0.0
C++23 MVVM framework (C++20 minimum) — reactive, coroutine-first, ABI-layered
Loading...
Searching...
No Matches
aria::Computed< T > Class Template Referencefinal

#include <computed.hpp>

Inheritance diagram for aria::Computed< T >:
[legend]

Public Types

using value_type = T

Public Member Functions

template<std::invocable<> Fn>
requires std::convertible_to<std::invoke_result_t<Fn>, T>
 Computed (Fn fn)
 Construct and perform the initial compute eagerly, so get() immediately returns the correct value without any flush.
 Computed (const Computed &)=delete
 Computed (Computed &&)=delete
Computedoperator= (const Computed &)=delete
Computedoperator= (Computed &&)=delete
 ~Computed () noexcept override
 Explicit destructor: detach every upstream edge before the edge pool releases the storage backing them.
get () const
 Return the cached value, ensuring it is up to date.
const T & get_ref () const
 Read by const reference.
peek () const noexcept(std::is_nothrow_copy_constructible_v< T >)
 Non-tracking snapshot read.
const T & peek_ref () const noexcept
 Non-tracking snapshot read by const reference.
 operator T () const
::aria::Subscription on_changed (std::function< void(const T &)> fn)
::aria::Subscription bind (std::function< void(const T &)> fn)
::aria::Subscription observe (std::function< void(const T &, const T &)> fn)
bool recompute () override
 Called by the Graph when an upstream has changed.
std::size_t dependency_count () const noexcept
 Number of upstreams currently in use.
Public Member Functions inherited from aria::reactive::Node
 Node (NodeKind kind) noexcept
virtual ~Node () noexcept
 Node (const Node &)=delete
Nodeoperator= (const Node &)=delete
 Node (Node &&)=delete
Nodeoperator= (Node &&)=delete
NodeKind kind () const noexcept
NodeState state () const noexcept
std::uint64_t version () const noexcept
const std::string & debug_name () const noexcept
void set_debug_name (std::string name)
const std::string & effective_debug_name () const
 A non-empty debug label for diagnostic output.
void notify_changed ()
 Called by a Source after its value has actually changed: bumps the version and colors all downstream nodes MaybeDirty.
void mark_downstream_maybe_dirty ()
 Mark self and all reachable descendants as MaybeDirty.
void mark_dirty () noexcept
 Escalate state to Dirty (used by Graph::pull after confirming an upstream has truly moved).
std::uint32_t depth () const noexcept
 Topological depth used by flush ordering.
void set_depth (std::uint32_t d) noexcept
virtual std::shared_ptr< Noderetain_for_recompute () noexcept
 Reactions are shared-owned and may cancel themselves while running.
void attach_as_observer_of (Node &source, Edge &edge) noexcept
void detach_edge (Edge &edge) noexcept
void clear_sources () noexcept
 Drop every upstream edge.
template<class F>
void for_each_observer (F &&f)
 Iterate the observer list (used by Graph to color downstream nodes).
template<class F>
void for_each_source (F &&f) const
 Iterate the source list (used by a Derivation in pull() to compare each upstream's current version against observed_version).
bool has_observers () const noexcept
bool has_sources () const noexcept

Additional Inherited Members

Static Public Member Functions inherited from aria::reactive::Node
static Graphgraph () noexcept
 Returns the process-wide singleton Graph this node belongs to.
Protected Member Functions inherited from aria::reactive::Node
void retire_ () noexcept
 Retire before derived members (including user captures) are destroyed.
void bump_version_ () noexcept
void set_state_ (NodeState s) noexcept

Member Typedef Documentation

◆ value_type

template<PropertyValue T>
using aria::reactive::Computed< T >::value_type = T

Constructor & Destructor Documentation

◆ Computed() [1/3]

template<PropertyValue T>
template<std::invocable<> Fn>
requires std::convertible_to<std::invoke_result_t<Fn>, T>
aria::reactive::Computed< T >::Computed ( Fn fn)
inlineexplicit

Construct and perform the initial compute eagerly, so get() immediately returns the correct value without any flush.

A deliberate choice: eager first-run keeps observer semantics simple (observers never see "empty" / default-constructed state).

◆ Computed() [2/3]

template<PropertyValue T>
aria::reactive::Computed< T >::Computed ( const Computed< T > & )
delete

◆ Computed() [3/3]

template<PropertyValue T>
aria::reactive::Computed< T >::Computed ( Computed< T > && )
delete

◆ ~Computed()

template<PropertyValue T>
aria::reactive::Computed< T >::~Computed ( )
inlineoverridenoexcept

Explicit destructor: detach every upstream edge before the edge pool releases the storage backing them.

If we rely on the default destruction sequence, edge_pool_ (a derived-class member) runs first and frees every Edge object; then ~Node() would call clear_sources() and dereference the already-freed list head -> classic use-after-free SIGSEGV.

Member Function Documentation

◆ operator=() [1/2]

template<PropertyValue T>
Computed & aria::reactive::Computed< T >::operator= ( const Computed< T > & )
delete

◆ operator=() [2/2]

template<PropertyValue T>
Computed & aria::reactive::Computed< T >::operator= ( Computed< T > && )
delete

◆ get()

template<PropertyValue T>
T aria::reactive::Computed< T >::get ( ) const
inlinenodiscard

Return the cached value, ensuring it is up to date.

If the graph has pending changes that could affect us, we pull ourselves first so the caller always sees a glitch-free value.

◆ get_ref()

template<PropertyValue T>
const T & aria::reactive::Computed< T >::get_ref ( ) const
inlinenodiscard

Read by const reference.

Same semantics as get() (auto-tracking

  • lazy pull) but avoids the copy on hot paths.

◆ peek()

template<PropertyValue T>
T aria::reactive::Computed< T >::peek ( ) const
inlinenodiscardnoexcept

Non-tracking snapshot read.

noexcept is conditional on T's copy ctor; if T may throw we still don't want to terminate.

◆ peek_ref()

template<PropertyValue T>
const T & aria::reactive::Computed< T >::peek_ref ( ) const
inlinenodiscardnoexcept

Non-tracking snapshot read by const reference.

◆ operator T()

template<PropertyValue T>
aria::reactive::Computed< T >::operator T ( ) const
inline

◆ on_changed()

template<PropertyValue T>
aria::Subscription aria::reactive::Computed< T >::on_changed ( std::function< void(const T &)> fn)
nodiscard

◆ bind()

template<PropertyValue T>
aria::Subscription aria::reactive::Computed< T >::bind ( std::function< void(const T &)> fn)
nodiscard

◆ observe()

template<PropertyValue T>
aria::Subscription aria::reactive::Computed< T >::observe ( std::function< void(const T &, const T &)> fn)
nodiscard

◆ recompute()

template<PropertyValue T>
bool aria::reactive::Computed< T >::recompute ( )
inlineoverridevirtual

Called by the Graph when an upstream has changed.

Re-establishes edges from scratch using a fresh TrackingContext and commits the new value, returning true iff the cached value actually moved.

Exception safety: if the user-supplied compute_() throws, we MUST keep the previous edge set intact — otherwise this Computed becomes orphaned in the graph and never recomputes again, even after the upstream stabilises. We achieve this by computing the new value FIRST under a temporary tracker (without touching our existing edges), and only swapping edges in once the user code has succeeded.

Reimplemented from aria::reactive::Node.

◆ dependency_count()

template<PropertyValue T>
std::size_t aria::reactive::Computed< T >::dependency_count ( ) const
inlinenodiscardnoexcept

Number of upstreams currently in use.

Exposed for diagnostics / tests; not part of the user-facing API surface.


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