1 // Copyright (c) 2003,2004,2005  INRIA Sophia-Antipolis (France).
2 // All rights reserved.
3 //
4 // This file is part of CGAL (www.cgal.org).
5 //
6 // $URL: https://github.com/CGAL/cgal/blob/v5.3/TDS_2/include/CGAL/internal/TDS_2/edge_list.h $
7 // $Id: edge_list.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot
8 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
9 //
10 //
11 // Author(s)     : Menelaos Karavelas <mkaravel@iacm.forth.gr>
12 
13 #ifndef CGAL_INTERNAL_TDS_2_EDGE_LIST_H
14 #define CGAL_INTERNAL_TDS_2_EDGE_LIST_H
15 
16 #include <CGAL/license/TDS_2.h>
17 
18 #include <CGAL/Unique_hash_map.h>
19 #include <CGAL/internal/TDS_2/Edge_hash_function.h>
20 #include <CGAL/circulator_bases.h>
21 
22 namespace CGAL {
23 
24 
25 namespace internal {
26 
27   template<class Edge_t>
28   class Edge_list_item
29   {
30   public:
31     typedef Edge_t                      Edge;
32 
33   private:
34     typedef typename Edge::first_type   Face_handle;
35 
36   private:
37     Edge prev_;
38     Edge next_;
39 
40   public:
41     // remove the following method and make SENTINEL_EDGE a static const
42     // member of the class.
sentinel_edge()43     static Edge sentinel_edge() {
44       return Edge(Face_handle(), sentinel_index());
45     }
46 
47   private:
sentinel_index()48     static int sentinel_index() { return -1; }
49 
50   public:
Edge_list_item()51     Edge_list_item()
52       : prev_(sentinel_edge()), next_(sentinel_edge()) {}
Edge_list_item(const Edge & prev,const Edge & next)53     Edge_list_item(const Edge& prev, const Edge& next)
54       : prev_(prev), next_(next) {}
55 
56 
is_in_list()57     bool is_in_list() const
58     {
59       return ( next_.second != sentinel_index() ||
60                prev_.second != sentinel_index() );
61     }
62 
set_next(const Edge & next)63     void set_next(const Edge& next)
64     {
65       next_ = next;
66     }
67 
set_previous(const Edge & prev)68     void set_previous(const Edge& prev)
69     {
70       prev_ = prev;
71     }
72 
next()73     const Edge& next()     const { return next_; }
previous()74     const Edge& previous() const { return prev_; }
75 
reset()76     void reset() {
77       Edge SENTINEL_EDGE = sentinel_edge();
78       next_ = prev_ = SENTINEL_EDGE;
79     }
80   };
81 
82 
83 
84   template<class E_t, class ListItem, class USE_STL_MAP_Tag>
85   struct Edge_list_which_map;
86 
87   // use STL's map
88   template<class E_t, class ListItem>
89   struct Edge_list_which_map<E_t,ListItem,Tag_true>
90   {
91     typedef E_t                       Edge;
92     typedef ListItem                  List_item;
93     typedef std::map<Edge,List_item>  Edge_map;
94   };
95 
96   // use CGAL's Unique_hash_map
97   template<class E_t, class ListItem>
98   struct Edge_list_which_map<E_t,ListItem,Tag_false>
99   {
100     typedef E_t                         Edge;
101     typedef ListItem                    List_item;
102     typedef CGAL::Edge_hash_function    Hash_function;
103 
104     typedef Unique_hash_map<Edge,List_item,Hash_function>  Edge_map;
105   };
106 
107 
108   template<class Edge_list_t>
109   class Edge_list_circulator
110     : public CGAL::Bidirectional_circulator_base<typename Edge_list_t::Edge>
111   {
112   private:
113     typedef Edge_list_t                                 List;
114     typedef typename List::Edge                         Edge;
115     typedef Edge_list_item<Edge>                        List_item;
116     typedef CGAL::Bidirectional_circulator_base<Edge>   Base;
117 
118     typedef Edge_list_circulator<List>                  Self;
119 
120   public:
121     typedef typename Base::pointer     pointer;
122     typedef typename Base::reference   reference;
123 
124   public:
125     Edge_list_circulator()
126       : l_(nullptr), c_(List_item::sentinel_edge()) {}
127 
128     Edge_list_circulator(const List* l, const Edge& c)
129       : l_(l), c_(/*const_cast<Edge&>(*/c/*)*/) {}
130 
131     Edge_list_circulator(const Edge_list_circulator& other)
132       : l_(other.l_), c_(other.c_) {}
133 
134     Edge_list_circulator& operator=(const Edge_list_circulator& other) {
135       l_ = other.l_;
136       c_ = other.c_;
137       return *this;
138     }
139 
140     Self& operator++() {
141       CGAL_precondition( l_ != nullptr );
142       //      c_ = const_cast<Edge&>(l_->next(c_));
143       c_ = l_->next(c_);
144       return *this;
145     }
146 
147     Self& operator--() {
148       CGAL_precondition( l_ != nullptr );
149       //      c_ = const_cast<Edge&>(l_->previous(c_));
150       c_ = l_->previous(c_);
151       return *this;
152     }
153 
154     Self operator++(int) {
155       Self tmp(*this);
156       ++(*this);
157       return tmp;
158     }
159 
160     Self operator--(int) {
161       Self tmp(*this);
162       --(*this);
163       return tmp;
164     }
165 
166     pointer   operator->() { return &c_; }
167     reference operator*() { return c_; }
168 
169     bool operator==(const Self& other) const {
170       CGAL_assertion( l_ == other.l_ );
171       return c_ == other.c_;
172     }
173 
174     bool operator!=(const Self& other) const {
175       CGAL_assertion( l_ == other.l_ );
176       return c_ != other.c_;
177     }
178 
179   protected:
180     const List* l_;
181     //    Edge& c_;
182     Edge c_;
183   };
184 
185 
186   template<class L>
187   class Edge_list_iterator
188   {
189     typedef L                               Edge_list;
190     typedef typename Edge_list::Edge        Edge;
191     typedef Edge_list_iterator<Edge_list>   Self;
192 
193   public:
194     typedef Edge*  pointer;
195     typedef Edge&  reference;
196 
197   public:
198     Edge_list_iterator() {}
199 
200     Edge_list_iterator(const Edge_list* l, const Edge& e, unsigned int idx)
201       : l(l), e(e), idx(idx) {}
202 
203     Edge_list_iterator(const Self& other)
204     {
205       l = other.l;
206       e = other.e;
207       idx = other.idx;
208     }
209 
210     Self& operator=(const Self& other)
211     {
212       l = other.l;
213       e = other.e;
214       idx = other.idx;
215       return *this;
216     }
217 
218     // pre-increment
219     Self& operator++() {
220       ++idx;
221       e = l->next(e);
222       return *this;
223     }
224 
225     // post-increment
226     Self operator++(int) {
227       Self tmp(*this);
228       ++(*this);
229       return tmp;
230     }
231 
232     Self& operator--() {
233       --idx;
234       e = l->previous(e);
235       return *this;
236     }
237 
238     Self operator--(int) {
239       Self tmp(*this);
240       --(*this);
241       return tmp;
242     }
243 
244     pointer    operator->() { return &e; }
245     reference  operator*()  { return e; }
246 
247 
248     bool operator==(const Self& other) const {
249       CGAL_assertion( l == other.l );
250       return idx == other.idx;
251     }
252 
253     bool operator!=(const Self& other) const {
254       CGAL_assertion( l == other.l );
255       return idx != other.idx;
256     }
257 
258   private:
259     const Edge_list* l;
260     Edge e;
261     unsigned int idx;
262   };
263 
264 
265 } // namespace internal
266 
267 
268 
269 template<class Edge_t, class USE_STL_MAP_Tag = Tag_true>
270 class Edge_list
271 {
272 public:
273   // TYPES
274   //======
275   typedef std::size_t       size_type;
276   typedef Edge_t            Edge;
277   typedef USE_STL_MAP_Tag   Use_stl_map_tag;
278 
279 private:
280   typedef internal::Edge_list_item<Edge>  List_item;
281 
282   typedef
283   internal::Edge_list_which_map<Edge,List_item,Use_stl_map_tag>
284   Which_map;
285 
286   typedef typename Which_map::Edge_map  Edge_map;
287 
288   typedef Edge_list<Edge,Use_stl_map_tag>  Self;
289 
290 public:
291   typedef internal::Edge_list_circulator<Self>  circulator;
292   typedef internal::Edge_list_iterator<Self>    iterator;
293 
294 private:
295   // PRIVATE DATA MEMBERS
296   //=====================
297   Edge_map             emap;
298   Edge                 front_;
299   size_type            size_;
300 
301 private:
302   // PRIVATE METHODS
303   //================
304   void increase_size() {
305     size_++;
306   }
307 
308   void decrease_size() {
309     size_--;
310   }
311 
312   void insert_before_nocheck(const Edge& e, const Edge& new_e) {
313     List_item& li_e = emap[e];
314 
315     const Edge& prev_e = li_e.previous();
316     List_item& li_prev_e = emap[prev_e];
317 
318     emap[new_e] = List_item(prev_e, e);
319     li_e.set_previous(new_e);
320     li_prev_e.set_next(new_e);
321     increase_size();
322   }
323 
324   // check whether the edge is in the list;
325   // the map used is STL's map
326   bool is_in_list_with_tag(const Edge& e, const Tag_true&) const
327   {
328     if ( emap.find(e) == emap.end() ) { return false; }
329     return emap.find(e)->second.is_in_list();
330   }
331 
332   // check whether the edge is in the list;
333   // the map used is CGAL's Unique_hash_map
334   bool is_in_list_with_tag(const Edge& e, const Tag_false&) const
335   {
336     if ( !emap.is_defined(e) ) { return false; }
337     return emap[e].is_in_list();
338   }
339 
340   // return the next edge in the list;
341   // the map used is STL's map
342   const Edge& next_with_tag(const Edge& e, const Tag_true&) const
343   {
344     return emap.find(e)->second.next();
345   }
346 
347   // return the next edge in the list;
348   // the map used is CGAL's Unique_hash_map
349   const Edge& next_with_tag(const Edge& e, const Tag_false&) const
350   {
351     return emap[e].next();
352   }
353 
354   // return the previous edge in the list;
355   // the map used is STL's map
356   const Edge& previous_with_tag(const Edge& e, const Tag_true&) const
357   {
358     return emap.find(e)->second.previous();
359   }
360 
361   // return the previous edge in the list;
362   // the map used is CGAL's Unique_hash_map
363   const Edge& previous_with_tag(const Edge& e, const Tag_false&) const
364   {
365     return emap[e].previous();
366   }
367 
368 public:
369   // CONSTRUCTOR
370   //============
371 #ifdef _MSC_VER
372   Edge_list(const Edge& e = Edge(typename Edge::first_type(),-1) )
373     : emap(), front_(e), size_(0) {}
374 #else
375   Edge_list(const Edge& e = List_item::sentinel_edge() )
376     : emap(), front_(e), size_(0) {}
377 #endif
378 
379   // PREDICATES
380   //===========
381   bool is_valid() const { return true; }
382 
383   bool is_in_list(const Edge& e) const {
384     Use_stl_map_tag  map_tag;
385     return is_in_list_with_tag(e, map_tag);
386   }
387 
388 
389   // ACCESS METHODS
390   //===============
391   size_type size() const {
392     return size_;
393   }
394 
395   const Edge& next(const Edge& e) const {
396     CGAL_precondition( is_in_list(e) );
397     Use_stl_map_tag  map_tag;
398     return next_with_tag(e, map_tag);
399   }
400 
401   const Edge& previous(const Edge& e) const {
402     CGAL_precondition( is_in_list(e) );
403     Use_stl_map_tag  map_tag;
404     return previous_with_tag(e, map_tag);
405   }
406 
407   const Edge& front() const {
408     CGAL_precondition( size() > 0 );
409     return front_;
410   }
411 
412   const Edge& back() const {
413     CGAL_precondition( size() > 0 );
414     return previous(front_);
415   }
416 
417 
418   // INSERTION
419   //==========
420   void push_front(const Edge& e) {
421     push_back(e);
422     front_ = e;
423   }
424 
425   void push_back(const Edge& e) {
426     CGAL_precondition( !is_in_list(e) );
427 
428     if ( size() == 0 ) {
429       emap[e] = List_item(e,e);
430       front_ = e;
431       increase_size();
432       return;
433     }
434 
435     insert_before_nocheck(front_, e);
436   }
437 
438   void insert_after(const Edge& e, const Edge& new_e) {
439     CGAL_precondition( is_in_list(e) );
440     CGAL_precondition( !is_in_list(new_e) );
441 
442     List_item& li_e = emap[e];
443 
444     const Edge& next_e = li_e.next();
445     List_item& li_next_e = emap[next_e];
446 
447     emap[new_e] = List_item(e, next_e);
448     li_e.set_next(new_e);
449     li_next_e.set_previous(new_e);
450     increase_size();
451   }
452 
453   void insert_before(const Edge& e, const Edge& new_e) {
454     CGAL_precondition( is_in_list(e) );
455     CGAL_precondition( !is_in_list(new_e) );
456     insert_before_nocheck(e, new_e);
457   }
458 
459 
460   // REPLACEMENT
461   //============
462   void replace(const Edge& e, const Edge& new_e) {
463     CGAL_precondition( is_in_list(e) );
464     CGAL_precondition( !is_in_list(new_e) );
465 
466     List_item& li_e = emap[e];
467 
468     if ( size() == 1 ) {
469       emap[new_e] = List_item(new_e, new_e);
470       front_ = new_e;
471       li_e.reset();
472     }
473 
474     const Edge& next_e = li_e.next();
475     const Edge& prev_e = li_e.previous();
476 
477     emap[prev_e].set_next(new_e);
478     emap[next_e].set_previous(new_e);
479 
480     emap[new_e] = List_item(prev_e, next_e);
481 
482     li_e.reset();
483 
484     if ( e == front_ ) {
485       front_ = new_e;
486     }
487   }
488 
489 
490   // REMOVAL
491   //========
492 
493   void remove(const Edge& e) {
494     CGAL_precondition( is_in_list(e) );
495 
496     if ( size() == 1 ) {
497       front_ = List_item::sentinel_edge();
498       emap[e].reset();
499       decrease_size();
500       return;
501     }
502 
503     List_item& li_e = emap[e];
504     const Edge& next_e = li_e.next();
505     const Edge& prev_e = li_e.previous();
506 
507     emap[prev_e].set_next(next_e);
508     emap[next_e].set_previous(prev_e);
509 
510     if ( e == front_ ) {
511       //      front_ = next_e;
512       front_ = next_e;
513     }
514 
515     li_e.reset();
516 
517     decrease_size();
518   }
519 
520 #if 0
521   // ACCESS TO CIRCULATOR
522   //=====================
523   inline circulator start() const {
524     return start(front());
525   }
526 
527   inline circulator start(const Edge& start) const {
528     CGAL_precondition( is_in_list(start) );
529     return circulator(this, start);
530   }
531 #endif
532   // ACCESS TO ITERATOR
533   //===================
534   iterator begin() const {
535     return iterator(this, front(), 0);
536   }
537 
538   iterator end() const {
539     return iterator(this, front(), size());
540   }
541 
542 
543   // MISCELLANEOUS
544   //==============
545   void clear() {
546     emap.clear();
547   }
548 };
549 
550 } //namespace CGAL
551 
552 
553 #endif // CGAL_INTERNAL_TDS_2_EDGE_LIST_H
554