callonce  1.0.0
Header-only memoized call-once wrapper for any C++ callable
fedem::utility::memoized_invoke< ExecutionPolicy, F, Args > Class Template Reference

Wraps a callable + argument set, runs it at most once, caches the result. More...

#include <memoized_invoke.hh>

+ Collaboration diagram for fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >:

Classes

struct  execution_guard
 

Public Types

using result_type = std::invoke_result_t< F, Args... >
 The callable's return type: std::invoke_result_t<F, Args...>. May be void. More...
 

Public Member Functions

 memoized_invoke (F func) requires(sizeof...(Args)
 Construct from a callable that takes no arguments. More...
 
memoized_invokeoperator= (memoized_invoke const &other) requires std
 Copy assignment. Self-assignment safe. More...
 
result_type operator() ()
 Invoke with the stored arguments, or return the cached result. More...
 
result_type operator() (std::decay_t< Args >... args) requires(sizeof...(Args) > 0)
 Invoke with a fresh argument set, re-executing if it changed. More...
 
void reset () noexcept
 Drop the cached result and return to the not-started state. More...
 
void reset (std::decay_t< Args >... args) requires(sizeof...(Args) > 0)
 Drop the cached result, replace the stored arguments, and reset. More...
 
bool is_done () const noexcept
 
auto const & value () const requires(! std
 Access the cached result without invoking the callable. More...
 

Private Types

using args_tuple = std::tuple< std::decay_t< Args >... >
 

Private Member Functions

void do_invoke ()
 
void check_and_call ()
 

Private Attributes

callable_
 
ExecutionPolicy policy_
 
detail::return_storage< result_typestorage_
 
args_tuple args_
 

Detailed Description

template<typename ExecutionPolicy, typename F, typename... Args>
class fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >

Wraps a callable + argument set, runs it at most once, caches the result.

Template Parameters
ExecutionPolicySynchronisation policy — single_threaded or lock_free, or any type meeting the same interface (try_enter, mark_done, mark_free, is_done, wait).
FThe callable type. Any type for which std::is_invocable_v<F, Args...> holds: free / member function pointers (including noexcept), lambdas (stateless, capturing, mutable), functors with const or non-const operator(), std::function, and std::bind_front results.
ArgsThe argument types F is invoked with. For a member function pointer, the object (pointer or reference) is the first entry. Stored by value as std::decay_t<Args>....

Construct with the callable and its arguments, then call operator(): the first call runs std::apply(f, args) and caches what it returns; every later call returns the cached value. operator()(new_args...) compares the new arguments with the stored ones (as tuples, via operator!=) and re-executes when they differ.

If the callable throws, an internal RAII guard rolls the policy state back to not-started, the cache stays empty, and the next call retries — the same contract as std::call_once.

CTAD deduces every parameter and selects single_threaded. For a different policy, go through make_memoized.

fedem::utility::memoized_invoke mi( &expensive, 21 ); // single_threaded
fedem::utility::lock_free >( &expensive, 21 );
Thread-safe, lock-free execution policy.
Definition: memoized_invoke.hh:204
Wraps a callable + argument set, runs it at most once, caches the result.
Definition: memoized_invoke.hh:332
requires std::is_invocable_v< F, Args... > auto make_memoized(F &&func, Args &&... args)
Build a memoized_invoke with an explicit execution policy.
Definition: memoized_invoke.hh:657
See also
make_memoized
single_threaded
lock_free

Member Typedef Documentation

◆ result_type

template<typename ExecutionPolicy , typename F , typename... Args>
using fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::result_type = std::invoke_result_t< F, Args... >

The callable's return type: std::invoke_result_t<F, Args...>. May be void.

◆ args_tuple

template<typename ExecutionPolicy , typename F , typename... Args>
using fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::args_tuple = std::tuple< std::decay_t< Args >... >
private

Constructor & Destructor Documentation

◆ memoized_invoke()

template<typename ExecutionPolicy , typename F , typename... Args>
fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::memoized_invoke ( func)
explicit

Construct from a callable that takes no arguments.

Parameters
funcThe callable. Moved into the object.
Note
Only participates in overload resolution when sizeof...(Args) == 0.

Member Function Documentation

◆ do_invoke()

template<typename ExecutionPolicy , typename F , typename... Args>
void fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::do_invoke ( )
inlineprivate

References fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::args_, fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::callable_, fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::storage_, and fedem::utility::detail::return_storage< T >::store().

Referenced by fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::check_and_call().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_and_call()

template<typename ExecutionPolicy , typename F , typename... Args>
void fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::check_and_call ( )
inlineprivate

References fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::execution_guard::commit(), fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::do_invoke(), and fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::policy_.

Referenced by fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::operator()().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ operator=()

template<typename ExecutionPolicy , typename F , typename... Args>
memoized_invoke& fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::operator= ( memoized_invoke< ExecutionPolicy, F, Args > const &  other)
inline

Copy assignment. Self-assignment safe.

Note
Requires std::is_copy_assignable_v<F>.

Move assignment. Self-assignment safe.

Note
noexcept when both F and the argument tuple move without throwing.

References fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::args_, fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::callable_, fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::policy_, and fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::storage_.

◆ operator()() [1/2]

template<typename ExecutionPolicy , typename F , typename... Args>
result_type fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::operator() ( )
inline

Invoke with the stored arguments, or return the cached result.

If is_done is false, runs std::apply(f, args), caches the result and transitions to done. If the callable throws, the exception propagates and the state stays not-started so a later call retries. If is_done is true, returns the cached result without running anything.

Returns
The cached result (a copy of it), or nothing for a void callable.

References fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::check_and_call(), fedem::utility::detail::return_storage< T >::get(), and fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::storage_.

+ Here is the call graph for this function:

◆ operator()() [2/2]

template<typename ExecutionPolicy , typename F , typename... Args>
result_type fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::operator() ( std::decay_t< Args >...  args)
inline

Invoke with a fresh argument set, re-executing if it changed.

The new arguments are compared with the stored ones as tuples via operator!=. If they differ, the stored arguments are replaced, the cache is cleared, the state is reset and the callable runs again. If they are equal, this behaves exactly like operator()().

Parameters
argsThe new argument set.
Returns
The (possibly recomputed) cached result, or nothing for void.
Note
Only available when sizeof...(Args) > 0. Requires the argument types to be equality-comparable. Not thread-safe even under lock_free.

References fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::args_, fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::check_and_call(), fedem::utility::detail::return_storage< T >::clear(), fedem::utility::detail::return_storage< T >::get(), fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::policy_, and fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::storage_.

+ Here is the call graph for this function:

◆ reset() [1/2]

template<typename ExecutionPolicy , typename F , typename... Args>
void fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::reset ( )
inlinenoexcept

Drop the cached result and return to the not-started state.

The stored arguments are kept; the next call re-runs the callable with them. Not thread-safe.

References fedem::utility::detail::return_storage< T >::clear(), fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::policy_, and fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::storage_.

+ Here is the call graph for this function:

◆ reset() [2/2]

template<typename ExecutionPolicy , typename F , typename... Args>
void fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::reset ( std::decay_t< Args >...  args)
inline

Drop the cached result, replace the stored arguments, and reset.

Parameters
argsThe new argument set the next call will use.
Note
Only available when sizeof...(Args) > 0. Not thread-safe.

References fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::args_, fedem::utility::detail::return_storage< T >::clear(), fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::policy_, and fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::storage_.

+ Here is the call graph for this function:

◆ is_done()

template<typename ExecutionPolicy , typename F , typename... Args>
bool fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::is_done ( ) const
inlinenoexcept
Returns
true once the callable has completed and a value is cached.

References fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::policy_.

◆ value()

template<typename ExecutionPolicy , typename F , typename... Args>
auto const& fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::value ( ) const
inline

Access the cached result without invoking the callable.

Returns
A const reference to the cached value.
Precondition
is_done must be true; otherwise the behaviour is undefined (the shipped implementation throws std::bad_optional_access).
Note
Only available for a non-void result_type.

References fedem::utility::detail::return_storage< T >::get(), and fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::storage_.

+ Here is the call graph for this function:

Member Data Documentation

◆ callable_

template<typename ExecutionPolicy , typename F , typename... Args>
F fedem::utility::memoized_invoke< ExecutionPolicy, F, Args >::callable_
private

◆ policy_

◆ storage_

◆ args_


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