Skip to content

Commit

Permalink
Add structural collection folding.
Browse files Browse the repository at this point in the history
  • Loading branch information
tmadden committed Sep 29, 2020
1 parent c24813f commit e07f620
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 0 deletions.
56 changes: 56 additions & 0 deletions src/alia/context/typing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,62 @@ get_tagged_data(Collection collection)

} // namespace detail

// fold_over_collection(collection, f, z) performs a functional fold over the
// objects in a structural collection, invoking f as f(tag, data, z) for each
// object (and accumulating in z).

template<class Collection, class Function, class Initial>
auto
fold_over_collection(Collection collection, Function f, Initial z);

namespace detail {

// collection_folder is a helper struct for doing compile-time component
// collection folding...
template<class Collection>
struct collection_folder
{
};
// the empty case
template<class Storage>
struct collection_folder<structural_collection<tag_list<>, Storage>>
{
template<class Collection, class Function, class Initial>
static auto
apply(Collection, Function, Initial z)
{
return z;
}
};
// the recursive case
template<class Storage, class Tag, class... Rest>
struct collection_folder<
structural_collection<tag_list<Tag, Rest...>, Storage>>
{
template<class Collection, class Function, class Initial>
static auto
apply(Collection collection, Function f, Initial z)
{
return f(
Tag(),
get_tagged_data<Tag>(collection),
fold_over_collection(
structural_collection<detail::tag_list<Rest...>, Storage>(
collection.storage),
f,
z));
}
};

} // namespace detail

template<class Collection, class Function, class Initial>
auto
fold_over_collection(Collection collection, Function f, Initial z)
{
return detail::collection_folder<Collection>::apply(collection, f, z);
}

} // namespace alia

#endif
54 changes: 54 additions & 0 deletions unit_tests/context/typing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,57 @@ TEST_CASE("tagged data casting", "[context][typing]")
auto ctx = add_tagged_data<int_tag>(empty, 1);
REQUIRE(get_tagged_data<int_tag>(ctx) == 1);
}

namespace {

using std::string;

template<class Tag>
struct tagged_data_printer
{
};

template<>
struct tagged_data_printer<foo_tag>
{
static string
apply(foo const& f)
{
return f.b ? "foo: true; " : "foo: false; ";
}
};

template<>
struct tagged_data_printer<bar_tag>
{
static string
apply(bar const& b)
{
return "bar: " + std::to_string(b.i) + "; ";
}
};

struct reducer
{
template<class Tag, class Data>
string
operator()(Tag, Data data, string z)
{
return tagged_data_printer<Tag>::apply(data) + z;
}
};

} // namespace

TEST_CASE("collection folding", "[context][typing]")
{
storage_type storage;
auto mc_empty = make_empty_structural_collection(&storage);
bar b(1);
auto mc_b = add_tagged_data<bar_tag>(mc_empty, std::ref(b));
foo f;
auto mc_fb = add_tagged_data<foo_tag>(mc_b, std::ref(f));

auto reduction = alia::fold_over_collection(mc_fb, reducer(), string());
REQUIRE(reduction == "foo: false; bar: 1; ");
}

0 comments on commit e07f620

Please sign in to comment.