In the Design section we say how a transducer may extend the state from the reducing function. Not only does this allow it to include feedback in the process, but also to signal to process whether the computation has terminated.
This section describes the abstract interface that comunicates between the state and the reducing process, and also the concrete state wrapping utilities provided for transducer implementors.
state_traits_t = state_traits<std::decay_t<T>>
decltype(auto) zug::state_complete(T && s)
Convenience function for calling state_traits::complete
zug::
state_is_reduced
(T &&s)¶Convenience function for calling state_traits::is_reduced
decltype(auto) zug::state_data(T && s, D && d)
Convenience function for calling state_traits::data
decltype(auto) zug::state_unwrap(T && s)
Convenience function for calling state_traits::unwrap
decltype(auto) zug::state_unwrap_all(T && s)
Convenience function for calling state_traits::unwrap_all
decltype(auto) zug::state_rewrap(T && s, U && x)
Convenience function for calling state_traits::unwrap_all
zug::
state_traits
¶Interface for a type specializing the State
concept.
A State
is the first parameter of a reducing function, also known as the accumulator. Every type is a model of State
, with the following default implementation. However, one might want to specialize the state it for a particular accumulator type, such that transducers can operate with it. A transducer should not make assumptions about the state it receives, instead, it can only wrap it using wrap_state
to attach additional data.
For an example of a stateful reducing function, see take
.
zug::
wrap_state
(StateT &&next, DataT &&data = DataT{})¶Given a tag TagT
and a state next
and associated data
, returns a state_wrapper
instance.
decltype(auto) zug::state_wrapper_unwrap(TagT, T && s)
Utility function for easy overloading of state_traits::unwrap
for state wrappers with a specific tag.
decltype(auto) zug::state_wrapper_complete(TagT, T && s)
Utility function for easy overloading of state_traits::complete
for state wrappers with a specific tag.
decltype(auto) zug::state_wrapper_unwrap_all(TagT, T && s)
Utility function for easy overloading of state_traits::unwrap_all
for state wrappers with a specific tag.
decltype(auto) zug::state_wrapper_rewrap(TagT, T && s, U && x)
Utility function for easy overloading of state_traits::rewrap
for state wrappers with a specific tag.
decltype(auto) zug::state_wrapper_data(TagT tag, T && s, D &&)
Utility function for easy overloading of state_traits::data
for state wrappers with a specific tag.
decltype(auto) zug::state_wrapper_data(T && s)
decltype(auto) zug::state_wrapper_data(TagT, T && s)
zug::
state_wrapper_data_is_reduced
(TagT, DataT&&)¶Utility function that returns whether the DataT
associated with a state wrapper with tag TagT
is reduced i.e. idempotent. Can be overloaded custom tags.
zug::
state_wrapper_is_reduced
(TagT tag, T &&s)¶Utility function for easy overloading of state_traits::is_reduced
for state wrappers with a specific tag. Most of the time you may want to overload state_wrapper_is_reduced
instead.
zug::
no_tag
¶Default tag for state_wrapper
.
zug::
state_wrapper
¶A decorator for the accumulator of a reduction.
A transducer must not make any assumptions about the accumulator of the process it is helping to reduce. However, a stateful transducer may use a state_wrapper
to attach extra data to the accumulator such that the reducing function object itself can be state-less.
A state wrapper has the following template arguments:
For an example of a stateful reducing function, see take.
TagT
: is as tag type used to identify the transducer that is attaching the state. This can useful to specialize the state_traits
for a concrete state wrapper.StateT
: is the accumulator that is to be wrapped and of which we shall make no assumptions.DataT
: is the additional data that the transducer wants to attach to represent its own state.zug::
is_state_wrapper
¶Metafunction returning whether StateT
is a, or reference to, a state_wrapper
instantiation.
zug::
is_state_wrapper
<_, state_wrapper<T, S, D>>¶zug::
state_traits
<state_wrapper<TagT, StateT, DataT>>¶State traits specialization for state_wrapper
. Just forwards to the state_wrapper_*
methods, that are easier to specialize for a given tag.
zug::
with_state
(StateT &&st, UnwrappedFn &&fn, WrappedFn &&fn)¶Given a value st
that represents the state of a reduction, this function generically dispatches to the right function UnwrappedFn
or WrappedFn
, depending of whether the value is already wrapped or not. This is, during the first iteration of the reduction, UnwrappedFn
will be called, from then on, WrappedFnT
will be called.
The signatures should be of the form:
UnwrappedFn : A -> B
WrappedFn : B -> B
This function can dispatch both statically and dynamically in a transparent way. It is thus very useful for writing stateful transducers that can be type erased in a transducer<>
object.
maybe_reduced = state_wrapper<maybe_reduced_tag, T, bool>
State wrapper for transducers that may want to signal that the reduction is finished.
zug::
state_wrapper_data_is_reduced
(maybe_reduced_tag, bool is_reduced)¶zug::
reduced_if
(T &&x, bool is_reduced)¶Wraps x
in a maybe_reduced
, where is_reduced
contains whether the reduction should actually finish.
decltype(auto) zug::reduced(T && x)
Wraps x
such that the reduction should finish.
decltype(auto) zug::not_reduced(T && x)
Wraps x
such that the reduction should continue.
zug::
maybe_reduced_tag
¶Tag for maybe_reduced
state wrapper.
skip_result_t = typename skip_result<ReducingFnT, StateT, InputTs...>::type
zug::
skip
(ReducingFnT&&, StateT &&state, InputTs&&...)¶Skip calling the next reducing function in a transducer. Returns the state
parameter, potentially wrapped in a value convertible to/from whatever call
would return for similar parameters.
A transducer might or might not call the next reducing function in the chain. One good example is filter
, where if the predicate passes, it calls the next reducing function, otherwise it just returns the current state of the reduction. However, this poses the question: what should be the return type of such a transducer? The next reducing function might wrap the state in a state_wrapper
to attach its own state to it. However, we don’t know at this point what how to create such a wrapped value. This method, and call
, take care of wrapping the state in a type that can hold values of both the current state, and the state that would be returned by the next reducing function. The metafunction skip_result
defines such a type.
zug::
skip
(StateT &&state)¶zug::
call
(ReducingFnT &&step, StateT &&state, InputTs&&... ins)¶Call the next reducing function in a transducer that could otherwise skip calling the next reducing function. Returns the result of calling step(state, ins...)
wrapped in a type that can also hold plain state
values. If state
is wrapped in such a type, it unwraps it before passing it.
zug::
skip_state
¶Type-safe union type that can hold values of both SkippedT
and CalledT
types.
zug::
is_skip_state
¶zug::
is_skip_state
<skip_state<SkippedT, CalledT>>¶zug::
skip_result
¶Metafunction that returns a type that can hold both values of type skipped_t = StateT
and wrapped_t = declval<ReducingFnT>(declval<StateT>(), declval<InputTs>()...)
The result is:
std::common_type<skipped_t, wrapped_t>
exists between the two types, it returns this type. For example, if one of these is a any_state
because is used in a type erased transducer, any_state
will be the result.skip_state<skipped_t, wrapped_t>
, which is essentially a type-safe union of these two types. zug::
any_state
¶Polymorphically holds any value implementing the state_traits
. This type is used for the implementation of transducer
.