Skip to content

Commit

Permalink
Add conditional functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
tmadden committed Sep 4, 2020
1 parent a38f2f5 commit 9d8305d
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 13 deletions.
88 changes: 88 additions & 0 deletions src/alia/flow/conditionals.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#ifndef ALIA_FLOW_CONDITIONALS_HPP
#define ALIA_FLOW_CONDITIONALS_HPP

#include <alia/flow/macros.hpp>
#include <type_traits>

namespace alia {

template<class Context, class ComponentCallback>
std::enable_if_t<is_invocable<ComponentCallback>::value>
invoke_component_callback(Context, ComponentCallback&& callback)
{
callback();
}

template<class Context, class ComponentCallback>
std::enable_if_t<is_invocable<ComponentCallback, Context>::value>
invoke_component_callback(Context ctx, ComponentCallback&& callback)
{
callback(ctx);
}

namespace detail {

template<class Context>
struct if_stub
{
template<class Condition, class Body>
if_stub
else_if_(Condition condition, Body&& body);

template<class Body>
void
else_(Body&& body);

Context ctx_;
bool else_condition_;
};

template<class Context, class Condition, class Body>
if_stub<Context>
if_(Context ctx, bool inherited_condition, Condition condition, Body&& body)
{
bool else_condition;

ALIA_IF(inherited_condition && condition)
{
invoke_component_callback(ctx, body);
}
// Hacking the macros...
// clang-format off
}
else_condition = inherited_condition && _alia_else_condition;
{
// clang-format on
ALIA_END

return if_stub<Context>{ctx, else_condition};
}

template<class Context>
template<class Condition, class Body>
if_stub<Context>
if_stub<Context>::else_if_(Condition condition, Body&& body)
{
return if_(this->ctx_, this->else_condition_, condition, body);
}

template<class Context>
template<class Body>
void
if_stub<Context>::else_(Body&& body)
{
if_(this->ctx_, this->else_condition_, true, body);
}

} // namespace detail

template<class Context, class Condition, class Body>
detail::if_stub<Context>
if_(Context ctx, Condition condition, Body&& body)
{
return detail::if_(ctx, true, condition, body);
}

} // namespace alia

#endif
25 changes: 12 additions & 13 deletions src/alia/signals/operators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,8 @@ operator&&(A const& a, B const& b)
// conditional(b, t, f), where :b, :t and :f are all signals, yields :t
// if :b's value is true and :f if :b's value is false.
//
// :t and :f must have the same value type, and :b's value type must be testable
// in a boolean context.
// :t and :f must have the same value type, and :b's value type must be
// testable in a boolean context.
//
// Note that this is a normal function call, so, unlike an if statement or the
// ternary operator, both :t and :f are fully evaluated. However, they are only
Expand Down Expand Up @@ -501,9 +501,9 @@ struct has_value_type<T, void_t<typename T::value_type>> : std::true_type
{
};

// has_mapped_type<T>::value yields a compile-time boolean indicating whether or
// not T has a mapped_type member (which is the case for standard associative
// containers, or at least the ones that aren't sets).
// has_mapped_type<T>::value yields a compile-time boolean indicating whether
// or not T has a mapped_type member (which is the case for standard
// associative containers, or at least the ones that aren't sets).
template<class T, class = void_t<>>
struct has_mapped_type : std::false_type
{
Expand All @@ -514,8 +514,8 @@ struct has_mapped_type<T, void_t<typename T::mapped_type>> : std::true_type
};

// subscript_result_type<Container, Index>::type gives the expected type of the
// value that results from invoking the subscript operator on a Container. (This
// is necessary to deal with containers that return proxies.)
// value that results from invoking the subscript operator on a Container.
// (This is necessary to deal with containers that return proxies.)
//
// The logic is as follows:
// 1 - If the container has a mapped_type field, use that.
Expand Down Expand Up @@ -557,8 +557,8 @@ struct subscript_result_type<
};

// has_at_indexer<Container, Index>::value yields a compile-time boolean
// indicating whether or not Container has an 'at' member function that takes an
// Index.
// indicating whether or not Container has an 'at' member function that takes
// an Index.
template<class Container, class Index, class = void_t<>>
struct has_at_indexer : std::false_type
{
Expand Down Expand Up @@ -595,8 +595,8 @@ invoke_const_subscript(
}

// const_subscript_returns_reference<Container,Index>::value yields a
// compile-time boolean indicating whether or not invoke_const_subscript returns
// by reference (vs by value).
// compile-time boolean indicating whether or not invoke_const_subscript
// returns by reference (vs by value).
template<class Container, class Index>
struct const_subscript_returns_reference
: std::is_reference<decltype(invoke_const_subscript(
Expand Down Expand Up @@ -723,8 +723,7 @@ make_subscript_signal(ContainerSignal container, IndexSignal index)

template<class Derived, class Value, class Capabilities>
template<class Index>
auto
signal_base<Derived, Value, Capabilities>::operator[](Index index) const
auto signal_base<Derived, Value, Capabilities>::operator[](Index index) const
{
return make_subscript_signal(
static_cast<Derived const&>(*this), signalize(std::move(index)));
Expand Down
51 changes: 51 additions & 0 deletions unit_tests/flow/conditionals.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include <alia/flow/conditionals.hpp>

#include <alia/signals/basic.hpp>
#include <alia/signals/operators.hpp>

#include <flow/testing.hpp>

using namespace alia;

TEST_CASE("conditional functions", "[flow][macros]")
{
clear_log();
{
data_graph graph;
auto make_controller = [](auto n) {
return [&](context ctx) {
if_(ctx, n < 0, [&]() {
do_int(ctx, -1);
}).else_if_(n == 0, [&] {
do_int(ctx, 0);
}).else_([&] { do_int(ctx, 1); });

if_(ctx, n != 17, [](auto ctx) { do_int(ctx, 2); });
};
};

do_traversal(graph, make_controller(value(-4)));
check_log(
"initializing int: -1;"
"initializing int: 2;");
do_traversal(graph, make_controller(value(1)));
check_log(
"initializing int: 1;"
"visiting int: 2;");
do_traversal(graph, make_controller(value(0)));
check_log(
"initializing int: 0;"
"visiting int: 2;");
do_traversal(graph, make_controller(value(1)));
check_log(
"visiting int: 1;"
"visiting int: 2;");
do_traversal(graph, make_controller(empty<int>()));
check_log("");
}
check_log(
"destructing int;"
"destructing int;"
"destructing int;"
"destructing int;");
}

0 comments on commit 9d8305d

Please sign in to comment.