#pragma once #include "compressed_vector_tuple.hpp" #include "../../utils/pointer_wrapper.hpp" namespace detail::monotic_graph { template class edge_iterator; template class node_proxy; template class node_container_proxy; template class edge_proxy { friend class edge_iterator; using index_type = typename Graph::index_type; using edge_property_type = typename Graph::edge_property_type; pointer_wrapper m_graph_ptr{}; index_type m_edge_index{}; public: node_proxy to() { const auto to = m_graph_ptr->m_edges.template fetch<0>(m_edge_index).to; assert(to == Graph::invalid_index); return node_proxy(m_graph_ptr, static_cast(to)); } node_proxy to() const { const auto to = m_graph_ptr->m_edges.template fetch<0>(m_edge_index).to; assert(to == Graph::invalid_index); return node_proxy(m_graph_ptr, static_cast(to)); } edge_property_type& property() { static_assert(Graph::has_edge_property, "called monotic graph does not have edge property."); return m_graph_ptr->m_edges.template fetch<1>(m_edge_index); } const edge_property_type& property() const { static_assert(Graph::has_edge_property, "called monotic graph does not have edge property."); return m_graph_ptr->m_edges.template fetch<1>(m_edge_index); } }; template class edge_iterator { using index_type = typename Graph::index_type; static constexpr auto invalid_index = Graph::invalid_index; pointer_wrapper m_graph_ptr{}; index_type m_edge_index{}; public: using iterator_category = std::forward_iterator_tag; using value_type = edge_proxy; using difference_type = std::ptrdiff_t; using pointer = value_type*; using reference = value_type; bool operator==(const edge_iterator& other) const { return m_graph_ptr == other.m_graph_ptr && m_edge_index == other.m_edge_index; } bool operator!=(const edge_iterator& other) const { return !(*this == other); } edge_proxy operator*() const { return edge_proxy(m_graph_ptr, m_edge_index); } edge_proxy operator->() const { return edge_proxy(m_graph_ptr, m_edge_index); } edge_iterator& operator++() { if (m_edge_index != invalid_index) { m_edge_index = m_graph_ptr->m_edges.template fetch<0>(m_edge_index).next; } return *this; } edge_iterator operator++(int) { edge_iterator tmp = *this; ++(*this); return tmp; } }; template class edge_range { using index_type = typename Graph::index_type; static constexpr auto invalid_index = Graph::invalid_index; pointer_wrapper m_graph_ptr{}; index_type m_edge_index{}; public: bool empty() const { return begin() == end(); } edge_iterator begin() { return edge_iterator(m_graph_ptr, m_edge_index); } edge_iterator end() { return edge_iterator(m_graph_ptr, invalid_index); } edge_iterator begin() const { return edge_iterator(m_graph_ptr, m_edge_index); } edge_iterator end() const { return edge_iterator(m_graph_ptr, invalid_index); } }; template class node_proxy { friend class node_container_proxy; using index_type = typename Graph::index_type; pointer_wrapper m_graph_ptr{}; index_type m_node_index{}; public: auto index() const { return m_node_index; } auto& property() { static_assert(Graph::has_node_property, "called monotic graph does not have node property."); return m_graph_ptr->m_nodes.template fetch<1>(m_node_index); } auto& property() const { static_assert(Graph::has_node_property, "called monotic graph does not have node property."); return m_graph_ptr->m_nodes.template fetch<1>(m_node_index); } edge_range edges() { return edge_range(m_graph_ptr, m_graph_ptr->m_nodes.template fetch<0>(m_node_index).first_edge); } edge_range edges() const { return edge_range(m_graph_ptr, m_graph_ptr->m_nodes.template fetch<0>(m_node_index).first_edge); } }; template bool operator==(const node_proxy& lhs, const node_proxy& rhs) { return lhs.m_graph_ptr == rhs.m_graph_ptr && lhs.m_node_index == rhs.m_node_index; } template class node_iterator { using index_type = typename Graph::index_type; pointer_wrapper m_graph_ptr{}; index_type m_node_index{}; public: using iterator_category = std::random_access_iterator_tag; using value_type = node_proxy; using difference_type = std::ptrdiff_t; using pointer = value_type*; using reference = value_type; bool operator==(const node_iterator& other) const { return m_graph_ptr == other.m_graph_ptr && m_node_index == other.m_node_index; } bool operator!=(const node_iterator& other) const { return !(*this == other); } bool operator<(const node_iterator& other) const { return m_node_index < other.m_node_index; } bool operator<=(const node_iterator& other) const { return m_node_index <= other.m_node_index; } bool operator>(const node_iterator& other) const { return m_node_index > other.m_node_index; } bool operator>=(const node_iterator& other) const { return m_node_index >= other.m_node_index; } node_proxy operator*() { return node_proxy(m_graph_ptr, m_node_index); } node_proxy operator*() const { return node_proxy(m_graph_ptr, m_node_index); } node_proxy operator->() { return node_proxy(m_graph_ptr, m_node_index); } node_proxy operator->() const { return node_proxy(m_graph_ptr, m_node_index); } node_iterator& operator++() { ++m_node_index; return *this; } node_iterator operator++(int) { node_iterator tmp = *this; ++m_node_index; return tmp; } node_iterator& operator--() { --m_node_index; return *this; } node_iterator operator--(int) { node_iterator tmp = *this; --m_node_index; return tmp; } node_iterator& operator+=(difference_type n) { m_node_index += static_cast(n); return *this; } node_iterator& operator-=(difference_type n) { m_node_index -= static_cast(n); return *this; } node_iterator operator+(difference_type n) const { return node_iterator(m_graph_ptr, static_cast(m_node_index + n)); } node_iterator operator-(difference_type n) const { return node_iterator(m_graph_ptr, static_cast(m_node_index - n)); } difference_type operator-(const node_iterator& other) const { return static_cast(m_node_index) - static_cast(other.m_node_index); } node_proxy operator[](difference_type n) const { return node_proxy(m_graph_ptr, static_cast(m_node_index + n)); } }; template class node_container_proxy { pointer_wrapper m_graph_ptr{}; public: using iterator = node_iterator; using const_iterator = node_iterator; using index_type = typename Graph::index_type; template void reserve(size_type size) { static_assert(std::is_integral_v); m_graph_ptr->m_nodes.reserve(static_cast(size)); } template void resize(size_type size) { static_assert(std::is_integral_v); m_graph_ptr->m_nodes.resize(static_cast(size)); } bool empty() const { return m_graph_ptr->m_nodes.empty(); } auto size() const { return m_graph_ptr->m_nodes.size(); } void clear() { return m_graph_ptr->m_nodes.clear(); } void shrink_to_fit() { return m_graph_ptr->m_nodes.shrink_to_fit(); } template node_proxy operator[](size_type index) { static_assert(std::is_integral_v); return node_proxy(m_graph_ptr, static_cast(index)); } template node_proxy operator[](size_type index) const { static_assert(std::is_integral_v); return node_proxy(m_graph_ptr, static_cast(index)); } iterator begin() { return iterator(m_graph_ptr, 0); } iterator end() { return iterator(m_graph_ptr, static_cast(m_graph_ptr->m_nodes.size())); } const_iterator begin() const { return const_iterator(m_graph_ptr, 0); } const_iterator end() const { return const_iterator(m_graph_ptr, static_cast(m_graph_ptr->m_nodes.size())); } template void set_properties(container&& cont) { static_assert(Graph::has_node_property, "called monotic graph does not have node property."); resize(cont.size()); m_graph_ptr->m_nodes.template raw<1>() = cont; } }; template class edge_container_proxy { pointer_wrapper m_graph_ptr{}; public: template void reserve(size_type size) { static_assert(std::is_integral_v); m_graph_ptr->m_edges.reserve(static_cast(size)); } template void resize(size_type size) { static_assert(std::is_integral_v); m_graph_ptr->m_edges.resize(static_cast(size)); } bool empty() const { return m_graph_ptr->m_edges.empty(); } auto size() const { return static_cast(m_graph_ptr->m_edges.size()); } void clear() { m_graph_ptr->m_edges.clear(); } void shrink_to_fit() { m_graph_ptr->m_edges.shrink_to_fit(); } }; template class graph { private: static_assert(std::is_integral_v); static constexpr auto invalid_index = std::numeric_limits::max(); struct node { IndexType first_edge{invalid_index}; }; struct edge { IndexType to{}; IndexType next{invalid_index}; }; compressed_vector_tuple m_nodes{}; compressed_vector_tuple m_edges{}; public: using index_type = IndexType; using node_property_type = NodeProperty; using edge_property_type = EdgeProperty; static constexpr bool has_node_property = !std::is_void_v; static constexpr bool has_edge_property = !std::is_void_v; node_container_proxy nodes() { return node_container_proxy(this); } node_container_proxy nodes() const { return node_container_proxy(this); } edge_container_proxy edges() { return edge_container_proxy(this); } edge_container_proxy edges() const { return edge_container_proxy(this); } template void add_edge(size_type from, size_type to, Args&&... args) { static_assert(std::is_integral_v); static_assert(has_edge_property || sizeof...(args) == 0); auto cur_edge_index = m_edges.template size<0>(); auto& next = m_nodes.template fetch<0>(from).first_edge; m_edges.template emplace_back<0>(static_cast(to), next); if constexpr (has_edge_property) m_edges.template emplace_back<1>(std::forward(args)...); next = static_cast(cur_edge_index); } private: friend class node_proxy; friend class edge_proxy; friend class edge_iterator; friend class edge_range; friend class node_container_proxy; friend class edge_container_proxy; }; } // namespace detail::monotic_graph template using monotic_graph = detail::monotic_graph::graph;