mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
build: add entt library
This commit is contained in:
332
include/entt/graph/adjacency_matrix.hpp
Normal file
332
include/entt/graph/adjacency_matrix.hpp
Normal file
@@ -0,0 +1,332 @@
|
||||
#ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP
|
||||
#define ENTT_GRAPH_ADJACENCY_MATRIX_HPP
|
||||
|
||||
#include "../config/config.h"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename It>
|
||||
class edge_iterator {
|
||||
using size_type = stl::size_t;
|
||||
|
||||
void find_next() noexcept {
|
||||
for(; pos != last && !it[static_cast<It::difference_type>(pos)]; pos += offset) {}
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = stl::pair<size_type, size_type>;
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
using iterator_category = stl::input_iterator_tag;
|
||||
using iterator_concept = stl::forward_iterator_tag;
|
||||
|
||||
constexpr edge_iterator() noexcept = default;
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
constexpr edge_iterator(It base, const size_type vertices, const size_type from, const size_type to, const size_type step) noexcept
|
||||
: it{stl::move(base)},
|
||||
vert{vertices},
|
||||
pos{from},
|
||||
last{to},
|
||||
offset{step} {
|
||||
find_next();
|
||||
}
|
||||
|
||||
constexpr edge_iterator &operator++() noexcept {
|
||||
pos += offset;
|
||||
find_next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr edge_iterator operator++(int) noexcept {
|
||||
const edge_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return stl::make_pair<size_type>(pos / vert, pos % vert);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const edge_iterator &other) const noexcept {
|
||||
return pos == other.pos;
|
||||
}
|
||||
|
||||
private:
|
||||
It it{};
|
||||
size_type vert{};
|
||||
size_type pos{};
|
||||
size_type last{};
|
||||
size_type offset{};
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Basic implementation of a directed adjacency matrix.
|
||||
* @tparam Category Either a directed or undirected category tag.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<stl::derived_from<directed_tag> Category, typename Allocator>
|
||||
class adjacency_matrix {
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
static_assert(stl::is_same_v<typename alloc_traits::value_type, stl::size_t>, "Invalid value type");
|
||||
using container_type = stl::vector<stl::size_t, typename alloc_traits::template rebind_alloc<stl::size_t>>;
|
||||
|
||||
public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Vertex type. */
|
||||
using vertex_type = size_type;
|
||||
/*! @brief Edge type. */
|
||||
using edge_type = stl::pair<vertex_type, vertex_type>;
|
||||
/*! @brief Vertex iterator type. */
|
||||
using vertex_iterator = iota_iterator<vertex_type>;
|
||||
/*! @brief Edge iterator type. */
|
||||
using edge_iterator = internal::edge_iterator<typename container_type::const_iterator>;
|
||||
/*! @brief Out-edge iterator type. */
|
||||
using out_edge_iterator = edge_iterator;
|
||||
/*! @brief In-edge iterator type. */
|
||||
using in_edge_iterator = edge_iterator;
|
||||
/*! @brief Graph category tag. */
|
||||
using graph_category = Category;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
adjacency_matrix() noexcept(noexcept(allocator_type{}))
|
||||
: adjacency_matrix{0u} {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit adjacency_matrix(const allocator_type &allocator) noexcept
|
||||
: adjacency_matrix{0u, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator and user
|
||||
* supplied number of vertices.
|
||||
* @param vertices Number of vertices.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
adjacency_matrix(const size_type vertices, const allocator_type &allocator = allocator_type{})
|
||||
: matrix{vertices * vertices, allocator},
|
||||
vert{vertices} {}
|
||||
|
||||
/*! @brief Default copy constructor. */
|
||||
adjacency_matrix(const adjacency_matrix &) = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
adjacency_matrix(const adjacency_matrix &other, const allocator_type &allocator)
|
||||
: matrix{other.matrix, allocator},
|
||||
vert{other.vert} {}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
adjacency_matrix(adjacency_matrix &&) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
adjacency_matrix(adjacency_matrix &&other, const allocator_type &allocator)
|
||||
: matrix{stl::move(other.matrix), allocator},
|
||||
vert{other.vert} {}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
~adjacency_matrix() = default;
|
||||
|
||||
/**
|
||||
* @brief Default copy assignment operator.
|
||||
* @return This container.
|
||||
*/
|
||||
adjacency_matrix &operator=(const adjacency_matrix &) = default;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @return This container.
|
||||
*/
|
||||
adjacency_matrix &operator=(adjacency_matrix &&) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given adjacency matrix.
|
||||
* @param other Adjacency matrix to exchange the content with.
|
||||
*/
|
||||
void swap(adjacency_matrix &other) noexcept {
|
||||
using stl::swap;
|
||||
swap(matrix, other.matrix);
|
||||
swap(vert, other.vert);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the associated allocator.
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
|
||||
return matrix.get_allocator();
|
||||
}
|
||||
|
||||
/*! @brief Clears the adjacency matrix. */
|
||||
void clear() noexcept {
|
||||
matrix.clear();
|
||||
vert = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if an adjacency matrix is empty, false otherwise.
|
||||
*
|
||||
* @warning
|
||||
* Potentially expensive, try to avoid it on hot paths.
|
||||
*
|
||||
* @return True if the adjacency matrix is empty, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const noexcept {
|
||||
const auto iterable = edges();
|
||||
return (iterable.begin() == iterable.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of vertices.
|
||||
* @return The number of vertices.
|
||||
*/
|
||||
[[nodiscard]] size_type size() const noexcept {
|
||||
return vert;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterable object to visit all vertices of a matrix.
|
||||
* @return An iterable object to visit all vertices of a matrix.
|
||||
*/
|
||||
[[nodiscard]] iterable_adaptor<vertex_iterator> vertices() const noexcept {
|
||||
return {0u, vert};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterable object to visit all edges of a matrix.
|
||||
* @return An iterable object to visit all edges of a matrix.
|
||||
*/
|
||||
[[nodiscard]] iterable_adaptor<edge_iterator> edges() const noexcept {
|
||||
const auto it = matrix.cbegin();
|
||||
const auto sz = matrix.size();
|
||||
return {{it, vert, 0u, sz, 1u}, {it, vert, sz, sz, 1u}};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterable object to visit all out-edges of a vertex.
|
||||
* @param vertex The vertex of which to return all out-edges.
|
||||
* @return An iterable object to visit all out-edges of a vertex.
|
||||
*/
|
||||
[[nodiscard]] iterable_adaptor<out_edge_iterator> out_edges(const vertex_type vertex) const noexcept {
|
||||
const auto it = matrix.cbegin();
|
||||
const auto from = vertex * vert;
|
||||
const auto to = from + vert;
|
||||
return {{it, vert, from, to, 1u}, {it, vert, to, to, 1u}};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterable object to visit all in-edges of a vertex.
|
||||
* @param vertex The vertex of which to return all in-edges.
|
||||
* @return An iterable object to visit all in-edges of a vertex.
|
||||
*/
|
||||
[[nodiscard]] iterable_adaptor<in_edge_iterator> in_edges(const vertex_type vertex) const noexcept {
|
||||
const auto it = matrix.cbegin();
|
||||
const auto from = vertex;
|
||||
const auto to = vert * vert + from;
|
||||
return {{it, vert, from, to, vert}, {it, vert, to, to, vert}};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resizes an adjacency matrix.
|
||||
* @param vertices The new number of vertices.
|
||||
*/
|
||||
void resize(const size_type vertices) {
|
||||
adjacency_matrix other{vertices, get_allocator()};
|
||||
|
||||
for(auto [lhs, rhs]: edges()) {
|
||||
other.insert(lhs, rhs);
|
||||
}
|
||||
|
||||
other.swap(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts an edge into the adjacency matrix, if it does not exist.
|
||||
* @param lhs The left hand vertex of the edge.
|
||||
* @param rhs The right hand vertex of the edge.
|
||||
* @return A pair consisting of an iterator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool denoting whether the
|
||||
* insertion took place.
|
||||
*/
|
||||
stl::pair<edge_iterator, bool> insert(const vertex_type lhs, const vertex_type rhs) {
|
||||
const auto pos = lhs * vert + rhs;
|
||||
|
||||
if constexpr(stl::is_same_v<graph_category, undirected_tag>) {
|
||||
const auto rev = rhs * vert + lhs;
|
||||
ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong");
|
||||
matrix[rev] = 1u;
|
||||
}
|
||||
|
||||
const auto inserted = !stl::exchange(matrix[pos], 1u);
|
||||
return {edge_iterator{matrix.cbegin(), vert, pos, matrix.size(), 1u}, inserted};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the edge associated with a pair of given vertices.
|
||||
* @param lhs The left hand vertex of the edge.
|
||||
* @param rhs The right hand vertex of the edge.
|
||||
* @return Number of elements removed (either 0 or 1).
|
||||
*/
|
||||
size_type erase(const vertex_type lhs, const vertex_type rhs) {
|
||||
const auto pos = lhs * vert + rhs;
|
||||
|
||||
if constexpr(stl::is_same_v<graph_category, undirected_tag>) {
|
||||
const auto rev = rhs * vert + lhs;
|
||||
ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong");
|
||||
matrix[rev] = 0u;
|
||||
}
|
||||
|
||||
return stl::exchange(matrix[pos], 0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if an adjacency matrix contains a given edge.
|
||||
* @param lhs The left hand vertex of the edge.
|
||||
* @param rhs The right hand vertex of the edge.
|
||||
* @return True if there is such an edge, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contains(const vertex_type lhs, const vertex_type rhs) const {
|
||||
const auto pos = lhs * vert + rhs;
|
||||
return pos < matrix.size() && matrix[pos];
|
||||
}
|
||||
|
||||
private:
|
||||
container_type matrix;
|
||||
size_type vert;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
56
include/entt/graph/dot.hpp
Normal file
56
include/entt/graph/dot.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef ENTT_GRAPH_DOT_HPP
|
||||
#define ENTT_GRAPH_DOT_HPP
|
||||
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/ostream.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Outputs a graph in dot format.
|
||||
* @tparam Graph Graph type, valid as long as it exposes edges and vertices.
|
||||
* @param out A standard output stream.
|
||||
* @param graph The graph to output.
|
||||
* @param writer Vertex decorator object.
|
||||
*/
|
||||
template<typename Graph>
|
||||
requires stl::derived_from<typename Graph::graph_category, directed_tag>
|
||||
void dot(stl::ostream &out, const Graph &graph, stl::invocable<stl::ostream &, typename Graph::vertex_type> auto writer) {
|
||||
if constexpr(stl::same_as<typename Graph::graph_category, undirected_tag>) {
|
||||
out << "graph{";
|
||||
} else {
|
||||
out << "digraph{";
|
||||
}
|
||||
|
||||
for(auto &&vertex: graph.vertices()) {
|
||||
out << vertex << "[";
|
||||
writer(out, vertex);
|
||||
out << "];";
|
||||
}
|
||||
|
||||
for(auto [lhs, rhs]: graph.edges()) {
|
||||
if constexpr(stl::same_as<typename Graph::graph_category, undirected_tag>) {
|
||||
out << lhs << "--" << rhs << ";";
|
||||
} else {
|
||||
out << lhs << "->" << rhs << ";";
|
||||
}
|
||||
}
|
||||
|
||||
out << "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Outputs a graph in dot format.
|
||||
* @tparam Graph Graph type, valid as long as it exposes edges and vertices.
|
||||
* @param out A standard output stream.
|
||||
* @param graph The graph to output.
|
||||
*/
|
||||
template<typename Graph>
|
||||
void dot(stl::ostream &out, const Graph &graph) {
|
||||
return dot(out, graph, [](auto &&...) {});
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
345
include/entt/graph/flow.hpp
Normal file
345
include/entt/graph/flow.hpp
Normal file
@@ -0,0 +1,345 @@
|
||||
#ifndef ENTT_GRAPH_FLOW_HPP
|
||||
#define ENTT_GRAPH_FLOW_HPP
|
||||
|
||||
#include "../config/config.h"
|
||||
#include "../container/dense_map.hpp"
|
||||
#include "../container/dense_set.hpp"
|
||||
#include "../core/compressed_pair.hpp"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../stl/algorithm.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/functional.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
#include "adjacency_matrix.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Utility class for creating task graphs.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
class basic_flow {
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
static_assert(stl::is_same_v<typename alloc_traits::value_type, id_type>, "Invalid value type");
|
||||
using task_container_type = dense_set<id_type, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc<id_type>>;
|
||||
using ro_rw_container_type = stl::vector<stl::pair<stl::size_t, bool>, typename alloc_traits::template rebind_alloc<stl::pair<stl::size_t, bool>>>;
|
||||
using deps_container_type = dense_map<id_type, ro_rw_container_type, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc<stl::pair<const id_type, ro_rw_container_type>>>;
|
||||
using adjacency_matrix_type = adjacency_matrix<directed_tag, typename alloc_traits::template rebind_alloc<stl::size_t>>;
|
||||
|
||||
void emplace(const id_type res, const bool is_rw) {
|
||||
ENTT_ASSERT(index.first() < vertices.size(), "Invalid node");
|
||||
|
||||
if(!deps.contains(res) && sync_on != vertices.size()) {
|
||||
deps[res].emplace_back(sync_on, true);
|
||||
}
|
||||
|
||||
deps[res].emplace_back(index.first(), is_rw);
|
||||
}
|
||||
|
||||
void setup_graph(adjacency_matrix_type &matrix) const {
|
||||
for(const auto &elem: deps) {
|
||||
const auto last = elem.second.cend();
|
||||
auto it = elem.second.cbegin();
|
||||
|
||||
while(it != last) {
|
||||
if(it->second) {
|
||||
// rw item
|
||||
if(auto curr = it++; it != last) {
|
||||
if(it->second) {
|
||||
matrix.insert(curr->first, it->first);
|
||||
} else if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
|
||||
for(; it != next; ++it) {
|
||||
matrix.insert(curr->first, it->first);
|
||||
matrix.insert(it->first, next->first);
|
||||
}
|
||||
} else {
|
||||
for(; it != next; ++it) {
|
||||
matrix.insert(curr->first, it->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ro item (first iteration only)
|
||||
if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
|
||||
for(; it != next; ++it) {
|
||||
matrix.insert(it->first, next->first);
|
||||
}
|
||||
} else {
|
||||
it = last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void transitive_closure(adjacency_matrix_type &matrix) const {
|
||||
const auto length = matrix.size();
|
||||
|
||||
for(stl::size_t vk{}; vk < length; ++vk) {
|
||||
for(stl::size_t vi{}; vi < length; ++vi) {
|
||||
for(stl::size_t vj{}; vj < length; ++vj) {
|
||||
if(matrix.contains(vi, vk) && matrix.contains(vk, vj)) {
|
||||
matrix.insert(vi, vj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void transitive_reduction(adjacency_matrix_type &matrix) const {
|
||||
const auto length = matrix.size();
|
||||
|
||||
for(stl::size_t vert{}; vert < length; ++vert) {
|
||||
matrix.erase(vert, vert);
|
||||
}
|
||||
|
||||
for(stl::size_t vj{}; vj < length; ++vj) {
|
||||
for(stl::size_t vi{}; vi < length; ++vi) {
|
||||
if(matrix.contains(vi, vj)) {
|
||||
for(stl::size_t vk{}; vk < length; ++vk) {
|
||||
if(matrix.contains(vj, vk)) {
|
||||
matrix.erase(vi, vk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Iterable task list. */
|
||||
using iterable = iterable_adaptor<typename task_container_type::const_iterator>;
|
||||
/*! @brief Adjacency matrix type. */
|
||||
using graph_type = adjacency_matrix_type;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
basic_flow()
|
||||
: basic_flow{allocator_type{}} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a flow builder with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit basic_flow(const allocator_type &allocator)
|
||||
: index{0u, allocator},
|
||||
vertices{allocator},
|
||||
deps{allocator} {}
|
||||
|
||||
/*! @brief Default copy constructor. */
|
||||
basic_flow(const basic_flow &) = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
basic_flow(const basic_flow &other, const allocator_type &allocator)
|
||||
: index{other.index.first(), allocator},
|
||||
vertices{other.vertices, allocator},
|
||||
deps{other.deps, allocator},
|
||||
sync_on{other.sync_on} {}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
basic_flow(basic_flow &&) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
basic_flow(basic_flow &&other, const allocator_type &allocator)
|
||||
: index{other.index.first(), allocator},
|
||||
vertices{stl::move(other.vertices), allocator},
|
||||
deps{stl::move(other.deps), allocator},
|
||||
sync_on{other.sync_on} {}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
~basic_flow() = default;
|
||||
|
||||
/**
|
||||
* @brief Default copy assignment operator.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &operator=(const basic_flow &) = default;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &operator=(basic_flow &&) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given flow builder.
|
||||
* @param other Flow builder to exchange the content with.
|
||||
*/
|
||||
void swap(basic_flow &other) noexcept {
|
||||
using stl::swap;
|
||||
swap(index, other.index);
|
||||
swap(vertices, other.vertices);
|
||||
swap(deps, other.deps);
|
||||
swap(sync_on, other.sync_on);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the associated allocator.
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
|
||||
return allocator_type{index.second()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the identifier at specified location.
|
||||
* @param pos Position of the identifier to return.
|
||||
* @return The requested identifier.
|
||||
*/
|
||||
[[nodiscard]] id_type operator[](const size_type pos) const {
|
||||
return vertices.cbegin()[static_cast<task_container_type::difference_type>(pos)];
|
||||
}
|
||||
|
||||
/*! @brief Clears the flow builder. */
|
||||
void clear() noexcept {
|
||||
index.first() = {};
|
||||
vertices.clear();
|
||||
deps.clear();
|
||||
sync_on = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if a flow builder contains no tasks, false otherwise.
|
||||
* @return True if the flow builder contains no tasks, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const noexcept {
|
||||
return vertices.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of tasks.
|
||||
* @return The number of tasks.
|
||||
*/
|
||||
[[nodiscard]] size_type size() const noexcept {
|
||||
return vertices.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Binds a task to a flow builder.
|
||||
* @param value Task identifier.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &bind(const id_type value) {
|
||||
sync_on += (sync_on == vertices.size());
|
||||
const auto it = vertices.emplace(value).first;
|
||||
index.first() = size_type(it - vertices.begin());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Turns the current task into a sync point.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &sync() {
|
||||
ENTT_ASSERT(index.first() < vertices.size(), "Invalid node");
|
||||
sync_on = index.first();
|
||||
|
||||
for(const auto &elem: deps) {
|
||||
elem.second.emplace_back(sync_on, true);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a resource to the current task with a given access mode.
|
||||
* @param res Resource identifier.
|
||||
* @param is_rw Access mode.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &set(const id_type res, bool is_rw = false) {
|
||||
emplace(res, is_rw);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a read-only resource to the current task.
|
||||
* @param res Resource identifier.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &ro(const id_type res) {
|
||||
emplace(res, false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a range of read-only resources to the current task.
|
||||
* @param first An iterator to the first element of the range of elements.
|
||||
* @param last An iterator past the last element of the range of elements.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &ro(stl::input_iterator auto first, stl::input_iterator auto last) {
|
||||
for(; first != last; ++first) {
|
||||
emplace(*first, false);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a writable resource to the current task.
|
||||
* @param res Resource identifier.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &rw(const id_type res) {
|
||||
emplace(res, true);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a range of writable resources to the current task.
|
||||
* @param first An iterator to the first element of the range of elements.
|
||||
* @param last An iterator past the last element of the range of elements.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &rw(stl::input_iterator auto first, stl::input_iterator auto last) {
|
||||
for(; first != last; ++first) {
|
||||
emplace(*first, true);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates a task graph for the current content.
|
||||
* @return The adjacency matrix of the task graph.
|
||||
*/
|
||||
[[nodiscard]] graph_type graph() const {
|
||||
graph_type matrix{vertices.size(), get_allocator()};
|
||||
|
||||
setup_graph(matrix);
|
||||
transitive_closure(matrix);
|
||||
transitive_reduction(matrix);
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
private:
|
||||
compressed_pair<size_type, allocator_type> index;
|
||||
task_container_type vertices;
|
||||
deps_container_type deps;
|
||||
size_type sync_on{};
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
28
include/entt/graph/fwd.hpp
Normal file
28
include/entt/graph/fwd.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef ENTT_GRAPH_FWD_HPP
|
||||
#define ENTT_GRAPH_FWD_HPP
|
||||
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @brief Undirected graph category tag. */
|
||||
struct directed_tag {};
|
||||
|
||||
/*! @brief Directed graph category tag. */
|
||||
struct undirected_tag: directed_tag {};
|
||||
|
||||
template<stl::derived_from<directed_tag>, typename = stl::allocator<stl::size_t>>
|
||||
class adjacency_matrix;
|
||||
|
||||
template<typename = stl::allocator<id_type>>
|
||||
class basic_flow;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using flow = basic_flow<>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user