Skip to content

Commit

Permalink
Fix a C++17 reliance and improve test coverage.
Browse files Browse the repository at this point in the history
  • Loading branch information
tmadden committed Aug 8, 2018
1 parent 024343c commit 35d5909
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 45 deletions.
9 changes: 9 additions & 0 deletions src/alia/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@ combine_hashes(size_t a, size_t b)
#define ALIA_UNUSED
#endif

// implementation of C++17's void_t that works on C++11 compilers
template<typename... Ts>
struct make_void
{
typedef void type;
};
template<typename... Ts>
using void_t = typename make_void<Ts...>::type;

} // namespace alia

#endif
24 changes: 24 additions & 0 deletions src/alia/id.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,30 @@ struct captured_id
{
this->capture(id);
}
captured_id(captured_id const& other)
{
if (other.is_initialized())
this->capture(other.get());
}
captured_id(captured_id&& other)
{
id_ = std::move(other.id_);
}
captured_id&
operator=(captured_id const& other)
{
if (other.is_initialized())
this->capture(other.get());
else
this->clear();
return *this;
}
captured_id&
operator=(captured_id&& other)
{
id_ = std::move(other.id_);
return *this;
}
void
clear()
{
Expand Down
14 changes: 1 addition & 13 deletions src/alia/signals/application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ enum class apply_status
template<class Value>
struct apply_result_data
{
int result_version;
int result_version = 0;
Value result;
apply_status status = apply_status::UNCOMPUTED;
};
Expand All @@ -137,9 +137,6 @@ reset(apply_result_data<Value>& data)
template<class Value>
struct apply_signal : signal<apply_signal<Value>, Value, read_only_signal>
{
apply_signal()
{
}
apply_signal(apply_result_data<Value>& data) : data_(&data)
{
}
Expand All @@ -159,15 +156,6 @@ struct apply_signal : signal<apply_signal<Value>, Value, read_only_signal>
{
return data_->result;
}
bool
is_writable() const
{
return false;
}
void
write(Value const& value) const
{
}

private:
apply_result_data<Value>* data_;
Expand Down
17 changes: 8 additions & 9 deletions src/alia/signals/operators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,24 +298,24 @@ operator->*(

// has_value_type<T>::value yields a compile-time boolean indicating whether or
// not T has a value_type member (which is the case for standard containers).
template<class T, class = std::void_t<>>
template<class T, class = void_t<>>
struct has_value_type : std::false_type
{
};
template<class T>
struct has_value_type<T, std::void_t<typename T::value_type>> : std::true_type
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).
template<class T, class = std::void_t<>>
template<class T, class = void_t<>>
struct has_mapped_type : std::false_type
{
};
template<class T>
struct has_mapped_type<T, std::void_t<typename T::mapped_type>> : std::true_type
struct has_mapped_type<T, void_t<typename T::mapped_type>> : std::true_type
{
};

Expand Down Expand Up @@ -364,32 +364,31 @@ struct subscript_result_type<

// has_at_indexer<Container, Index>::value yields a compile-time boolean
// indicating whether or not Container has an 'at' method that takes an Index.
template<class Container, class Index, class = std::void_t<>>
template<class Container, class Index, class = void_t<>>
struct has_at_indexer : std::false_type
{
};
template<class Container, class Index>
struct has_at_indexer<
Container,
Index,
std::void_t<decltype(std::declval<Container const&>().at(
void_t<decltype(std::declval<Container const&>().at(
std::declval<Index>()))>> : std::true_type
{
};

// has_const_subscript<Container, Index>::value yields a compile-time boolean
// indicating whether or not Container has a const subscript operator that takes
// an Index.
template<class Container, class Index, class = std::void_t<>>
template<class Container, class Index, class = void_t<>>
struct has_const_subscript : std::false_type
{
};
template<class Container, class Index>
struct has_const_subscript<
Container,
Index,
std::void_t<decltype(
std::declval<Container const&>()[std::declval<Index>()])>>
void_t<decltype(std::declval<Container const&>()[std::declval<Index>()])>>
: std::true_type
{
};
Expand Down
73 changes: 72 additions & 1 deletion unit_tests/id.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ TEST_CASE("id_ref", "[id]")
test_different_ids(ref(make_id(0)), ref(make_id(1)));
}

TEST_CASE("captured_id", "[id]")
TEST_CASE("captured_id basics", "[id]")
{
captured_id c;
REQUIRE(!c.is_initialized());
Expand All @@ -85,6 +85,11 @@ TEST_CASE("captured_id", "[id]")
REQUIRE(c.get() == make_id(0));
c.clear();
REQUIRE(!c.is_initialized());
}

TEST_CASE("captured_id operators", "[id]")
{
captured_id c;
c.capture(make_id(0));
captured_id d;
REQUIRE(c != d);
Expand All @@ -96,6 +101,72 @@ TEST_CASE("captured_id", "[id]")
REQUIRE(boost::lexical_cast<std::string>(c) == "0");
}

TEST_CASE("captured_id copy construction", "[id]")
{
captured_id c;
c.capture(make_id(0));
captured_id d = c;
REQUIRE(d == c);
// Check that d is independent of changes in c.
c.capture(make_id(1));
REQUIRE(d != c);

c.clear();
captured_id e = c;
REQUIRE(e == c);
// Check that e is independent of changes in c.
c.capture(make_id(1));
REQUIRE(e != c);
}

TEST_CASE("captured_id move construction", "[id]")
{
captured_id c;
c.capture(make_id(0));
captured_id d = std::move(c);
REQUIRE(d.matches(make_id(0)));

captured_id e;
e.clear();
captured_id f = std::move(e);
REQUIRE(!f.is_initialized());
}

TEST_CASE("captured_id copy assignment", "[id]")
{
captured_id c;
c.capture(make_id(0));
captured_id d;
d = c;
REQUIRE(d == c);
// Check that d is independent of changes in c.
c.capture(make_id(1));
REQUIRE(d != c);

c.clear();
captured_id e;
e = c;
REQUIRE(e == c);
// Check that e is independent of changes in c.
c.capture(make_id(1));
REQUIRE(e != c);
}

TEST_CASE("captured_id move assignment", "[id]")
{
captured_id c;
c.capture(make_id(0));
captured_id d;
d = std::move(c);
REQUIRE(d.matches(make_id(0)));

captured_id e;
e.clear();
captured_id f;
f = std::move(e);
REQUIRE(!f.is_initialized());
}

TEST_CASE("combine_ids x1", "[id]")
{
auto a = combine_ids(make_id(0));
Expand Down
54 changes: 32 additions & 22 deletions unit_tests/signals/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,36 +78,46 @@ TEST_CASE("simple apply", "[signals]")
return x * 2 + y;
};

{
data_graph graph;
auto make_controller = [=](int x, int y) {
return [=](context ctx) {
auto s = apply(ctx, f, value(x), value(y));
captured_id signal_id;

typedef decltype(s) signal_t;
REQUIRE(signal_can_read<signal_t>::value);
REQUIRE(!signal_can_write<signal_t>::value);
data_graph graph;
auto make_controller = [&](int x, int y) {
return [=, &signal_id](context ctx) {
auto s = apply(ctx, f, value(x), value(y));

REQUIRE(signal_is_readable(s));
REQUIRE(read_signal(s) == x * 2 + y);
};
typedef decltype(s) signal_t;
REQUIRE(signal_can_read<signal_t>::value);
REQUIRE(!signal_can_write<signal_t>::value);

REQUIRE(signal_is_readable(s));
REQUIRE(read_signal(s) == x * 2 + y);

signal_id.capture(s.value_id());
};
};

do_traversal(graph, make_controller(1, 2));
REQUIRE(f_call_count == 1);
do_traversal(graph, make_controller(1, 2));
REQUIRE(f_call_count == 1);
captured_id last_id = signal_id;

do_traversal(graph, make_controller(1, 2));
REQUIRE(f_call_count == 1);
do_traversal(graph, make_controller(1, 2));
REQUIRE(f_call_count == 1);
REQUIRE(last_id == signal_id);
last_id = signal_id;

do_traversal(graph, make_controller(2, 2));
REQUIRE(f_call_count == 2);
do_traversal(graph, make_controller(2, 2));
REQUIRE(f_call_count == 2);
REQUIRE(last_id != signal_id);
last_id = signal_id;

do_traversal(graph, make_controller(2, 2));
REQUIRE(f_call_count == 2);
do_traversal(graph, make_controller(2, 2));
REQUIRE(f_call_count == 2);
REQUIRE(last_id == signal_id);
last_id = signal_id;

do_traversal(graph, make_controller(2, 3));
REQUIRE(f_call_count == 3);
}
do_traversal(graph, make_controller(2, 3));
REQUIRE(f_call_count == 3);
REQUIRE(last_id != signal_id);
}

TEST_CASE("unready apply", "[signals]")
Expand Down

0 comments on commit 35d5909

Please sign in to comment.