23 template<network Connectivity,
class Nodes>
24 class SEQUOIA_MSVC_EMPTY_BASE_HACK graph_primitive;
28 template<network Connectivity,
class Nodes>
33 using index_type =
typename graph_type::edge_index_type;
34 using difference_type = std::make_signed_t<index_type>;
35 using value_type = index_type;
36 using reference = index_type;
45 constexpr const graph_type& graph()
const noexcept
51 constexpr static reference get(index_type i) {
return i; }
72 template<network Connectivity,
class Nodes>
76 template<network Connectivity,
class Nodes>
79 a.graph().swap_nodes(a.base_iterator(), b.base_iterator());
82 template<
class NodeWeight>
86 std::initializer_list<tree_initializer> children{};
89 template<
class NodeWeight>
90 requires std::is_empty_v<NodeWeight>
93 std::initializer_list<tree_initializer> children{};
96 enum class tree_link_direction {symmetric, forward, backward};
98 template<tree_link_direction d>
105 template<network Connectivity,
class Nodes>
106 class SEQUOIA_MSVC_EMPTY_BASE_HACK
graph_primitive :
public Connectivity,
public Nodes
109 using node_weight_type =
typename Nodes::weight_type;
112 using connectivity_type = Connectivity;
113 using nodes_type = Nodes;
114 using edge_init_type =
typename Connectivity::edge_init_type;
115 using edge_index_type =
typename Connectivity::edge_index_type;
116 using size_type = std::common_type_t<typename Connectivity::size_type, typename Nodes::size_type>;
119 using edges_initializer = std::initializer_list<std::initializer_list<edge_init_type>>;
124 requires std::is_empty_v<node_weight_type>
125 : Connectivity{edges}
130 requires (!std::is_empty_v<node_weight_type> && !heterogeneous_nodes<graph_primitive> && std::is_default_constructible_v<node_weight_type>)
131 : Connectivity{edges}
132 , Nodes(edges.size())
135 constexpr graph_primitive(edges_initializer edges, std::initializer_list<node_weight_type> nodeWeights)
136 requires (!std::is_empty_v<node_weight_type> && !heterogeneous_nodes<graph_primitive>)
137 : Connectivity{check_initialization(edges, nodeWeights.size(), edges.size())}
141 template<
class... NodeWeights>
142 requires heterogeneous_nodes<graph_primitive>
143 constexpr graph_primitive(edges_initializer edges, NodeWeights&&... nodeWeights)
144 : Connectivity{check_initialization(edges,
sizeof...(NodeWeights), edges.size())}
145 , Nodes{std::forward<NodeWeights>(nodeWeights)...}
148 template<tree_link_direction dir>
149 requires ( !heterogeneous_nodes<graph_primitive>
150 && ((dir == tree_link_direction::symmetric) || is_directed(Connectivity::flavour)))
153 for(
const auto& tree : forest)
155 build_tree(std::numeric_limits<size_type>::max(), tree, tdc);
159 template<tree_link_direction dir>
160 requires ( !heterogeneous_nodes<graph_primitive>
161 && ((dir == tree_link_direction::symmetric) || is_directed(Connectivity::flavour)))
164 build_tree(std::numeric_limits<size_type>::max(), tree, tdc);
170 constexpr size_type size()
const noexcept
172 return connectivity_type::size();
175 constexpr void swap_nodes(edge_index_type i, edge_index_type j)
177 if constexpr(!std::is_empty_v<node_weight_type>)
179 Nodes::swap_nodes(i, j);
182 Connectivity::swap_nodes(i, j);
185 template<
class Compare>
186 constexpr void sort_nodes(Compare c)
188 sort_nodes(edge_index_type{}, Connectivity::order(), std::move(c));
191 template<
class Compare>
192 constexpr void sort_nodes(
const edge_index_type first,
const edge_index_type last, Compare c)
205 constexpr static bool enableNodeAllocation{!heterogeneous_nodes<graph_primitive> && !std::is_empty_v<N>};
212 requires enableNodeAllocation<node_weight_type>
213 constexpr graph_primitive(
const EdgeAllocator& edgeAlloc,
const NodeAllocator& nodeAlloc)
215 : Connectivity(edgeAlloc)
222 alloc EdgePartitionsAllocator,
225 requires (enableNodeAllocation<node_weight_type>)
226 constexpr graph_primitive(
const EdgeAllocator& edgeAlloc,
const EdgePartitionsAllocator& edgeParitionsAlloc,
const NodeAllocator& nodeAlloc)
227 : Connectivity(edgeAlloc, edgeParitionsAlloc)
231 template<alloc EdgeAllocator>
232 requires (!enableNodeAllocation<node_weight_type>)
234 : Connectivity(edgeAlloc)
240 alloc EdgePartitionsAllocator
242 requires(!enableNodeAllocation<node_weight_type>)
243 constexpr graph_primitive(
const EdgeAllocator& edgeAlloc,
const EdgePartitionsAllocator& edgeParitionsAlloc)
244 : Connectivity(edgeAlloc, edgeParitionsAlloc)
252 requires enableNodeAllocation<node_weight_type>
253 constexpr graph_primitive(edges_initializer edges,
const EdgeAllocator& edgeAlloc, std::initializer_list<node_weight_type> nodeWeights,
const NodeAllocator& nodeAlloc)
254 : Connectivity{edges, edgeAlloc}
255 , Nodes{nodeWeights, nodeAlloc}
261 alloc EdgePartitionsAllocator,
264 requires enableNodeAllocation<node_weight_type>
265 constexpr graph_primitive(edges_initializer edges,
const EdgeAllocator& edgeAlloc,
const EdgePartitionsAllocator& edgeParitionsAlloc, std::initializer_list<node_weight_type> nodeWeights,
const NodeAllocator& nodeAlloc)
266 : Connectivity{edges, edgeAlloc, edgeParitionsAlloc}
267 , Nodes{nodeWeights, nodeAlloc}
273 alloc EdgePartitionsAllocator,
276 requires heterogeneous_nodes<graph_primitive>
277 constexpr graph_primitive(edges_initializer edges,
const EdgeAllocator& edgeAlloc,
const EdgePartitionsAllocator& edgeParitionsAlloc, NodeWeights&&... nodeWeights)
278 : Connectivity{edges, edgeAlloc, edgeParitionsAlloc}
279 , Nodes{std::forward<NodeWeights>(nodeWeights)...}
287 requires enableNodeAllocation<node_weight_type>
288 constexpr graph_primitive(edges_initializer edges,
const EdgeAllocator& edgeAlloc,
const NodeAllocator& nodeAlloc)
289 : Connectivity{edges, edgeAlloc}
290 , Nodes(edges.size(), nodeAlloc)
296 alloc EdgePartitionsAllocator,
299 requires enableNodeAllocation<node_weight_type>
300 constexpr graph_primitive(edges_initializer edges,
const EdgeAllocator& edgeAlloc,
const EdgePartitionsAllocator& edgeParitionsAlloc,
const NodeAllocator& nodeAlloc)
301 : Connectivity{edges, edgeAlloc, edgeParitionsAlloc}
302 , Nodes(edges.size(), nodeAlloc)
308 alloc EdgePartitionsAllocator
310 requires (!enableNodeAllocation<node_weight_type>)
311 constexpr graph_primitive(edges_initializer edges,
const EdgeAllocator& edgeAlloc,
const EdgePartitionsAllocator& edgeParitionsAlloc)
312 : Connectivity{edges, edgeAlloc, edgeParitionsAlloc}
316 template<alloc EdgeAllocator>
317 requires (!enableNodeAllocation<node_weight_type>)
318 constexpr graph_primitive(edges_initializer edges,
const EdgeAllocator& edgeAlloc)
319 : Connectivity{edges, edgeAlloc}
328 alloc EdgePartitionsAllocator,
331 requires enableNodeAllocation<node_weight_type>
332 constexpr graph_primitive(
const graph_primitive& in,
const EdgeAllocator& edgeAlloc,
const EdgePartitionsAllocator& edgeParitionsAlloc,
const NodeAllocator& nodeAlloc)
333 : Connectivity{
static_cast<const Connectivity&
>(in), edgeAlloc, edgeParitionsAlloc}
334 , Nodes{
static_cast<const Nodes&
>(in), nodeAlloc}
342 requires enableNodeAllocation<node_weight_type>
344 : Connectivity{
static_cast<const Connectivity&
>(in), edgeAlloc}
345 , Nodes{
static_cast<const Nodes&
>(in), nodeAlloc}
351 alloc EdgePartitionsAllocator
353 requires (!enableNodeAllocation<node_weight_type>)
355 : Connectivity{
static_cast<const Connectivity&
>(in), edgeAlloc, edgeParitionsAlloc}
356 , Nodes{
static_cast<const Nodes&
>(in)}
359 template<alloc EdgeAllocator>
360 requires (!enableNodeAllocation<node_weight_type>)
362 : Connectivity{
static_cast<const Connectivity&
>(in), edgeAlloc}
363 , Nodes{
static_cast<const Nodes&
>(in)}
373 alloc EdgePartitionsAllocator,
376 requires enableNodeAllocation<node_weight_type>
377 constexpr graph_primitive(
graph_primitive&& in,
const EdgeAllocator& edgeAlloc,
const EdgePartitionsAllocator& edgeParitionsAlloc,
const NodeAllocator& nodeAlloc)
378 : Connectivity{
static_cast<Connectivity&&
>(in), edgeAlloc, edgeParitionsAlloc}
379 , Nodes{
static_cast<Nodes&&
>(in), nodeAlloc}
387 requires enableNodeAllocation<node_weight_type>
389 : Connectivity{
static_cast<Connectivity&&
>(in), edgeAlloc}
390 , Nodes{
static_cast<Nodes&&
>(in), nodeAlloc}
396 alloc EdgePartitionsAllocator,
399 requires (!enableNodeAllocation<node_weight_type>)
401 : Connectivity{
static_cast<Connectivity&&
>(in), edgeAlloc, edgeParitionsAlloc}
402 , Nodes{
static_cast<Nodes&&
>(in)}
410 requires (!enableNodeAllocation<node_weight_type>)
412 : Connectivity{
static_cast<Connectivity&&
>(in), edgeAlloc}
413 , Nodes{
static_cast<Nodes&&
>(in)}
423 noexcept(
noexcept(this->Connectivity::swap(rhs)) &&
noexcept(this->Nodes::swap(rhs)))
425 Connectivity::swap(rhs);
429 void reserve_nodes(
const size_type size)
431 if constexpr(!std::is_empty_v<node_weight_type>)
433 Nodes::reserve(size);
436 Connectivity::reserve_nodes(size);
440 size_type node_capacity()
const noexcept
442 if constexpr(!std::is_empty_v<node_weight_type>)
444 return std::ranges::min(Connectivity::node_capacity(), Nodes::capacity());
448 return Connectivity::node_capacity();
454 if constexpr(!std::is_empty_v<node_weight_type>)
456 Nodes::shrink_to_fit();
459 Connectivity::shrink_to_fit();
462 template<
class... Args>
463 size_type add_node(Args&&... args)
465 return insert_node(this->order(), std::forward<Args>(args)...);
468 template<
class... Args>
469 size_type insert_node(
const size_type pos, Args&&... args)
471 insertion_sentinel sentinel{*
this, pos};
473 return Connectivity::insert_node(insert_node_impl(pos, std::forward<Args>(args)...));
476 void erase_node(
const size_type node)
478 Connectivity::erase_node(node);
479 if constexpr (!std::is_empty_v<node_weight_type>) Nodes::erase_node(this->cbegin_node_weights() + node);
482 void clear()
noexcept
484 if constexpr (!std::is_empty_v<node_weight_type>) Nodes::clear();
485 Connectivity::clear();
488 template<tree_link_direction dir,
class... Args>
491 const auto n{insert_node(pos, std::forward<Args>(args)...)};
493 if(this->order() > 1)
495 if constexpr((dir != tree_link_direction::forward) && is_directed(Connectivity::flavour))
497 Connectivity::join(n, parent);
500 if constexpr(dir != tree_link_direction::backward)
502 Connectivity::join(parent, n);
509 template<tree_link_direction dir,
class... Args>
512 return insert_node_to_tree(tldc, this->order(), parent, std::forward<Args>(args)...);
515 class [[nodiscard]] insertion_sentinel
523 ~insertion_sentinel()
525 if constexpr(!std::is_empty_v<node_weight_type>)
527 if(
static_cast<Nodes&
>(m_Graph).size() >
static_cast<Connectivity&
>(m_Graph).order())
528 m_Graph.remove_excess_node(m_NodeIndex);
533 size_type m_NodeIndex{};
536 friend insertion_sentinel;
539 constexpr static const edges_initializer& check_initialization(
const edges_initializer& edges, std::size_t numNodes, std::size_t edgeParitions)
541 if(numNodes != edgeParitions)
542 throw std::logic_error{graph_errors::inconsistent_initialization_message(numNodes, edgeParitions)};
547 template<tree_link_direction dir>
548 requires (!heterogeneous_nodes<graph_primitive> && !std::is_empty_v<node_weight_type>)
551 if(root >= Connectivity::order()) root = add_node(tree.node);
553 for(
const auto& child : tree.children)
555 const auto n{add_node_to_tree(tdc, root, child.node)};
556 build_tree(n, child, tdc);
560 template<tree_link_direction dir>
561 requires (!heterogeneous_nodes<graph_primitive> && std::is_empty_v<node_weight_type>)
564 if(root >= Connectivity::order()) root = add_node();
566 for(
const auto& child : tree.children)
568 const auto n{add_node_to_tree(tdc, root)};
569 build_tree(n, child, tdc);
574 pseudo_iterator begin()
noexcept {
return {edge_index_type{}, *
this}; }
577 pseudo_iterator end()
noexcept {
return {Connectivity::order(), *
this}; }
579 template<
class... Args>
580 size_type insert_node_impl(
const size_type pos, Args&&... args)
582 const auto node{std::ranges::min(pos, this->order())};
583 if constexpr (!std::is_empty_v<node_weight_type>)
585 Nodes::insert_node(this->cbegin_node_weights() + node, std::forward<Args>(args)...);
591 void remove_excess_node(size_type index)
593 if(!std::is_empty_v<node_weight_type>)
595 Nodes::erase_node(this->cbegin_node_weights() + index);
A collection of constexpr algorithms.
constexpr void sort(Iter begin, Iter end, Comp comp={}, Proj proj={})
Definition: Algorithms.hpp:79
Helper for dealing with allocator propagation during copy assignment.
Implementation for a partitioned sequence of edges, which represents a graph's connectivity.
Traits and Concepts for graphs.
Definition: GraphPrimitive.hpp:30
Definition: GraphPrimitive.hpp:107
An iterator with policies controlling dereferencing and auxiliary data.
Definition: Iterator.hpp:234
A concept for allocators.
Definition: Concepts.hpp:48
Definition: GraphPrimitive.hpp:84
Definition: GraphPrimitive.hpp:99