remove \r
[extl.git] / extl / container / net_base.h
blob0ebbde2a7f0d4b754ecb6a394b7b68db53982770
1 /* ///////////////////////////////////////////////////////////////////////
2 * File: net_base.h
4 * Created: 08.11.27
5 * Updated: 08.11.27
7 * Brief: The net_base class - compact net
9 * [<Home>]
10 * Copyright (c) 2008-2020, Waruqi All rights reserved.
11 * //////////////////////////////////////////////////////////////////// */
13 #ifndef EXTL_CONTAINER_NET_BASE_H
14 #define EXTL_CONTAINER_NET_BASE_H
16 /*!\file net_base.h
17 * \brief net_base class
20 /* ///////////////////////////////////////////////////////////////////////
21 * Includes
23 #include "prefix.h"
24 #include "detail/net_base_impl.h"
25 #include "detail/net_node_iterator.h"
26 #include "detail/net_arc_iterator.h"
27 /* ///////////////////////////////////////////////////////////////////////
28 * ::extl namespace
30 EXTL_BEGIN_NAMESPACE
33 /*!brief net_base
35 * \param is_dir returns \true if it's a directed net
36 * \param Nods the nodes type
37 * \param Mtx1 the adjacent matrix type for directed net
38 * \param Mtx2 the adjacent matrix type for indirected net - symmetrical matrix
40 * \ingroup extl_group_container
42 template< typename_param_k Dev
43 , e_bool_t is_dir
44 , typename_param_k Nods
45 , typename_param_k Mtx1
46 , typename_param_k Mtx2
48 class net_base
49 : public EXTL_NS_DETAIL(net_base_impl)<is_dir>::template_qual_k impl< Dev
50 , Nods
51 , Mtx1
52 , Mtx2
55 /// \name Protected Types
56 /// @{
57 protected:
58 typedef typename_type_k EXTL_NS_DETAIL(net_base_impl)<is_dir>::
59 template_qual_k impl< Dev
60 , Nods
61 , Mtx1
62 , Mtx2
63 > base_type;
64 typedef Dev derived_type;
65 typedef typename_type_k base_type::adjmtx_type adjmtx_type;
66 typedef typename_type_k base_type::node_type node_type;
67 typedef typename_type_k base_type::nodes_type nodes_type;
68 typedef typename_type_k base_type::arc_type arc_type;
69 typedef typename_type_k base_type::weight_type weight_type;
70 #ifdef EXTL_TYPE_ALIAS_FRIEND_SUPPORT
71 friend base_type;
72 #endif
73 /// @}
75 /// \name Public Types
76 /// @{
77 public:
78 typedef net_base class_type;
79 typedef typename_type_k base_type::value_type value_type;
80 typedef typename_type_k base_type::pointer pointer;
81 typedef typename_type_k base_type::const_pointer const_pointer;
82 typedef typename_type_k base_type::reference reference;
83 typedef typename_type_k base_type::const_reference const_reference;
84 typedef typename_type_k base_type::size_type size_type;
85 typedef typename_type_k base_type::bool_type bool_type;
86 typedef typename_type_k base_type::difference_type difference_type;
87 typedef typename_type_k base_type::int_type int_type;
88 typedef typename_type_k base_type::index_type index_type;
90 // const_node_iterator
91 typedef EXTL_NS_DETAIL(const_net_node_iterator)<nodes_type> const_node_iterator;
92 typedef const_reverse_bidirectional_iterator_base<const_node_iterator> const_reverse_node_iterator;
94 // const_arc_iterator
95 typedef EXTL_NS_DETAIL(const_net_arc_iterator)<adjmtx_type> const_arc_iterator;
96 typedef const_reverse_bidirectional_iterator_base<const_arc_iterator> const_reverse_arc_iterator;
97 /// @}
99 /// \name Constants
100 /// @{
101 public:
102 EXTL_STATIC_MEMBER_CONST(bool_type, is_directed = is_dir);
103 /// @}
105 /// \name Members
106 /// @{
107 protected:
108 nodes_type m_nodes;
109 adjmtx_type m_adjmtx;
110 size_type m_arcs_n;
111 size_type m_nodes_n;
112 /// @}
114 private:
115 net_base(class_type const& rhs);
116 class_type& operator =(class_type& rhs);
118 /// \name Constructors
119 /// @{
120 public:
121 explicit_k net_base(size_type max_nodes_n)
122 : m_nodes(max_nodes_n)
123 , m_adjmtx(max_nodes_n, max_nodes_n)
124 , m_arcs_n(0)
125 , m_nodes_n(0)
127 derive().clear();
128 EXTL_ASSERT(derive().is_valid());
130 net_base(derived_type const& rhs)
131 : m_nodes(rhs.nodes())
132 , m_adjmtx(rhs.adjmtx())
133 , m_arcs_n(rhs.arcs_size())
134 , m_nodes_n(rhs.nodes_size())
136 EXTL_ASSERT(derive().is_valid());
138 /// @}
140 /// \name Attributes
141 /// @{
142 public:
143 size_type nodes_size() const { return m_nodes_n; }
144 size_type size() const { return derive().nodes_size(); }
145 size_type arcs_size() const { return m_arcs_n; }
146 bool_type is_empty() const { return nodes().is_empty(); }
147 bool_type empty() const { return derive().is_empty(); }
148 size_type max_nodes_size() const { return nodes().size(); }
149 size_type max_size() const { return derive().max_nodes_size(); }
150 size_type max_arcs_size() const { return derive().max_arcs_size_impl(); }
151 bool_type is_valid() const;
152 /// @}
154 /// \name Mutators
155 /// @{
156 public:
157 void clear();
158 void swap(derived_type& rhs);
159 derived_type& operator =(derived_type& rhs);
161 derived_type& insert_arc(index_type bid, index_type eid, weight_type w = weight_type());
162 derived_type& remove_arc(index_type bid, index_type eid);
164 derived_type& insert_node(index_type id, const_reference val = value_type());
165 derived_type& remove_node(index_type id);
166 /// @}
168 /// \name Accessors
169 /// @{
170 public:
171 bool_type node_exists(index_type id) const;
172 bool_type arc_exists(index_type bid, index_type eid) const;
174 const_reference at(index_type id) const { return node_at(id).value(); }
175 reference at(index_type id) { return node_at(id).value(); }
177 weight_type const& weight(index_type bid, index_type eid) const { return derive().adjmtx_at(bid, eid).weight(); }
178 weight_type& weight(index_type bid, index_type eid) { return derive().adjmtx_at(bid, eid).weight(); }
180 size_type degree(index_type id) const { return node_at(id).degree(); }
181 /// @}
183 /// \name Node Iterators
184 /// \note cannot insert and erase nodes in the iteration
185 /// @{
186 public:
187 const_node_iterator node_begin() const { return const_node_iterator(nodes().begin(), nodes()); }
188 const_node_iterator node_end() const { return const_node_iterator(nodes().end(), nodes()); }
190 const_reverse_node_iterator node_rbegin() const { return const_reverse_node_iterator(node_end()); }
191 const_reverse_node_iterator node_rend() const { return const_reverse_node_iterator(node_begin()); }
192 /// @}
194 /// \name Arc Iterators
195 /// \note cannot insert and erase arcs in the iteration
196 /// @{
197 public:
198 const_arc_iterator arc_begin() const { return const_arc_iterator(adjmtx().begin(), adjmtx()); }
199 const_arc_iterator arc_end() const { return const_arc_iterator(adjmtx().end(), adjmtx()); }
201 const_reverse_arc_iterator arc_rbegin() const { return const_reverse_arc_iterator(arc_end()); }
202 const_reverse_arc_iterator arc_rend() const { return const_reverse_arc_iterator(arc_begin()); }
203 /// @}
205 /// \name Protected Accessors
206 /// @{
207 #ifdef EXTL_TYPE_ALIAS_FRIEND_SUPPORT
208 protected:
209 #else
210 public:
211 #endif
212 nodes_type& nodes() { return m_nodes; }
213 nodes_type const& nodes() const { return m_nodes; }
215 adjmtx_type& adjmtx() { return m_adjmtx; }
216 adjmtx_type const& adjmtx() const { return m_adjmtx; }
217 /// @}
219 /// \name Protected Unsafe Mutators
220 /// @{
221 #ifdef EXTL_TYPE_ALIAS_FRIEND_SUPPORT
222 protected:
223 #else
224 public:
225 #endif
226 void unsafe_insert_arc(index_type bid, index_type eid, weight_type w);
227 void unsafe_remove_arc(index_type bid, index_type eid);
228 void unsafe_insert_node(index_type id, const_reference val);
229 void unsafe_remove_node(index_type id);
230 /// @}
232 /// \name Helpers
233 /// @{
234 #ifdef EXTL_TYPE_ALIAS_FRIEND_SUPPORT
235 protected:
236 #else
237 public:
238 #endif
239 void clear_nodes();
240 void clear_adjmtx();
242 node_type& node_at(index_type id);
243 node_type const& node_at(index_type id) const;
245 node_type& node_at_uncheck(index_type id);
246 node_type const& node_at_uncheck(index_type id) const;
248 arc_type& adjmtx_at(index_type bid, index_type eid);
249 arc_type const& adjmtx_at(index_type bid, index_type eid) const;
251 arc_type& adjmtx_at_uncheck(index_type bid, index_type eid);
252 arc_type const& adjmtx_at_uncheck(index_type bid, index_type eid) const;
254 derived_type& derive() { return static_cast<derived_type&>(*this); }
255 derived_type const& derive() const { return static_cast<derived_type const&>(*this); }
256 /// @}
259 /* ///////////////////////////////////////////////////////////////////////
260 * Macro
262 // Template declaration
263 #ifdef EXTL_NET_BASE_TEMPLATE_DECL
264 # undef EXTL_NET_BASE_TEMPLATE_DECL
265 #endif
267 #define EXTL_NET_BASE_TEMPLATE_DECL \
268 template< typename_param_k Dev \
269 , e_bool_t is_dir \
270 , typename_param_k Nods \
271 , typename_param_k Mtx1 \
272 , typename_param_k Mtx2 \
275 // Class qualification
276 #ifdef EXTL_NET_BASE_QUAL
277 # undef EXTL_NET_BASE_QUAL
278 #endif
280 #define EXTL_NET_BASE_QUAL net_base<Dev, is_dir, Nods, Mtx1, Mtx2>
282 // Class qualification
283 #ifdef EXTL_NET_BASE_RET_QUAL
284 # undef EXTL_NET_BASE_RET_QUAL
285 #endif
287 #define EXTL_NET_BASE_RET_QUAL(ret_type) \
288 typename_type_ret_k EXTL_NET_BASE_QUAL::ret_type \
289 EXTL_NET_BASE_QUAL
291 /* ///////////////////////////////////////////////////////////////////////
292 * Implementation
295 EXTL_NET_BASE_TEMPLATE_DECL
296 inline void EXTL_NET_BASE_QUAL::unsafe_insert_node(index_type id, const_reference val)
298 // note: too slowly
299 //EXTL_ASSERT(derive().is_valid());
300 if (!derive().node_exists(id)) // insert node if not exists
302 derive().node_at_uncheck(id) = node_type(id, val);
303 ++m_nodes_n;
305 else // update node if exists
307 EXTL_ASSERT(id == derive().node_at_uncheck(id).id());
308 derive().node_at_uncheck(id) = node_type(id, val);
311 //EXTL_ASSERT(derive().is_valid());
313 EXTL_NET_BASE_TEMPLATE_DECL
314 inline void EXTL_NET_BASE_QUAL::unsafe_remove_node(index_type id)
316 if (!derive().node_exists(id)) return;
318 //EXTL_ASSERT(derive().is_valid());
320 derive().node_at_uncheck(id).clear();
321 --m_nodes_n;
323 EXTL_ASSERT(!derive().node_exists(id));
324 //EXTL_ASSERT(derive().is_valid());
326 EXTL_NET_BASE_TEMPLATE_DECL
327 inline void EXTL_NET_BASE_QUAL::unsafe_insert_arc(index_type bid, index_type eid, weight_type w)
329 //EXTL_ASSERT(derive().is_valid());
331 if (!derive().arc_exists(bid, eid)) // insert arc if not exists
333 derive().adjmtx_at_uncheck(bid, eid) = arc_type(bid, eid, w);
334 derive().inc_degree(bid, eid);
335 ++m_arcs_n;
337 else // update arc if exists
339 derive().adjmtx_at_uncheck(bid, eid) = arc_type(bid, eid, w);
342 //EXTL_ASSERT(derive().is_valid());
344 EXTL_NET_BASE_TEMPLATE_DECL
345 inline void EXTL_NET_BASE_QUAL::unsafe_remove_arc(index_type bid, index_type eid)
347 if (!derive().arc_exists(bid, eid)) return ;
349 //EXTL_ASSERT(derive().is_valid());
351 derive().adjmtx_at_uncheck(bid, eid).clear();
352 derive().dec_degree(bid, eid);
353 --m_arcs_n;
355 EXTL_ASSERT(!derive().arc_exists(bid, eid));
356 //EXTL_ASSERT(derive().is_valid());
359 EXTL_NET_BASE_TEMPLATE_DECL
360 inline EXTL_NET_BASE_RET_QUAL(derived_type&)::insert_arc(index_type bid, index_type eid, weight_type w)
362 EXTL_ASSERT(derive().is_valid());
363 size_type step = 0;
365 EXTL_TRY
366 // insert it at first if node not exist
367 if (derive().node_at_uncheck(bid).is_empty())
369 derive().unsafe_insert_node(bid, value_type());
370 step = 1;
373 if (derive().node_at_uncheck(eid).is_empty())
375 derive().unsafe_insert_node(eid, value_type());
376 step = 2;
378 // insert arc
379 unsafe_insert_arc(bid, eid, w);
380 EXTL_CATCH_ALL
381 switch (step)
383 case 2:
384 derive().unsafe_remove_node(eid);
385 case 1:
386 derive().unsafe_remove_node(bid);
387 default:
388 break;
390 // reraise
391 EXTL_THROW;
392 EXTL_CATCH_END
394 EXTL_ASSERT(derive().is_valid());
395 return derive();
397 EXTL_NET_BASE_TEMPLATE_DECL
398 inline EXTL_NET_BASE_RET_QUAL(derived_type&)::remove_arc(index_type bid, index_type eid)
400 EXTL_ASSERT(derive().is_valid());
401 derive().unsafe_remove_arc(bid, eid);
402 EXTL_ASSERT(derive().is_valid());
403 return derive();
405 EXTL_NET_BASE_TEMPLATE_DECL
406 inline EXTL_NET_BASE_RET_QUAL(derived_type&)::insert_node(index_type id, const_reference val)
408 EXTL_ASSERT(derive().is_valid());
409 derive().unsafe_insert_node(id, val);
410 EXTL_ASSERT(derive().is_valid());
411 return derive();
414 EXTL_NET_BASE_TEMPLATE_DECL
415 inline EXTL_NET_BASE_RET_QUAL(derived_type&)::remove_node(index_type id)
417 EXTL_ASSERT(derive().is_valid());
418 #ifdef EXTL_EXCEPTION_ENABLE
419 // need erase arcs in the vicinity of the node at first
420 derived_type tmp(derive());
421 tmp.safe_remove_node(id);
422 tmp.swap(derive());
423 #else
424 derive().safe_remove_node(id);
425 #endif
426 EXTL_ASSERT(derive().is_valid());
427 return derive();
430 EXTL_NET_BASE_TEMPLATE_DECL
431 inline void EXTL_NET_BASE_QUAL::clear_nodes()
433 typedef typename_type_k nodes_type::iterator node_iterator_;
434 for (node_iterator_ pn = nodes().begin(); pn != nodes().end(); ++pn)
435 (*pn).clear();
438 EXTL_NET_BASE_TEMPLATE_DECL
439 inline void EXTL_NET_BASE_QUAL::clear_adjmtx()
441 typedef typename_type_k adjmtx_type::iterator arc_iterator_;
442 for (arc_iterator_ pa = adjmtx().begin(); pa != adjmtx().end(); ++pa)
443 (*pa).clear();
446 EXTL_NET_BASE_TEMPLATE_DECL
447 inline void EXTL_NET_BASE_QUAL::clear()
449 derive().clear_nodes();
450 derive().clear_adjmtx();
452 m_arcs_n = 0;
453 m_nodes_n = 0;
455 EXTL_ASSERT(derive().is_valid());
458 EXTL_NET_BASE_TEMPLATE_DECL
459 inline void EXTL_NET_BASE_QUAL::swap(derived_type& rhs)
461 EXTL_ASSERT(derive().is_valid());
462 nodes().swap(static_cast<class_type&>(rhs).m_nodes);
463 adjmtx().swap(static_cast<class_type&>(rhs).m_adjmtx);
464 std_swap(m_arcs_n, static_cast<class_type&>(rhs).m_arcs_n);
465 std_swap(m_nodes_n, static_cast<class_type&>(rhs).m_nodes_n);
466 EXTL_ASSERT(derive().is_valid());
469 EXTL_NET_BASE_TEMPLATE_DECL
470 inline EXTL_NET_BASE_RET_QUAL(derived_type&)::operator =(derived_type& rhs)
472 EXTL_ASSERT(derive().is_valid());
473 derived_type(rhs).swap(derive());
474 EXTL_ASSERT(derive().is_valid());
475 return derive();
477 EXTL_NET_BASE_TEMPLATE_DECL
478 inline EXTL_NET_BASE_RET_QUAL(node_type const&)::node_at(index_type id) const
480 EXTL_MESSAGE_ASSERT(id < nodes().size(), "out of range");
481 EXTL_ASSERT_THROW(id < nodes().size(), "out of range");
483 EXTL_MESSAGE_ASSERT(!nodes()[id].is_empty(), "node not exists");
484 EXTL_ASSERT_THROW(!nodes()[id].is_empty(), "node not exists");
486 return nodes()[id];
488 EXTL_NET_BASE_TEMPLATE_DECL
489 inline EXTL_NET_BASE_RET_QUAL(node_type&)::node_at(index_type id)
491 return const_cast<node_type&>(static_cast<derived_type const&>(*this).node_at(id));
493 EXTL_NET_BASE_TEMPLATE_DECL
494 inline EXTL_NET_BASE_RET_QUAL(node_type const&)::node_at_uncheck(index_type id) const
496 EXTL_MESSAGE_ASSERT(id < nodes().size(), "out of range");
497 return nodes()[id];
499 EXTL_NET_BASE_TEMPLATE_DECL
500 inline EXTL_NET_BASE_RET_QUAL(node_type&)::node_at_uncheck(index_type id)
502 return const_cast<node_type&>(static_cast<derived_type const&>(*this).node_at_uncheck(id));
505 EXTL_NET_BASE_TEMPLATE_DECL
506 inline EXTL_NET_BASE_RET_QUAL(arc_type&)::adjmtx_at(index_type bid, index_type eid)
508 return const_cast<arc_type&>(static_cast<derived_type const&>(*this).adjmtx_at(bid, eid));
510 EXTL_NET_BASE_TEMPLATE_DECL
511 inline EXTL_NET_BASE_RET_QUAL(arc_type const&)::adjmtx_at(index_type bid, index_type eid) const
513 EXTL_MESSAGE_ASSERT ( bid < adjmtx().dim0()
514 && eid < adjmtx().dim1()
515 , "adjmtx_at: out of range");
517 EXTL_ASSERT_THROW ( bid < adjmtx().dim0()
518 && eid < adjmtx().dim1()
519 , "adjmtx_at: out of range");
521 EXTL_MESSAGE_ASSERT ( derive().arc_exists(bid, eid)
522 , "adjmtx_at: arc not exist");
524 EXTL_ASSERT_THROW ( derive().arc_exists(bid, eid)
525 , "adjmtx_at: arc not exist");
528 return adjmtx().at(bid, eid);
530 EXTL_NET_BASE_TEMPLATE_DECL
531 inline EXTL_NET_BASE_RET_QUAL(arc_type&)::adjmtx_at_uncheck(index_type bid, index_type eid)
533 return const_cast<arc_type&>(static_cast<derived_type const&>(*this).adjmtx_at_uncheck(bid, eid));
535 EXTL_NET_BASE_TEMPLATE_DECL
536 inline EXTL_NET_BASE_RET_QUAL(arc_type const&)::adjmtx_at_uncheck(index_type bid, index_type eid) const
538 EXTL_MESSAGE_ASSERT ( bid < adjmtx().dim0()
539 && eid < adjmtx().dim1()
540 , "adjmtx_at: out of range");
542 // note: can not call arc_exists(bid, eid) at this.
543 // note: can not call is_valid() at this.
545 return adjmtx().at(bid, eid);
548 EXTL_NET_BASE_TEMPLATE_DECL
549 inline EXTL_NET_BASE_RET_QUAL(bool_type)::node_exists(index_type id) const
551 if (!(id < nodes().size())) return e_false_v;
552 return !node_at_uncheck(id).is_empty();
554 EXTL_NET_BASE_TEMPLATE_DECL
555 inline EXTL_NET_BASE_RET_QUAL(bool_type)::arc_exists(index_type bid, index_type eid) const
557 // note: can not call is_valid() at this.
558 if (!(bid < adjmtx().dim0() && eid < adjmtx().dim1()))
559 return e_false_v;
560 return !this->adjmtx_at_uncheck(bid, eid).is_empty();
563 EXTL_NET_BASE_TEMPLATE_DECL
564 inline EXTL_NET_BASE_RET_QUAL(bool_type)::is_valid() const
566 size_type n0 = adjmtx().dim0();
567 size_type n1 = adjmtx().dim1();
569 if (n0 != n1) return e_false_v;
570 if (derive().nodes_size() > derive().max_nodes_size()) return e_false_v;
571 if (derive().arcs_size() > derive().max_arcs_size()) return e_false_v;
573 for (index_type i = 0; i < n0; ++i)
575 for (index_type j = 0; j < n1; ++j)
577 if (!derive().arc_exists(i, j)) continue;
579 // invariance of arc
580 if (!adjmtx().at(i, j).is_valid())
581 return e_false_v;
583 // out of range
584 if ( adjmtx().at(i, j).begin_id() >= nodes().size()
585 || adjmtx().at(i, j).end_id() >= nodes().size())
586 return e_false_v;
588 // non-consistency
589 if (is_directed)
591 if (adjmtx().at(i, j).begin_id() != i || adjmtx().at(i, j).end_id() != j)
592 return e_false_v;
594 else
596 if ((adjmtx().at(i, j).begin_id() != i && adjmtx().at(i, j).begin_id() != j)
597 || (adjmtx().at(i, j).end_id() != i && adjmtx().at(i, j).end_id() != j))
598 return e_false_v;
601 // null ----> end
602 if (nodes()[adjmtx().at(i, j).begin_id()].is_empty())
603 return e_false_v;
605 // start ---> null
606 if (nodes()[adjmtx().at(i, j).end_id()].is_empty())
607 return e_false_v;
611 return e_true_v;
614 /* //////////////////////////////////////////////////////////////////// */
615 #undef EXTL_NET_BASE_TEMPLATE_DECL
616 #undef EXTL_NET_BASE_QUAL
617 #undef EXTL_NET_BASE_RET_QUAL
619 /* ///////////////////////////////////////////////////////////////////////
620 * ::extl namespace
622 EXTL_END_NAMESPACE
624 /* //////////////////////////////////////////////////////////////////// */
625 #endif /* EXTL_CONTAINER_NET_BASE_H */
626 /* //////////////////////////////////////////////////////////////////// */