graph: (currently directed only) adjacency_matrix
This commit is contained in:
@@ -147,6 +147,8 @@ if(ENTT_INCLUDE_HEADERS)
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/sparse_set.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/storage.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/view.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/adjacency_matrix.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/locator/locator.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/adl_pointer.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/container.hpp>
|
||||
|
||||
1
TODO
1
TODO
@@ -12,6 +12,7 @@ DOC:
|
||||
* document iterator.hpp (see core.md)
|
||||
|
||||
WIP:
|
||||
* add directed/undirected support to adjacency matrix (see brief)
|
||||
* handle: replace visit with an iterable object
|
||||
* add storage getter for filters to views and groups
|
||||
* exploit the tombstone mechanism to allow enabling/disabling entities (see bump, compact and clear for further details)
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "entity/sparse_set.hpp"
|
||||
#include "entity/storage.hpp"
|
||||
#include "entity/view.hpp"
|
||||
#include "graph/adjacency_matrix.hpp"
|
||||
#include "locator/locator.hpp"
|
||||
#include "meta/adl_pointer.hpp"
|
||||
#include "meta/container.hpp"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "container/fwd.hpp"
|
||||
#include "core/fwd.hpp"
|
||||
#include "entity/fwd.hpp"
|
||||
#include "graph/fwd.hpp"
|
||||
#include "meta/fwd.hpp"
|
||||
#include "poly/fwd.hpp"
|
||||
#include "process/fwd.hpp"
|
||||
|
||||
298
src/entt/graph/adjacency_matrix.hpp
Normal file
298
src/entt/graph/adjacency_matrix.hpp
Normal file
@@ -0,0 +1,298 @@
|
||||
#ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP
|
||||
#define ENTT_GRAPH_ADJACENCY_MATRIX_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct edge_iterator {
|
||||
using value_type = std::pair<std::size_t, std::size_t>;
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
constexpr edge_iterator() noexcept
|
||||
: matrix{},
|
||||
vert{},
|
||||
it{},
|
||||
last{} {}
|
||||
|
||||
constexpr edge_iterator(const std::size_t *ref, const std::size_t vertices, const std::size_t from) noexcept
|
||||
: edge_iterator{ref, vertices, from, vertices * vertices} {}
|
||||
|
||||
constexpr edge_iterator(const std::size_t *ref, const std::size_t vertices, const std::size_t from, const std::size_t to) noexcept
|
||||
: matrix{ref},
|
||||
vert{vertices},
|
||||
it{from},
|
||||
last{to} {
|
||||
for(; it != last && !matrix[it]; ++it) {}
|
||||
}
|
||||
|
||||
constexpr edge_iterator &operator++() noexcept {
|
||||
for(++it; it != last && !matrix[it]; ++it) {}
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr edge_iterator operator++(int) noexcept {
|
||||
edge_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return std::make_pair<std::size_t>(it / vert, it % vert);
|
||||
}
|
||||
|
||||
friend constexpr bool operator==(const edge_iterator &, const edge_iterator &) noexcept;
|
||||
|
||||
private:
|
||||
const std::size_t *matrix;
|
||||
std::size_t vert;
|
||||
std::size_t it;
|
||||
std::size_t last;
|
||||
};
|
||||
|
||||
[[nodiscard]] inline constexpr bool operator==(const edge_iterator &lhs, const edge_iterator &rhs) noexcept {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr bool operator!=(const edge_iterator &lhs, const edge_iterator &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Basic implementation of a directed adjacency matrix.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
class basic_adjacency_matrix {
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
static_assert(std::is_same_v<typename alloc_traits::value_type, std::size_t>, "Invalid value type");
|
||||
using container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
|
||||
|
||||
public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Vertex type. */
|
||||
using vertex_type = size_type;
|
||||
/*! @brief Edge type. */
|
||||
using edge_type = std::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;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
basic_adjacency_matrix() noexcept(noexcept(allocator_type{}))
|
||||
: basic_adjacency_matrix{0u} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit basic_adjacency_matrix(const allocator_type &allocator) noexcept
|
||||
: basic_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.
|
||||
*/
|
||||
basic_adjacency_matrix(const size_type vertices, const allocator_type &allocator = allocator_type{})
|
||||
: matrix(vertices * vertices),
|
||||
vert{vertices} {}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
*/
|
||||
basic_adjacency_matrix(const basic_adjacency_matrix &other)
|
||||
: basic_adjacency_matrix{other, other.get_allocator()} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
basic_adjacency_matrix(const basic_adjacency_matrix &other, const allocator_type &allocator)
|
||||
: matrix{other.matrix, allocator},
|
||||
vert{other.vert} {}
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_adjacency_matrix(basic_adjacency_matrix &&other) noexcept
|
||||
: basic_adjacency_matrix{std::move(other), other.get_allocator()} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
basic_adjacency_matrix(basic_adjacency_matrix &&other, const allocator_type &allocator)
|
||||
: matrix{std::move(other.matrix), allocator},
|
||||
vert{std::exchange(other.vert, 0u)} {}
|
||||
|
||||
/**
|
||||
* @brief Default copy assignment operator.
|
||||
* @param other The instance to copy from.
|
||||
* @return This container.
|
||||
*/
|
||||
basic_adjacency_matrix &operator=(const basic_adjacency_matrix &other) {
|
||||
matrix = other.matrix;
|
||||
vert = other.vert;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This container.
|
||||
*/
|
||||
basic_adjacency_matrix &operator=(basic_adjacency_matrix &&other) noexcept {
|
||||
matrix = std::move(other.matrix);
|
||||
vert = std::exchange(other.vert, 0u);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 Exchanges the contents with those of a given adjacency matrix.
|
||||
* @param other Adjacency matrix to exchange the content with.
|
||||
*/
|
||||
void swap(adjacency_matrix &other) {
|
||||
using std::swap;
|
||||
swap(matrix, other.matrix);
|
||||
swap(vert, other.vert);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 {
|
||||
return {{matrix.data(), vert, 0u}, {matrix.data(), vert, matrix.size()}};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterable object to visit all edges of a vertex.
|
||||
* @param vertex The vertex of which to return all edges.
|
||||
* @return An iterable object to visit all edges of a vertex.
|
||||
*/
|
||||
[[nodiscard]] iterable_adaptor<edge_iterator> edges(const vertex_type vertex) const noexcept {
|
||||
const auto first = vertex * vert;
|
||||
const auto last = vertex * vert + vert;
|
||||
return {{matrix.data(), vert, first, last}, {matrix.data(), vert, last, last}};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resizes an adjacency matrix.
|
||||
* @param vertices The new number of vertices.
|
||||
*/
|
||||
void resize(const size_type vertices) {
|
||||
matrix.resize(vertices * vertices);
|
||||
vert = vertices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
std::pair<edge_iterator, bool> insert(const vertex_type lhs, const vertex_type rhs) {
|
||||
const auto pos = lhs * vert + rhs;
|
||||
const auto inserted = !std::exchange(matrix[pos], 1u);
|
||||
return {edge_iterator{matrix.data(), vert, pos}, 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) {
|
||||
return std::exchange(matrix[lhs * vert + rhs], 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
|
||||
17
src/entt/graph/fwd.hpp
Normal file
17
src/entt/graph/fwd.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef ENTT_GRAPH_FWD_HPP
|
||||
#define ENTT_GRAPH_FWD_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
namespace entt {
|
||||
|
||||
template<typename = std::allocator<std::size_t>>
|
||||
struct basic_adjacency_matrix;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using adjacency_matrix = basic_adjacency_matrix<>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -217,6 +217,10 @@ SETUP_BASIC_TEST(sparse_set entt/entity/sparse_set.cpp)
|
||||
SETUP_BASIC_TEST(storage entt/entity/storage.cpp)
|
||||
SETUP_BASIC_TEST(view entt/entity/view.cpp)
|
||||
|
||||
# Test graph
|
||||
|
||||
SETUP_BASIC_TEST(adjacency_matrix entt/graph/adjacency_matrix.cpp)
|
||||
|
||||
# Test locator
|
||||
|
||||
SETUP_BASIC_TEST(locator entt/locator/locator.cpp)
|
||||
|
||||
289
test/entt/graph/adjacency_matrix.cpp
Normal file
289
test/entt/graph/adjacency_matrix.cpp
Normal file
@@ -0,0 +1,289 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/graph/adjacency_matrix.hpp>
|
||||
#include "../common/throwing_allocator.hpp"
|
||||
|
||||
TEST(AdjacencyMatrix, Resize) {
|
||||
entt::adjacency_matrix adjacency_matrix{2};
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 2u);
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
|
||||
adjacency_matrix.resize(3u);
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 3u);
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Constructors) {
|
||||
entt::adjacency_matrix adjacency_matrix{};
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
|
||||
adjacency_matrix = entt::adjacency_matrix{std::allocator<bool>{}};
|
||||
adjacency_matrix = entt::adjacency_matrix{3u, std::allocator<bool>{}};
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 3u);
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
entt::adjacency_matrix temp{adjacency_matrix, adjacency_matrix.get_allocator()};
|
||||
entt::adjacency_matrix other{std::move(adjacency_matrix), adjacency_matrix.get_allocator()};
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
|
||||
ASSERT_FALSE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_TRUE(other.contains(0u, 1u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Copy) {
|
||||
entt::adjacency_matrix adjacency_matrix{3u};
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
entt::adjacency_matrix other{adjacency_matrix};
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 3u);
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_TRUE(other.contains(0u, 1u));
|
||||
|
||||
adjacency_matrix.resize(4u);
|
||||
adjacency_matrix.insert(0u, 2u);
|
||||
other.insert(1u, 2u);
|
||||
|
||||
other = adjacency_matrix;
|
||||
|
||||
ASSERT_EQ(other.size(), 4u);
|
||||
ASSERT_EQ(adjacency_matrix.size(), 4u);
|
||||
|
||||
ASSERT_TRUE(other.contains(0u, 1u));
|
||||
ASSERT_FALSE(other.contains(1u, 2u));
|
||||
ASSERT_TRUE(other.contains(0u, 2u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Move) {
|
||||
entt::adjacency_matrix adjacency_matrix{3u};
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
entt::adjacency_matrix other{std::move(adjacency_matrix)};
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
|
||||
ASSERT_FALSE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_TRUE(other.contains(0u, 1u));
|
||||
|
||||
adjacency_matrix = {};
|
||||
adjacency_matrix.resize(4u);
|
||||
adjacency_matrix.insert(0u, 2u);
|
||||
other.insert(1u, 2u);
|
||||
|
||||
other = std::move(adjacency_matrix);
|
||||
|
||||
ASSERT_EQ(other.size(), 4u);
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
|
||||
ASSERT_FALSE(other.contains(0u, 1u));
|
||||
ASSERT_FALSE(other.contains(1u, 2u));
|
||||
ASSERT_TRUE(other.contains(0u, 2u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Swap) {
|
||||
entt::adjacency_matrix adjacency_matrix{3u};
|
||||
entt::adjacency_matrix other{};
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
ASSERT_EQ(other.size(), 0u);
|
||||
ASSERT_EQ(adjacency_matrix.size(), 3u);
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_FALSE(other.contains(0u, 1u));
|
||||
|
||||
adjacency_matrix.swap(other);
|
||||
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
ASSERT_FALSE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_TRUE(other.contains(0u, 1u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Insert) {
|
||||
entt::adjacency_matrix adjacency_matrix{3u};
|
||||
|
||||
auto first = adjacency_matrix.insert(0u, 1u);
|
||||
auto second = adjacency_matrix.insert(0u, 2u);
|
||||
auto other = adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
ASSERT_TRUE(first.second);
|
||||
ASSERT_TRUE(second.second);
|
||||
ASSERT_FALSE(other.second);
|
||||
|
||||
ASSERT_NE(first.first, second.first);
|
||||
ASSERT_EQ(first.first, other.first);
|
||||
|
||||
ASSERT_EQ(*first.first, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(*second.first, std::make_pair(std::size_t{0u}, std::size_t{2u}));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Erase) {
|
||||
entt::adjacency_matrix adjacency_matrix{3u};
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_EQ(adjacency_matrix.erase(0u, 1u), 1u);
|
||||
ASSERT_EQ(adjacency_matrix.erase(0u, 1u), 0u);
|
||||
ASSERT_FALSE(adjacency_matrix.contains(0u, 1u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Clear) {
|
||||
entt::adjacency_matrix adjacency_matrix{3u};
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(0u, 2u);
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 2u));
|
||||
ASSERT_EQ(adjacency_matrix.size(), 3u);
|
||||
|
||||
adjacency_matrix.clear();
|
||||
|
||||
ASSERT_FALSE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_FALSE(adjacency_matrix.contains(0u, 2u));
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, VertexIterator) {
|
||||
using iterator = typename entt::adjacency_matrix::vertex_iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, std::size_t>);
|
||||
static_assert(std::is_same_v<iterator::pointer, void>);
|
||||
static_assert(std::is_same_v<iterator::reference, std::size_t>);
|
||||
|
||||
entt::adjacency_matrix adjacency_matrix{2u};
|
||||
const auto iterable = adjacency_matrix.vertices();
|
||||
|
||||
iterator end{iterable.begin()};
|
||||
iterator begin{};
|
||||
|
||||
begin = iterable.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, iterable.begin());
|
||||
ASSERT_EQ(end, iterable.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(*begin, 0u);
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(*begin, 1u);
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, EdgeIterator) {
|
||||
using iterator = typename entt::adjacency_matrix::edge_iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, std::pair<std::size_t, std::size_t>>);
|
||||
static_assert(std::is_same_v<iterator::pointer, entt::input_iterator_pointer<std::pair<std::size_t, std::size_t>>>);
|
||||
static_assert(std::is_same_v<iterator::reference, std::pair<std::size_t, std::size_t>>);
|
||||
|
||||
entt::adjacency_matrix adjacency_matrix{3u};
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(0u, 2u);
|
||||
|
||||
const auto iterable = adjacency_matrix.edges();
|
||||
|
||||
iterator end{iterable.begin()};
|
||||
iterator begin{};
|
||||
|
||||
begin = iterable.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, iterable.begin());
|
||||
ASSERT_EQ(end, iterable.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(*begin, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(*begin.operator->(), std::make_pair(std::size_t{0u}, std::size_t{2u}));
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Vertices) {
|
||||
entt::adjacency_matrix adjacency_matrix{};
|
||||
auto iterable = adjacency_matrix.vertices();
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.resize(2u);
|
||||
iterable = adjacency_matrix.vertices();
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 2u);
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, 0u);
|
||||
ASSERT_EQ(*it, 1u);
|
||||
ASSERT_EQ(++it, iterable.end());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Edges) {
|
||||
entt::adjacency_matrix adjacency_matrix{3u};
|
||||
auto iterable = adjacency_matrix.edges();
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(1u, 2u);
|
||||
iterable = adjacency_matrix.edges();
|
||||
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(*it.operator->(), std::make_pair(std::size_t{1u}, std::size_t{2u}));
|
||||
ASSERT_EQ(++it, iterable.end());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, EdgesByVertex) {
|
||||
entt::adjacency_matrix adjacency_matrix{3u};
|
||||
auto iterable = adjacency_matrix.edges();
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(1u, 2u);
|
||||
iterable = adjacency_matrix.edges(0u);
|
||||
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(it, iterable.end());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, ThrowingAllocator) {
|
||||
using allocator = test::throwing_allocator<std::size_t>;
|
||||
using exception = typename allocator::exception_type;
|
||||
|
||||
entt::basic_adjacency_matrix<allocator> adjacency_matrix{2u};
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
allocator::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 2u);
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
|
||||
ASSERT_THROW(adjacency_matrix.resize(4u), exception);
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 2u);
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
}
|
||||
Reference in New Issue
Block a user