Skip to content

Commit

Permalink
Add make_returnable_ref
Browse files Browse the repository at this point in the history
  • Loading branch information
tmadden committed Dec 29, 2020
1 parent 21c55ac commit c86708e
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 9 deletions.
38 changes: 29 additions & 9 deletions src/alia/flow/data_graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,18 +406,31 @@ struct scoped_cache_clearing_disabler
bool old_cache_clearing_state_;
};

// get_data_node(ctx, &ptr) represents a data node in the data graph.
// A call to get_data_node() represents a data node in the data graph.
//
// The call retrieves data from the graph at the current point in the
// traversal, assigns its address to *ptr, and advances the traversal to the
// next node.
// It comes in two forms:
//
// The return value is true if the data at the node was just constructed and
// false if it already existed.
// (1) get_data_node(ctx, &ptr, create)
// (2) get_data_node(ctx, &ptr)
//
template<class Context, class Node>
// In both forms, the call retrieves data from the graph at the current point
// in the traversal, assigns its address to :ptr, and advances the traversal to
// the next node.
//
// In (1), you specify a custom function (:create) which allocates and
// initializes a new object (using `new`) and returns a pointer to it.
// get_data_node() will call this function when necessary to allocate and
// initialize the object at this node.
//
// In (2), alia uses a default allocater/initializer that simply calls `new`
// to create a default-constructed object.
//
// In both forms, the return value is true if the data at the node was just
// constructed and false if it already existed.
//
template<class Context, class Node, class Create>
bool
get_data_node(Context& ctx, Node** ptr)
get_data_node(Context& ctx, Node** ptr, Create&& create)
{
data_traversal& traversal = get_data_traversal(ctx);
data_node* node = *traversal.next_data_ptr;
Expand All @@ -430,14 +443,21 @@ get_data_node(Context& ctx, Node** ptr)
}
else
{
Node* new_node = new Node;
Node* new_node = std::forward<Create>(create)();
*traversal.next_data_ptr = new_node;
traversal.next_data_ptr = &new_node->alia_next_data_node_;
*ptr = new_node;
return true;
}
}

template<class Context, class Node>
bool
get_data_node(Context& ctx, Node** ptr)
{
return get_data_node(ctx, ptr, [&] { return new Node; });
}

template<class T>
struct persistent_data_node : data_node
{
Expand Down
40 changes: 40 additions & 0 deletions src/alia/flow/utilities.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef ALIA_FLOW_UTILITIES_HPP
#define ALIA_FLOW_UTILITIES_HPP

#include <alia/context/interface.hpp>
#include <alia/flow/data_graph.hpp>

namespace alia {

// make_returnable_ref(ctx, x) stores a copy of x within the data graph of ctx
// and returns a reference to that copy. (It will move instead of copying when
// possible.)

template<class T>
struct returnable_ref_node : data_node
{
// TODO: Use optional instead.
std::unique_ptr<T> value;

void
clear_cache()
{
value.reset();
}
};

template<class T>
T&
make_returnable_ref(context ctx, T x)
{
returnable_ref_node<T>* node;
if (get_data_node(ctx, &node))
node->value.reset(new T(x));
else
*node->value = std::move(x);
return *node->value;
}

} // namespace alia

#endif
31 changes: 31 additions & 0 deletions unit_tests/flow/utilities.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#define ALIA_LOWERCASE_MACROS

#include <alia/flow/utilities.hpp>

#include <alia/signals/basic.hpp>

#include <testing.hpp>

#include "traversal.hpp"

using namespace alia;

using std::string;

TEST_CASE("make_returnable_ref", "[flow][for_each]")
{
alia::system sys;
initialize_system(sys, [](context) {});

auto function_that_returns = [](context ctx) -> readable<string> {
return make_returnable_ref(ctx, value(string("something")));
};

auto controller = [&](context ctx) {
auto s = function_that_returns(ctx);
REQUIRE(signal_has_value(s));
REQUIRE(read_signal(s) == "something");
};

do_traversal(sys, controller);
}

0 comments on commit c86708e

Please sign in to comment.