Skip to content

Commit

Permalink
Improve content ID mechanics.
Browse files Browse the repository at this point in the history
  • Loading branch information
tmadden committed Oct 1, 2020
1 parent 4002f56 commit a308e39
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 86 deletions.
42 changes: 17 additions & 25 deletions src/alia/context/interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ make_context(
timing_subsystem& timing)
{
storage->content_id = &unit_id;
return extend_context<data_traversal_tag>(
extend_context<timing_tag>(
extend_context<event_traversal_tag>(
extend_context<system_tag>(
return detail::add_context_object<data_traversal_tag>(
detail::add_context_object<timing_tag>(
detail::add_context_object<event_traversal_tag>(
detail::add_context_object<system_tag>(
make_context(
detail::make_empty_structural_collection(storage)),
sys),
Expand All @@ -27,45 +27,37 @@ make_context(
data);
}

struct scoped_context_content_id_data
namespace detail {

struct context_content_id_folding_data
{
captured_id id_from_above;
captured_id id_from_here;
unsigned id_to_present = 0;
simple_id<unsigned> id_to_present = {0};
};

void
scoped_context_content_id::begin(context ctx, id_interface const& id)
fold_in_content_id(context ctx, id_interface const& id)
{
ctx_.reset(ctx);
parent_id_ = ctx.contents_.storage->content_id;
id_interface const* id_from_above = ctx.contents_.storage->content_id;

auto& data = get_cached_data<scoped_context_content_id_data>(ctx);
auto& data = get_cached_data<context_content_id_folding_data>(ctx);

if (!data.id_from_above.matches(*parent_id_))
if (!data.id_from_above.matches(*id_from_above))
{
++data.id_to_present;
data.id_from_above.capture(*parent_id_);
++data.id_to_present.value_;
data.id_from_above.capture(*id_from_above);
}

if (!data.id_from_here.matches(id))
{
++data.id_to_present;
++data.id_to_present.value_;
data.id_from_here.capture(id);
}

this_id_ = make_id(data.id_to_present);
ctx.contents_.storage->content_id = &this_id_;
ctx.contents_.storage->content_id = &data.id_to_present;
}

void
scoped_context_content_id::end()
{
if (ctx_)
{
ctx_->contents_.storage->content_id = parent_id_;
ctx_.reset();
}
}
} // namespace detail

} // namespace alia
119 changes: 78 additions & 41 deletions src/alia/context/interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,24 +92,24 @@ struct context_interface

// manipulation of context objects...

template<class Tag, class Contents, class Data>
auto
extend_context(context_interface<Contents> ctx, Data& data)
namespace detail {

template<class Contents>
auto&
get_storage_object(context_interface<Contents> ctx)
{
auto new_contents
= detail::add_tagged_data<Tag>(ctx.contents_, std::ref(data));
return context_interface<decltype(new_contents)>(std::move(new_contents));
return *ctx.contents_.storage;
}

template<class Tag, class Contents>
decltype(auto)
get(context_interface<Contents> ctx)
template<class Tag, class Contents, class Object>
auto
add_context_object(context_interface<Contents> ctx, Object& object)
{
return detail::get_tagged_data<Tag>(ctx.contents_);
auto new_contents
= detail::add_tagged_data<Tag>(ctx.contents_, std::ref(object));
return context_interface<decltype(new_contents)>(std::move(new_contents));
}

namespace detail {

template<class Tag, class Contents>
bool
has_context_object(context_interface<Contents> ctx)
Expand Down Expand Up @@ -171,7 +171,7 @@ typedef context_interface<detail::add_tagged_data_types_t<

typedef extend_context_type_t<dataless_context, data_traversal_tag> context;

// And some convenience functions...
// And various small functions for working with contexts...

template<class Contents>
auto
Expand Down Expand Up @@ -200,6 +200,71 @@ copy_context(Context ctx)
return Context(typename Context::contents_type(new_storage));
}

namespace detail {

template<class Object, class = void_t<>>
struct has_value_id : std::false_type
{
};
template<class Object>
struct has_value_id<
Object,
void_t<decltype(static_cast<id_interface const&>(
std::declval<Object>().value_id()))>> : std::true_type
{
};

void
fold_in_content_id(context ctx, id_interface const& id);

template<class Object>
std::enable_if_t<has_value_id<Object>::value>
fold_in_object_id(context ctx, Object const& object)
{
fold_in_content_id(ctx, object.value_id());
}

template<class Object>
std::enable_if_t<!has_value_id<Object>::value>
fold_in_object_id(context, Object const&)
{
}

} // namespace detail

template<class Tag, class Contents, class Object>
auto
extend_context(context_interface<Contents> ctx, Object& object)
{
auto extended_ctx
= detail::add_context_object<Tag>(copy_context(ctx), object);
fold_in_object_id(extended_ctx, object);
return extended_ctx;
}

template<class Tag, class Contents>
decltype(auto)
get(context_interface<Contents> ctx)
{
return detail::get_tagged_data<Tag>(ctx.contents_);
}

template<class Contents>
void
recalculate_content_id(context_interface<Contents> ctx)
{
get_storage_object(ctx).content_id = &unit_id;
alia::fold_over_collection(
ctx.contents_,
[](auto, auto& object, auto ctx) {
fold_in_object_id(ctx, object);
return ctx;
},
ctx);
}

// convenience accessors...

template<class Context>
event_traversal&
get_event_traversal(Context ctx)
Expand Down Expand Up @@ -282,34 +347,6 @@ struct optional_context
Context ctx_;
};

// scoped_context_content_id is used to fold another ID into the overall ID for
// a context's content.
struct scoped_context_content_id
{
scoped_context_content_id()
{
}
scoped_context_content_id(context ctx, id_interface const& id)
{
begin(ctx, id);
}
~scoped_context_content_id()
{
end();
}

void
begin(context ctx, id_interface const& id);

void
end();

private:
optional_context<dataless_context> ctx_;
simple_id<unsigned> this_id_;
id_interface const* parent_id_;
};

} // namespace alia

#endif
37 changes: 28 additions & 9 deletions unit_tests/context/interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ TEST_CASE("context", "[context][interface]")

other_traversal other;
extend_context_type_t<context, other_traversal_tag> extended
= extend_context<other_traversal_tag>(copy_context(ctx), other);
= detail::add_context_object<other_traversal_tag>(
copy_context(ctx), other);
REQUIRE(detail::has_context_object<data_traversal_tag>(extended));
REQUIRE(&get<data_traversal_tag>(extended) == &data);
REQUIRE(detail::has_context_object<event_traversal_tag>(extended));
Expand Down Expand Up @@ -106,35 +107,53 @@ TEST_CASE("optional_context", "[context][interface]")
REQUIRE(!optional);
}

TEST_CASE("make_context", "[context][interface]")
TEST_CASE("content IDs", "[context][interface]")
{
alia::system sys;
initialize_system(sys, [](context) {});

captured_id outer_id, inner_id;
captured_id outer_id, inner_id, downcast_id, recalculated_id;

ALIA_DEFINE_TAGGED_TYPE(outer_tag, value_signal<int>&)
ALIA_DEFINE_TAGGED_TYPE(inner_tag, value_signal<int>&)

auto make_controller = [&](int outer, int inner) {
return [&, outer, inner](context ctx) {
REQUIRE(get_content_id(ctx) == unit_id);
scoped_context_content_id outer_content(ctx, make_id(outer));
outer_id.capture(get_content_id(ctx));
return [&, outer, inner](context root_ctx) {
REQUIRE(get_content_id(root_ctx) == unit_id);
auto outer_signal = value(outer);
auto outer_ctx = extend_context<outer_tag>(root_ctx, outer_signal);
outer_id.capture(get_content_id(outer_ctx));
{
scoped_context_content_id inner_content(ctx, make_id(inner));
inner_id.capture(get_content_id(ctx));
auto inner_signal = value(inner);
auto inner_ctx
= extend_context<inner_tag>(outer_ctx, inner_signal);
inner_id.capture(get_content_id(inner_ctx));
{
decltype(outer_ctx) downcast_ctx = inner_ctx;
downcast_id.capture(get_content_id(downcast_ctx));
recalculate_content_id(downcast_ctx);
recalculated_id.capture(get_content_id(downcast_ctx));
}
}
};
};

do_traversal(sys, make_controller(4, 1));
REQUIRE(downcast_id == inner_id);
REQUIRE(recalculated_id == outer_id);
captured_id last_outer = outer_id;
captured_id last_inner = inner_id;

do_traversal(sys, make_controller(4, 2));
REQUIRE(downcast_id == inner_id);
REQUIRE(recalculated_id == outer_id);
REQUIRE(last_outer == outer_id);
REQUIRE(last_inner != inner_id);
last_inner = inner_id;

do_traversal(sys, make_controller(4, 2));
REQUIRE(downcast_id == inner_id);
REQUIRE(recalculated_id == outer_id);
REQUIRE(last_outer == outer_id);
REQUIRE(last_inner == inner_id);

Expand Down
7 changes: 3 additions & 4 deletions unit_tests/flow/events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ do_my_thing(my_context ctx, readable<string> label)
{
auto id = get_component_id(ctx);

on_refresh(ctx, [id](auto ctx) {
get<my_tag>(ctx).push_back(externalize(id));
});
on_refresh(
ctx, [id](auto ctx) { get<my_tag>(ctx).push_back(externalize(id)); });

on_event<my_event>(
ctx, [&](auto, auto& e) { e.visited += read_signal(label) + ";"; });
Expand All @@ -54,7 +53,7 @@ TEST_CASE("node IDs", "[flow][events]")
std::vector<external_component_id> ids;

sys.controller = [&](context vanilla_ctx) {
my_context ctx = extend_context<my_tag>(vanilla_ctx, ids);
my_context ctx = detail::add_context_object<my_tag>(vanilla_ctx, ids);
do_my_thing(ctx, value("one"));
do_my_thing(ctx, value("two"));
};
Expand Down
15 changes: 10 additions & 5 deletions unit_tests/flow/object_trees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ TEST_CASE("simple object tree", "[flow][object_trees]")
alia::system sys;
initialize_system(sys, [&](context vanilla_ctx) {
tree_traversal<test_object> traversal;
auto ctx = extend_context<tree_traversal_tag>(vanilla_ctx, traversal);
auto ctx = detail::add_context_object<tree_traversal_tag>(
vanilla_ctx, traversal);
if (is_refresh_event(ctx))
{
traverse_object_tree(traversal, root, [&]() { controller(ctx); });
Expand Down Expand Up @@ -160,7 +161,8 @@ TEST_CASE("multilevel object tree", "[flow][object_trees]")
alia::system sys;
initialize_system(sys, [&](context vanilla_ctx) {
tree_traversal<test_object> traversal;
auto ctx = extend_context<tree_traversal_tag>(vanilla_ctx, traversal);
auto ctx = detail::add_context_object<tree_traversal_tag>(
vanilla_ctx, traversal);
if (is_refresh_event(ctx))
{
traverse_object_tree(traversal, root, [&]() { controller(ctx); });
Expand Down Expand Up @@ -239,7 +241,8 @@ TEST_CASE("fluid object tree", "[flow][object_trees]")
alia::system sys;
initialize_system(sys, [&](context vanilla_ctx) {
tree_traversal<test_object> traversal;
auto ctx = extend_context<tree_traversal_tag>(vanilla_ctx, traversal);
auto ctx = detail::add_context_object<tree_traversal_tag>(
vanilla_ctx, traversal);
if (is_refresh_event(ctx))
{
traverse_object_tree(traversal, root, [&]() { controller(ctx); });
Expand Down Expand Up @@ -374,7 +377,8 @@ TEST_CASE("piecewise containers", "[flow][object_trees]")
alia::system sys;
initialize_system(sys, [&](context vanilla_ctx) {
tree_traversal<test_object> traversal;
auto ctx = extend_context<tree_traversal_tag>(vanilla_ctx, traversal);
auto ctx = detail::add_context_object<tree_traversal_tag>(
vanilla_ctx, traversal);
if (is_refresh_event(ctx))
{
traverse_object_tree(traversal, root, [&]() { controller(ctx); });
Expand Down Expand Up @@ -480,7 +484,8 @@ TEST_CASE("object tree caching", "[flow][object_trees]")
alia::system sys;
initialize_system(sys, [&](context vanilla_ctx) {
tree_traversal<test_object> traversal;
auto ctx = extend_context<tree_traversal_tag>(vanilla_ctx, traversal);
auto ctx = detail::add_context_object<tree_traversal_tag>(
vanilla_ctx, traversal);
if (is_refresh_event(ctx))
{
traverse_object_tree(traversal, root, [&]() { controller(ctx); });
Expand Down
3 changes: 2 additions & 1 deletion unit_tests/flow/try_catch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ TEST_CASE("try_catch", "[flow][try_catch]")
alia::system sys;
initialize_system(sys, [&](context vanilla_ctx) {
tree_traversal<test_object> traversal;
auto ctx = extend_context<tree_traversal_tag>(vanilla_ctx, traversal);
auto ctx = detail::add_context_object<tree_traversal_tag>(
vanilla_ctx, traversal);
if (is_refresh_event(ctx))
{
traverse_object_tree(traversal, root, [&]() { controller(ctx); });
Expand Down
3 changes: 2 additions & 1 deletion unit_tests/signals/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ TEST_CASE("failing lazy_apply", "[signals][application]")
alia::system sys;
initialize_system(sys, [&](context vanilla_ctx) {
tree_traversal<test_object> traversal;
auto ctx = extend_context<tree_traversal_tag>(vanilla_ctx, traversal);
auto ctx = detail::add_context_object<tree_traversal_tag>(
vanilla_ctx, traversal);
if (is_refresh_event(ctx))
{
traverse_object_tree(traversal, root, [&]() { controller(ctx); });
Expand Down

0 comments on commit a308e39

Please sign in to comment.