Aleph-w  1.9
General library for algorithms and data structures
dlink.H
1 
2 /* Aleph-w
3 
4  / \ | | ___ _ __ | |__ __ __
5  / _ \ | |/ _ \ '_ \| '_ \ ____\ \ /\ / / Data structures & Algorithms
6  / ___ \| | __/ |_) | | | |_____\ V V / version 1.9b
7  /_/ \_\_|\___| .__/|_| |_| \_/\_/ https://github.com/lrleon/Aleph-w
8  |_|
9 
10  This file is part of Aleph-w library
11 
12  Copyright (c) 2002-2018 Leandro Rabindranath Leon & Alejandro Mujica
13 
14  This program is free software: you can redistribute it and/or modify
15  it under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  This program is distributed in the hope that it will be useful, but
20  WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with this program. If not, see <https://www.gnu.org/licenses/>.
26 */
27 
28 # ifndef DLINK_H
29 # define DLINK_H
30 
31 # include <aleph.H>
32 
33 using namespace Aleph;
34 
35 namespace Aleph {
36 
37 template <typename T> class Dnode; // Forward declaration of derived class
38 
48 class Dlink
49 {
50 protected:
51 
52  mutable Dlink * prev;
53  mutable Dlink * next;
54 
55 public:
56 
57  template <typename T> inline Dnode<T> * to_dnode() noexcept;
58  template <typename T> inline const Dnode<T> * to_dnode() const noexcept;
59  template <typename T> inline T& to_data() noexcept;
60  template <typename T> inline const T& to_data() const noexcept;
61 
63  Dlink() noexcept : prev(this), next(this) { assert(is_empty()); }
64 
67  Dlink(const Dlink & l) noexcept
68  : prev(l.prev), next(l.next)
69  {
70  if (l.is_empty())
71  reset();
72  }
73 
82  void swap(Dlink * link) noexcept
83  {
84  if (is_empty() and link->is_empty())
85  return;
86 
87  if (is_empty())
88  {
89  link->next->prev = this;
90  link->prev->next = this;
91  next = link->next;
92  prev = link->prev;
93  link->reset();
94  return;
95  }
96 
97  if (link->is_empty())
98  {
99  next->prev = link;
100  prev->next = link;
101  link->next = next;
102  link->prev = prev;
103  reset();
104  return;
105  }
106 
107  std::swap(prev->next, link->prev->next);
108  std::swap(next->prev, link->next->prev);
109  std::swap(prev, link->prev);
110  std::swap(next, link->next);
111  }
112 
121  void swap(Dlink & l) noexcept
122  {
123  swap(&l);
124  }
125 
133  Dlink(Dlink && l) noexcept : Dlink()
134  {
135  swap(l);
136  }
137 
145  Dlink & operator = (const Dlink & l) noexcept
146  {
147  if (l.is_empty())
148  return *this;
149 
150  assert(is_empty());
151  prev = l.prev;
152  next = l.next;
153  return *this;
154  }
155 
168  Dlink & operator = (Dlink && l) noexcept
169  {
170  swap(l);
171  return *this;
172  }
173 
180  void reset() noexcept
181  {
182  next = prev = this;
183  }
184 
186  void init() noexcept
187  {
188  reset();
189  }
190 
192  bool is_empty() const noexcept { return this == next and this == prev; }
193 
195  bool is_unitarian() const noexcept { return this != next and next == prev; }
196 
198  bool is_unitarian_or_empty() const noexcept { return next == prev; }
199 
205  void insert(Dlink * node) noexcept
206  {
207  assert(next != nullptr and prev != nullptr);
208  assert(node != nullptr);
209  assert(node->is_empty());
210 
211  node->prev = this;
212  node->next = next;
213  next->prev = node;
214  next = node;
215  }
216 
218  void push(Dlink * node) noexcept
219  {
220  insert(node);
221  }
222 
228  void append(Dlink * node) noexcept
229  {
230  assert(next != nullptr and prev != nullptr);
231  assert(node != nullptr);
232  assert(node->is_empty());
233 
234  node->next = this;
235  node->prev = prev;
236  prev->next = node;
237  prev = node;
238  }
239 
241  Dlink *& get_next() const noexcept
242  {
243  assert(next != nullptr and prev != nullptr);
244  return next;
245  }
246 
248  Dlink *& get_prev() const noexcept
249  {
250  assert(next != nullptr and prev != nullptr);
251  return prev;
252  }
253 
255  Dlink *& get_first_ne() const noexcept { return next; }
256 
258  Dlink *& get_last_ne() const noexcept { return prev; }
259 
261  Dlink *& get_first() const noexcept { return next; }
262 
264  Dlink *& get_last() const noexcept { return prev; }
265 
291  void wrap_header(Dlink * l) noexcept
292  {
293  assert(is_empty());
294  l->append(this);
295  }
296 
307  void insert_list(Dlink * head) noexcept
308  {
309  if (head->is_empty())
310  return;
311 
312  head->prev->next = next;
313  head->next->prev = this;
314  next->prev = head->prev;
315  next = head->next;
316  head->reset();
317  }
318 
329  void append_list(Dlink * head) noexcept
330  {
331  if (head->is_empty())
332  return;
333 
334  head->next->prev = prev;
335  head->prev->next = this;
336  prev->next = head->next;
337  prev = head->prev;
338  head->reset();
339  }
340 
345  void splice(Dlink * l) noexcept
346  {
347  Dlink head;
348  head.wrap_header(l);
349  insert_list(&head);
350  assert(head.is_empty());
351  }
352 
362  void concat_list(Dlink * head) noexcept
363  {
364  assert(head != nullptr);
365 
366  if (head->is_empty())
367  return;
368 
369  if (this->is_empty())
370  {
371  swap(head);
372  return;
373  }
374 
375  prev->next = head->next;
376  head->next->prev = prev;
377  prev = head->prev;
378  head->prev->next = this;
379  head->reset();
380  }
381 
383  void concat_list(Dlink & head) noexcept
384  {
385  concat_list(&head);
386  }
387 
389  Dlink * del() noexcept
390  {
391  assert(next != nullptr and prev != nullptr);
392 
393  prev->next = next;
394  next->prev = prev;
395  reset();
396  return this;
397  }
398 
400  void erase() noexcept { del(); }
401 
413  Dlink * remove_prev() noexcept
414  {
415  assert(not is_empty());
416 
417  Dlink* retValue = prev;
418  retValue->del();
419 
420  return retValue;
421  }
422 
434  Dlink * remove_next() noexcept
435  {
436  assert(not is_empty());
437 
438  Dlink* retValue = next;
439  retValue->del();
440 
441  return retValue;
442  }
443 
444  Dlink * remove_last_ne() noexcept
445  {
446  return remove_prev();
447  }
448 
449  Dlink * remove_first_ne() noexcept
450  {
451  return remove_next();
452  }
453 
454  Dlink * remove_last() noexcept
455  {
456  return remove_prev();
457  }
458 
459  Dlink * remove_first() noexcept
460  {
461  return remove_next();
462  }
463 
465  Dlink * top()
466  {
467  if (is_empty())
468  throw std::underflow_error("Dlink as stack is not empty");
469  return get_next();
470  }
471 
472  Dlink * pop()
473  {
474  if (is_empty())
475  throw std::underflow_error("Dlink as stack is not empty");
476  return remove_next();
477  }
478 
483  size_t reverse_list() noexcept
484  {
485  if (is_empty())
486  return 0;
487 
488  Dlink tmp;
489  size_t counter = 0;
490  for (; not is_empty(); counter++)
491  tmp.insert(remove_next());
492 
493  swap(&tmp);
494 
495  return counter;
496  }
497 
499  size_t reverse() noexcept { return reverse_list(); }
500 
514  size_t split_list_ne(Dlink & l, Dlink & r) noexcept
515  {
516  assert(l.is_empty() and r.is_empty()); // l y r deben estar vacías
517 
518  size_t count = 0;
519  while (not is_empty())
520  {
521  l.append(remove_next()); ++count;
522 
523  if (is_empty())
524  break;
525 
526  r.insert(remove_prev()); ++count;
527  }
528 
529  return count;
530  }
531 
532  size_t split_list(Dlink & l, Dlink & r) noexcept
533  {
534  return split_list_ne(l, r);
535  }
536 
556  Dlink cut_list(Dlink * link) noexcept
557  {
558  assert(not is_empty() and not link->is_empty() and link != this);
559 
560  Dlink list;
561  if (link == this->prev) // is link the last item?
562  {
563  link->del();
564  list.append(link);
565  return list;
566  }
567 
568  if (link == this->next) // is link the first item?
569  {
570  list.swap(this);
571  assert(this->is_empty());
572  return list;
573  }
574 
575  list.prev = this->prev; // enlazar list a link (punto de corte)
576  list.next = link;
577  this->prev = link->prev; // quitar de this todo a partir de link
578  link->prev->next = this;
579  link->prev = &list; // colocar el corte en list
580  list.prev->next = &list;
581 
582  return list;
583  }
584 
589  class Iterator
590  {
591  private:
592 
593  mutable Dlink * head = nullptr;
594  mutable Dlink * curr = nullptr;
595 
596  public:
597 
599  using Set_Type = Dlink;
600 
602  using Item_Type = Dlink *;
603 
609  Iterator(Dlink * head_ptr) noexcept
610  : head(head_ptr), curr(head->get_next()) { /* */ }
611 
616  Iterator(const Dlink & list) noexcept
617  : head(&const_cast<Dlink&>(list)), curr(head->get_next())
618  {
619  // Empty
620  }
621 
629  void set(Dlink * new_curr) noexcept
630  {
631  assert(curr != nullptr and head != nullptr);
632  curr = new_curr;
633  }
634 
635  Iterator() noexcept : head(nullptr), curr(nullptr) { /* Empty */ }
636 
638  void reset_first() noexcept
639  {
640  assert(curr != nullptr and head != nullptr);
641  curr = head->get_next();
642  }
643 
645  void reset_last() noexcept
646  {
647  assert(curr != nullptr and head != nullptr);
648  curr = head->get_prev();
649  }
650 
652  void end() noexcept
653  {
654  put_itor_at_the_end(*this);
655  }
656 
658  bool has_curr() const noexcept
659  {
660  assert(curr != nullptr and head != nullptr);
661  return curr != head;
662  }
663 
664  bool is_last() const noexcept
665  {
666  return head->is_empty() ? false : curr == head->prev;
667  }
668 
670  Dlink * get_curr_ne() const noexcept
671  {
672  assert(curr != nullptr and head != nullptr);
673  return curr;
674  }
675 
681  Dlink * get_curr() const
682  {
683  if (not has_curr())
684  throw std::overflow_error("Not element in list");
685 
686  return get_curr_ne();
687  }
688 
690  bool is_in_first() const noexcept
691  {
692  return head->is_empty() ? false : curr == head->next;
693  }
694 
696  bool is_in_last() const noexcept { return is_last(); }
697 
700  void prev_ne() noexcept { curr = curr->get_prev(); }
701 
706  void prev()
707  {
708  if (not has_curr())
709  throw std::underflow_error("Not previous element in list");
710  prev_ne();
711  }
712 
715  void next_ne() noexcept { curr = curr->get_next(); }
716 
721  void next()
722  {
723  if (not has_curr())
724  throw std::overflow_error("Not next element in list");
725  next_ne();
726  }
727 
729  bool operator == (const Iterator & it) const noexcept
730  { return curr == it.curr; }
731 
733  bool operator != (const Iterator & it) const noexcept
734  { return curr != it.curr; }
735 
741  Dlink * del()
742  {
743  assert(curr != nullptr and head != nullptr);
744  assert(has_curr());
745 
746  Dlink * current = get_curr(); // obtener nodo actual
747  next(); // avanzar al siguiente nodo
748  current->del(); // eliminar de la lista antiguo nodo actual
749  return current;
750  }
751 
752  Dlink * del_ne() noexcept
753  {
754  assert(curr != nullptr and head != nullptr);
755  assert(has_curr());
756 
757  Dlink * current = get_curr_ne(); // obtener nodo actual
758  next_ne(); // avanzar al siguiente nodo
759  current->del(); // eliminar de la lista antiguo nodo actual
760  return current;
761  }
762 
764  bool verify(Dlink * l) const { return head == l; }
765 
767  bool verify(const Iterator & it) const { return head == it.head; }
768  };
769 
781  void remove_all_and_delete() noexcept
782  {
783  while (not is_empty())
784  delete remove_next();
785  }
786 
801  void rotate_left(size_t n)
802  {
803  if (is_empty())
804  if (n == 0)
805  return;
806  else
807  throw std::domain_error("List is empty");
808 
809  for (size_t i = 0; i < n; ++i)
810  append(remove_first());
811  }
812 
814  void rotate_right(size_t n)
815  {
816  if (is_empty())
817  if (n == 0)
818  return;
819  else
820  throw std::domain_error("List is empty");
821 
822  for (size_t i = 0; i < n; ++i)
823  insert(remove_last());
824  }
825 
827  bool check()
828  {
829  Iterator itor(this);
830  Dlink* node;
831 
832  for (/* nothing */; itor.has_curr(); itor.next_ne())
833  {
834  node = itor.get_curr_ne();
835 
836  if (not (node->get_next()->get_prev() == node))
837  return false;
838 
839  if (not (node->get_prev()->get_next() == node))
840  return false;
841  }
842 
843  for (itor.reset_last(); itor.has_curr(); itor.prev())
844  {
845  node = itor.get_curr();
846 
847  if (not (node->get_next()->get_prev() == node))
848  return false;
849 
850  if (not (node->get_prev()->get_next() == node))
851  return false;
852  }
853 
854  return true;
855  }
856 };
857 
887 # define DLINK_TO_TYPE(type_name, link_name) \
888  inline static type_name * dlink_to_##type_name(Dlink * link) noexcept \
889  { \
890  type_name * ptr_zero = 0; \
891  size_t offset_link = reinterpret_cast<size_t>(&(ptr_zero->link_name)); \
892  char * address_type = reinterpret_cast<char*>(link) - offset_link; \
893  return reinterpret_cast<type_name *>(address_type); \
894  }
895 
937 # define LINKNAME_TO_TYPE(type_name, link_name) \
938  inline static type_name * link_name##_to_##type_name(Dlink * link) noexcept \
939  { \
940  type_name * ptr_zero = 0; \
941  size_t offset_link = reinterpret_cast<size_t>(&(ptr_zero->link_name)); \
942  char * address_type = reinterpret_cast<char*>(link) - offset_link; \
943  return reinterpret_cast<type_name *>(address_type); \
944  }
945 
946 
973 # define DLINK_TO_BASE(type_name, link_name) \
974  inline static type_name * dlink_to_base(Dlink * link) noexcept \
975  { \
976  type_name * ptr_zero = 0; \
977  size_t offset_link = reinterpret_cast<size_t>(&(ptr_zero->link_name)); \
978  char * address_type = reinterpret_cast<char*>(link) - offset_link; \
979  return reinterpret_cast<type_name *>(address_type); \
980  }
981 
982 }
983 
984 # endif /* DLINK_H */
985 
void swap(list &c)
Definition: List.H:512
Definition: ah-comb.H:35
Definition: List.H:49
Definition: dlink.H:37

Leandro Rabindranath León