-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
255 additions
and
180 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#ifndef ALIA_FLOW_CONTENT_CACHING_HPP | ||
#define ALIA_FLOW_CONTENT_CACHING_HPP | ||
|
||
#include <alia/context/interface.hpp> | ||
#include <alia/flow/components.hpp> | ||
#include <alia/flow/data_graph.hpp> | ||
|
||
namespace alia { | ||
|
||
template<class Object, class Content> | ||
auto | ||
implement_alia_content_caching(context, Object&, bool, Content content) | ||
{ | ||
return content; | ||
} | ||
|
||
struct component_caching_data | ||
{ | ||
data_block context_setup_block; | ||
data_block content_block; | ||
component_container_ptr container; | ||
captured_id args_id; | ||
}; | ||
|
||
template<class Context, class Component, class... Args> | ||
void | ||
invoke_pure_component(Context ctx, Component&& component, Args&&... args) | ||
{ | ||
component_caching_data* data; | ||
if (get_data(ctx, &data)) | ||
data->container.reset(new component_container); | ||
|
||
scoped_component_container container(ctx, &data->container); | ||
|
||
auto invoke_content = [&]() { | ||
scoped_data_block content_block(ctx, data->content_block); | ||
component(ctx, std::forward<Args>(args)...); | ||
}; | ||
|
||
if (is_refresh_event(ctx)) | ||
{ | ||
bool content_traversal_required = container.is_dirty(); | ||
|
||
auto args_id = combine_ids(ref(args.value_id())...); | ||
if (!data->args_id.matches(args_id)) | ||
content_traversal_required = true; | ||
|
||
scoped_data_block context_setup(ctx, data->context_setup_block); | ||
|
||
auto invoker = alia::fold_over_collection( | ||
get_structural_collection(ctx), | ||
[&](auto, auto& object, auto content) { | ||
return implement_alia_content_caching( | ||
ctx, object, content_traversal_required, content); | ||
}, | ||
[&]() { | ||
if (content_traversal_required) | ||
{ | ||
invoke_content(); | ||
} | ||
}); | ||
invoker(); | ||
|
||
data->args_id.capture(args_id); | ||
} | ||
else | ||
{ | ||
if (container.is_on_route()) | ||
{ | ||
invoke_content(); | ||
} | ||
} | ||
} | ||
|
||
} // namespace alia | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
#include <alia/flow/content_caching.hpp> | ||
|
||
#include <alia/signals/basic.hpp> | ||
#include <alia/signals/operators.hpp> | ||
|
||
#include <flow/testing.hpp> | ||
|
||
TEST_CASE("content caching", "[flow][content_caching]") | ||
{ | ||
clear_log(); | ||
|
||
int n = 0; | ||
|
||
tree_node<test_object> root; | ||
root.object.name = "root"; | ||
|
||
auto controller = [&](test_context ctx) { | ||
ALIA_IF(n & 1) | ||
{ | ||
do_object(ctx, "bit0"); | ||
} | ||
ALIA_END | ||
|
||
ALIA_IF(n & 2) | ||
{ | ||
do_object(ctx, "bit1"); | ||
} | ||
ALIA_END | ||
|
||
// Objects inside named blocks aren't necessarily deleted in order, so | ||
// this tests different code paths. | ||
naming_context nc(ctx); | ||
if (n & 32) | ||
{ | ||
named_block nb(nc, make_id(32)); | ||
do_object(ctx, "bit5"); | ||
} | ||
|
||
invoke_pure_component( | ||
ctx, | ||
[&](auto ctx, auto n) { | ||
the_log << "traversing cached content; "; | ||
|
||
ALIA_IF(n & 4) | ||
{ | ||
do_object(ctx, "bit2"); | ||
} | ||
ALIA_END | ||
|
||
ALIA_IF(n & 8) | ||
{ | ||
do_object(ctx, "bit3"); | ||
} | ||
ALIA_END | ||
}, | ||
value(n & 12)); | ||
|
||
ALIA_IF(n & 16) | ||
{ | ||
do_object(ctx, "bit4"); | ||
} | ||
ALIA_END | ||
}; | ||
|
||
alia::system sys; | ||
initialize_system(sys, [&](context vanilla_ctx) { | ||
tree_traversal<test_object> 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); }); | ||
} | ||
else | ||
{ | ||
controller(ctx); | ||
} | ||
}); | ||
|
||
n = 0b000000; | ||
refresh_system(sys); | ||
check_log("traversing cached content; "); | ||
REQUIRE(root.object.to_string() == "root()"); | ||
|
||
n = 0b000011; | ||
refresh_system(sys); | ||
check_log( | ||
"relocating bit0 into root; " | ||
"relocating bit1 into root after bit0; "); | ||
REQUIRE(root.object.to_string() == "root(bit0();bit1();)"); | ||
|
||
n = 0b000010; | ||
refresh_system(sys); | ||
check_log("removing bit0; "); | ||
REQUIRE(root.object.to_string() == "root(bit1();)"); | ||
|
||
n = 0b001111; | ||
refresh_system(sys); | ||
check_log( | ||
"relocating bit0 into root; " | ||
"traversing cached content; " | ||
"relocating bit2 into root after bit1; " | ||
"relocating bit3 into root after bit2; "); | ||
REQUIRE(root.object.to_string() == "root(bit0();bit1();bit2();bit3();)"); | ||
|
||
n = 0b001110; | ||
refresh_system(sys); | ||
check_log("removing bit0; "); | ||
REQUIRE(root.object.to_string() == "root(bit1();bit2();bit3();)"); | ||
|
||
n = 0b101110; | ||
refresh_system(sys); | ||
check_log("relocating bit5 into root after bit1; "); | ||
REQUIRE(root.object.to_string() == "root(bit1();bit5();bit2();bit3();)"); | ||
|
||
n = 0b101100; | ||
refresh_system(sys); | ||
check_log("removing bit1; "); | ||
REQUIRE(root.object.to_string() == "root(bit5();bit2();bit3();)"); | ||
|
||
n = 0b101101; | ||
refresh_system(sys); | ||
check_log("relocating bit0 into root; "); | ||
REQUIRE(root.object.to_string() == "root(bit0();bit5();bit2();bit3();)"); | ||
|
||
n = 0b001101; | ||
refresh_system(sys); | ||
check_log( | ||
"relocating bit2 into root after bit0; " | ||
"relocating bit3 into root after bit2; " | ||
"removing bit5; "); | ||
REQUIRE(root.object.to_string() == "root(bit0();bit2();bit3();)"); | ||
|
||
n = 0b000101; | ||
refresh_system(sys); | ||
check_log( | ||
"traversing cached content; " | ||
"removing bit3; "); | ||
REQUIRE(root.object.to_string() == "root(bit0();bit2();)"); | ||
|
||
n = 0b100100; | ||
refresh_system(sys); | ||
check_log("removing bit0; relocating bit5 into root; "); | ||
REQUIRE(root.object.to_string() == "root(bit5();bit2();)"); | ||
} |
Oops, something went wrong.