1#ifndef HALCHECK_LIB_DAG_HPP
2#define HALCHECK_LIB_DAG_HPP
10#include <halcheck/lib/functional.hpp>
11#include <halcheck/lib/iterator.hpp>
12#include <halcheck/lib/optional.hpp>
13#include <halcheck/lib/scope.hpp>
14#include <halcheck/lib/type_traits.hpp>
25namespace halcheck {
namespace lib {
73 dag(R &&range, F func) {
76 for (
auto &&value : range) {
77 const auto &resources = func(value);
79 for (
auto &&resource : resources) {
80 auto it = state.
find(resource);
81 if (it != state.
end()) {
82 parents.push_back(std::move(it->second));
88 for (
auto &&resource : resources) {
89 auto i = state.
find(resource);
91 state.
emplace(std::move(resource), it);
160 while (first != last) {
167 for (
auto &&edge : _edges) {
168 if (edge.children.back() == index)
169 edge.children.pop_back();
172 if (_roots.
back() == index)
232 struct to_const_iterator {
233 to_const_iterator() : self(nullptr) {};
234 explicit to_const_iterator(
const dag *self) : self(self) {}
235 to_const_iterator(
const to_iterator &other) : self(other.self) {}
257 auto &&data = _edges[it.
index()].children;
267 auto &&data = _edges[it.
index()].children;
277 auto &&data = _edges[it.
index()].parents;
287 auto &&data = _edges[it.
index()].parents;
340 for (
auto i = graph.
begin(); i != graph.
end(); ++i) {
342 for (
auto j : graph.
parents(i))
348 for (
const auto &parent : parents)
353 std::move(parents)));
356 for (
auto &&future : futures)
406 results[i].get_future().get());
432template<
typename T,
typename S,
typename F>
446 if (--references[j - dag.
begin()] == 0)
458 if (references[j - dag.
begin()]++ == 0)
463 if (linearize(dag, next, func, references, queue)) {
464 seed = std::move(next);
469 return queue.empty();
479bool linearize(
const lib::dag<T> &dag, S &seed, F func) {
481 for (
auto i = dag.begin(); i != dag.end(); ++i) {
482 for (
auto j : dag.children(i))
483 ++references[j - dag.begin()];
487 return detail::linearize(dag, seed, func, references, queue);
496lib::optional<lib::invoke_result_t<F>> linearize(
const lib::dag<T> &dag, F init, G func) {
502 lib::optional<lib::invoke_result_t<F>> value;
505 explicit state(F &init, G &func) : init(init), func(func) {}
507 state(state &&other)
noexcept(lib::is_nothrow_swappable<lib::optional<lib::invoke_result_t<F>>>())
508 : init(other.init), func(other.func), prefix(
std::move(other.prefix)) {
510 swap(value, other.value);
513 state &operator=(state &&other)
noexcept(lib::is_nothrow_swappable<lib::optional<lib::invoke_result_t<F>>>()) {
514 if (
this != &other) {
517 prefix = std::move(other.prefix);
521 swap(value, other.value);
527 state(
const state &other) : init(other.init), func(other.func), prefix(other.prefix) {}
529 state &operator=(
const state &other) {
530 if (
this != &other) {
533 prefix = other.prefix;
541 bool apply(
const T &label) {
542 if (func(label, get())) {
543 prefix.push_back(label);
551 lib::invoke_result_t<F> &get() {
553 value.emplace(lib::invoke(init));
554 for (
auto &&label : prefix) {
555 if (!func(label, *value))
564 state seed(init, func);
565 if (lib::linearize(dag, seed, [&](
const T &label, state ¤t) {
return current.apply(label); }))
566 return std::move(seed.get());
const_view parents(const_iterator it) const
Obtains a node's parents.
Definition dag.hpp:276
void clear()
Removes all nodes from this dag.
Definition dag.hpp:220
view roots()
Obtains the root nodes of this dag.
Definition dag.hpp:301
iterator emplace(const std::initializer_list< const_iterator > &range, Args &&...args)
Adds a node to this dag with its label constructed in place.
Definition dag.hpp:212
const_view roots() const
Obtains the root nodes of this dag.
Definition dag.hpp:295
iterator emplace(R &&range, Args &&...args)
Adds a node to this dag with its label constructed in place.
Definition dag.hpp:200
view parents(const_iterator it)
Obtains a node's parents.
Definition dag.hpp:286
std::size_t size() const
Gets the number of nodes in this dag.
Definition dag.hpp:133
iterator end()
Gets an iterator pointing past the last node in this dag.
Definition dag.hpp:114
const_view children(const_iterator it) const
Obtains a node's children.
Definition dag.hpp:256
const_iterator begin() const
Gets an const_iterator pointing to the first node in this dag.
Definition dag.hpp:108
iterator begin()
Gets an iterator pointing to the first node in this dag.
Definition dag.hpp:102
void reserve(std::size_t size)
Reserves enough memory to contain the specified number of nodes.
Definition dag.hpp:307
iterator emplace(I first, I last, Args &&...args)
Adds a node to this dag with its label constructed in place.
Definition dag.hpp:150
view children(const_iterator it)
Obtains a node's children.
Definition dag.hpp:266
const_iterator end() const
Gets an const_iterator pointing past the last node in this dag.
Definition dag.hpp:120
bool empty() const
Determines whether this dag is empty.
Definition dag.hpp:127
Directed acyclic graphs with labelled nodes.
Definition dag.hpp:33
T value_type
The type of node labels.
Definition dag.hpp:48
lib::index_iterator< std::vector< T > > iterator
A iterator to T. These are also referred to as "nodes".
Definition dag.hpp:53
lib::index_iterator< const std::vector< T > > const_iterator
An iterator to const T. These are also referred to as "nodes".
Definition dag.hpp:58
difference_type index() const
Gets the index of the element this iterator points to.
Definition index.hpp:118
An iterator into a random-access range that is invalidated if and only if the index of the pointed-to...
Definition index.hpp:22
T emplace_back(T... args)
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::@20 invoke
An implementation of std::invoke.
decltype(lib::invoke(std::declval< F >(), std::declval< Args >()...)) invoke_result_t
An implementation of std::invoke_result_t.
Definition invoke.hpp:42
lib::iter_value_t< lib::iterator_t< R > > range_value_t
The type of element contained in a range.
Definition range.hpp:332
decltype(lib::begin(std::declval< T & >())) iterator_t
Obtains the iterator type of a range type.
Definition range.hpp:92
typename std::iterator_traits< I >::reference iter_reference_t
The return type of operator* for an iterator.
Definition base.hpp:24
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::@31 transform
Constructs a transform_view.
lib::iter_reference_t< lib::iterator_t< R > > range_reference_t
The type returned by operator* for a range type's iterators.
Definition range.hpp:340
static constexpr nullopt_t nullopt
An implementation of std::nullopt.
Definition optional.hpp:41
lib::finally_t< F > finally(F func)
Definition scope.hpp:157
#define HALCHECK_REQUIRE(...)
Expands to a template argument that is only valid if the given argument evaluates to true.
Definition type_traits.hpp:24
void async(lib::dag< T > &graph, F func)
Executes a function on each label in a given graph. Calls for unrelated node labels are executed in p...
Definition dag.hpp:336
Determines if a type satisfies the EqualityComparable concept.
Definition type_traits.hpp:386
Determines if a type has a valid std::hash specialization.
Definition type_traits.hpp:398
Determines whether the given type is a range.
Definition range.hpp:158