Embedded Template Library  1.0
intrusive_links.h
Go to the documentation of this file.
1 
3 /******************************************************************************
4 The MIT License(MIT)
5 
6 Embedded Template Library.
7 https://github.com/ETLCPP/etl
8 https://www.etlcpp.com
9 
10 Copyright(c) 2016 jwellbelove
11 
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files(the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions :
18 
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21 
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29 ******************************************************************************/
30 
31 #ifndef ETL_INTRUSIVE_LINKS_INCLUDED
32 #define ETL_INTRUSIVE_LINKS_INCLUDED
33 
34 #include <assert.h>
35 
36 #include "platform.h"
37 #include "nullptr.h"
38 #include "type_traits.h"
39 #include "exception.h"
40 #include "error_handler.h"
41 
42 #include "utility.h"
43 #include "algorithm.h"
44 
45 #undef ETL_FILE
46 #define ETL_FILE "22"
47 
48 //*****************************************************************************
49 // Note:
50 // The link functions work slightly differently to the STL 'insert' convention
51 // in that the second link parameter will be inserted after the first.
52 // i.e.
53 // If the list contains '1', '2', '3', '4' and "link_splice '2','5'" is invoked the
54 // resulting list will contain '1', '2', '5', '3', '4'
55 // This is to maintain consistency between forward and bidirectional links
56 // and also is intuitive.
57 //*****************************************************************************
58 
59 namespace etl
60 {
61  //***************************************************************************
63  //***************************************************************************
65  {
66  public:
67 
68  link_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
69  : exception(reason_, file_name_, line_number_)
70  {
71  }
72  };
73 
74  //***************************************************************************
76  //***************************************************************************
78  {
79  public:
80 
81  not_unlinked_exception(string_type file_name_, numeric_type line_number_)
82  : link_exception(ETL_ERROR_TEXT("link:still linked", ETL_FILE"A"), file_name_, line_number_)
83  {
84  }
85  };
86 
87  //***************************************************************************
89  //***************************************************************************
90  template <const size_t ID_>
91  struct forward_link
92  {
93  enum
94  {
95  ID = ID_,
96  };
97 
98  void clear()
99  {
100  etl_next = ETL_NULLPTR;
101  }
102 
103  bool is_linked() const
104  {
105  return etl_next != ETL_NULLPTR;
106  }
107 
108  forward_link* etl_next;
109  };
110 
111  // Reference, Reference
112  template <typename TLink>
114  link(TLink& lhs, TLink& rhs)
115  {
116  lhs.etl_next = &rhs;
117  }
118 
119  // Reference, Reference
120  template <typename TLink>
122  link_splice(TLink& lhs, TLink& rhs)
123  {
124  rhs.etl_next = lhs.etl_next;
125  lhs.etl_next = &rhs;
126  }
127 
128  // Pointer, Pointer
129  template <typename TLink>
131  link(TLink* lhs, TLink* rhs)
132  {
133  if (lhs != ETL_NULLPTR)
134  {
135  lhs->etl_next = rhs;
136  }
137  }
138 
139  // Pointer, Pointer
140  template <typename TLink>
142  link_splice(TLink* lhs, TLink* rhs)
143  {
144  if (lhs != ETL_NULLPTR)
145  {
146  if (rhs != ETL_NULLPTR)
147  {
148  rhs->etl_next = lhs->etl_next;
149  }
150 
151  lhs->etl_next = rhs;
152  }
153  }
154 
155  // Reference, Pointer
156  template <typename TLink>
158  link(TLink& lhs, TLink* rhs)
159  {
160  lhs.etl_next = rhs;
161  }
162 
163  // Reference, Pointer
164  template <typename TLink>
166  link_splice(TLink& lhs, TLink* rhs)
167  {
168  if (rhs != ETL_NULLPTR)
169  {
170  rhs->etl_next = lhs.etl_next;
171  }
172 
173  lhs.etl_next = rhs;
174  }
175 
176  // Pointer, Reference
177  template <typename TLink>
179  link(TLink* lhs, TLink& rhs)
180  {
181  if (lhs != ETL_NULLPTR)
182  {
183  lhs->etl_next = &rhs;
184  }
185  }
186 
187  // Pointer, Reference
188  template <typename TLink>
190  link_splice(TLink* lhs, TLink& rhs)
191  {
192  if (lhs != ETL_NULLPTR)
193  {
194  rhs.etl_next = lhs->etl_next;
195  lhs->etl_next = &rhs;
196  }
197  }
198 
199  // Reference, Reference, Reference
200  template <typename TLink>
202  link_splice(TLink& lhs, TLink& first, TLink& last)
203  {
204  last.etl_next = lhs.etl_next;
205  lhs.etl_next = &first;
206  }
207 
208  // Pointer, Reference, Reference
209  template <typename TLink>
211  link_splice(TLink* lhs, TLink& first, TLink& last)
212  {
213  if (lhs != ETL_NULLPTR)
214  {
215  last.etl_next = lhs->etl_next;
216  lhs->etl_next = &first;
217  }
218  else
219  {
220  last.etl_next = ETL_NULLPTR;
221  }
222  }
223 
224  // Reference
225  template <typename TLink>
227  unlink_after(TLink& node)
228  {
229  if (node.etl_next != ETL_NULLPTR)
230  {
231  TLink* unlinked_node = node.etl_next;
232  node.etl_next = unlinked_node->etl_next;
233  }
234  }
235 
236  // Reference, Reference
237  template <typename TLink>
239  unlink_after(TLink& before, TLink& last)
240  {
241  before.etl_next = last.etl_next;
242  }
243 
244  //***************************************************************************
246  //***************************************************************************
247  template <const size_t ID_>
249  {
250  enum
251  {
252  ID = ID_,
253  };
254 
255  void clear()
256  {
257  etl_previous = ETL_NULLPTR;
258  etl_next = ETL_NULLPTR;
259  }
260 
261  bool is_linked() const
262  {
263  return (etl_previous != ETL_NULLPTR) || (etl_next != ETL_NULLPTR);
264  }
265 
266  void reverse()
267  {
268  using ETL_OR_STD::swap; // Allow ADL
269 
270  swap(etl_previous, etl_next);
271  }
272 
273  bidirectional_link* etl_previous;
274  bidirectional_link* etl_next;
275 
276  void unlink()
277  {
278  // Connect the previous link with the next.
279  if (etl_previous != ETL_NULLPTR)
280  {
281  etl_previous->etl_next = etl_next;
282  }
283 
284  // Connect the next link with the previous.
285  if (etl_next != ETL_NULLPTR)
286  {
287  etl_next->etl_previous = etl_previous;
288  }
289  }
290  };
291 
292  // Reference, Reference
293  template <typename TLink>
295  link(TLink& lhs, TLink& rhs)
296  {
297  lhs.etl_next = &rhs;
298  rhs.etl_previous = &lhs;
299  }
300 
301  // Reference, Reference
302  template <typename TLink>
304  link_splice(TLink& lhs, TLink& rhs)
305  {
306  rhs.etl_next = lhs.etl_next;
307  rhs.etl_previous = &lhs;
308 
309  if (lhs.etl_next != ETL_NULLPTR)
310  {
311  lhs.etl_next->etl_previous = &rhs;
312  }
313 
314  lhs.etl_next = &rhs;
315  }
316 
317  // Pointer, Pointer
318  template <typename TLink>
320  link(TLink* lhs, TLink* rhs)
321  {
322  if (lhs != ETL_NULLPTR)
323  {
324  lhs->etl_next = rhs;
325  }
326 
327  if (rhs != ETL_NULLPTR)
328  {
329  rhs->etl_previous = lhs;
330  }
331  }
332 
333  // Pointer, Pointer
334  template <typename TLink>
336  link_splice(TLink* lhs, TLink* rhs)
337  {
338  if (rhs != ETL_NULLPTR)
339  {
340  if (lhs != ETL_NULLPTR)
341  {
342  rhs->etl_next = lhs->etl_next;
343  }
344 
345  rhs->etl_previous = lhs;
346  }
347 
348  if (lhs != ETL_NULLPTR)
349  {
350  if (lhs->etl_next != ETL_NULLPTR)
351  {
352  lhs->etl_next->etl_previous = rhs;
353  }
354 
355  lhs->etl_next = rhs;
356  }
357  }
358 
359  // Reference, Pointer
360  template <typename TLink>
362  link(TLink& lhs, TLink* rhs)
363  {
364  lhs.etl_next = rhs;
365 
366  if (rhs != ETL_NULLPTR)
367  {
368  rhs->etl_previous = &lhs;
369  }
370  }
371 
372  // Reference, Pointer
373  template <typename TLink>
375  link_splice(TLink& lhs, TLink* rhs)
376  {
377  if (rhs != ETL_NULLPTR)
378  {
379  rhs->etl_next = lhs.etl_next;
380  rhs->etl_previous = &lhs;
381  }
382 
383  if (lhs.etl_next != ETL_NULLPTR)
384  {
385  lhs.etl_next->etl_previous = rhs;
386  }
387 
388  lhs.etl_next = rhs;
389  }
390 
391  // Pointer, Reference
392  template <typename TLink>
394  link(TLink* lhs, TLink& rhs)
395  {
396  if (lhs != ETL_NULLPTR)
397  {
398  lhs->etl_next = &rhs;
399  }
400 
401  rhs.etl_previous = lhs;
402  }
403 
404  // Pointer, Reference
405  template <typename TLink>
407  link_splice(TLink* lhs, TLink& rhs)
408  {
409  if (lhs != ETL_NULLPTR)
410  {
411  rhs.etl_next = lhs->etl_next;
412  }
413 
414  rhs.etl_previous = lhs;
415 
416  if (lhs != ETL_NULLPTR)
417  {
418  if (lhs->etl_next != ETL_NULLPTR)
419  {
420  lhs->etl_next->etl_previous = &rhs;
421  }
422 
423  lhs->etl_next = &rhs;
424  }
425  }
426 
427  // Reference, Reference, Reference
428  template <typename TLink>
430  link_splice(TLink& lhs, TLink& first, TLink& last)
431  {
432  last.etl_next = lhs.etl_next;
433  first.etl_previous = &lhs;
434 
435  if (last.etl_next != ETL_NULLPTR)
436  {
437  last.etl_next->etl_previous = &last;
438  }
439 
440  lhs.etl_next = &first;
441  }
442 
443  // Pointer, Reference, Reference
444  template <typename TLink>
446  link_splice(TLink* lhs, TLink& first, TLink& last)
447  {
448  if (lhs != ETL_NULLPTR)
449  {
450  last.etl_next = lhs->etl_next;
451  }
452  else
453  {
454  last.etl_next = ETL_NULLPTR;
455  }
456 
457  first.etl_previous = lhs;
458 
459  if (last.etl_next != ETL_NULLPTR)
460  {
461  last.etl_next->etl_previous = &last;
462  }
463 
464  if (lhs != ETL_NULLPTR)
465  {
466  lhs->etl_next = &first;
467  }
468  }
469 
470  // Reference
471  template <typename TLink>
473  unlink(TLink& node)
474  {
475  node.unlink();
476  }
477 
478  // Reference Reference
479  template <typename TLink>
481  unlink(TLink& first, TLink& last)
482  {
483  if (&first == &last)
484  {
485  first.unlink();
486  }
487  else
488  {
489  if (last.etl_next != ETL_NULLPTR)
490  {
491  last.etl_next->etl_previous = first.etl_previous;
492  }
493 
494  if (first.etl_previous != ETL_NULLPTR)
495  {
496  first.etl_previous->etl_next = last.etl_next;
497  }
498  }
499  }
500 
501  //***************************************************************************
503  //***************************************************************************
504  template <const size_t ID_>
505  struct tree_link
506  {
507  enum
508  {
509  ID = ID_,
510  };
511 
512  void clear()
513  {
514  etl_parent = ETL_NULLPTR;
515  etl_left = ETL_NULLPTR;
516  etl_right = ETL_NULLPTR;
517  }
518 
519  bool is_linked() const
520  {
521  return (etl_parent != ETL_NULLPTR) || (etl_left != ETL_NULLPTR) || (etl_right != ETL_NULLPTR);
522  }
523 
524  tree_link* etl_parent;
525  tree_link* etl_left;
526  tree_link* etl_right;
527  };
528 
529  // Reference, Reference
530  template <typename TLink>
532  link_left(TLink& parent, TLink& leaf)
533  {
534  parent.etl_left = &leaf;
535  leaf.etl_parent = &parent;
536  }
537 
538  template <typename TLink>
540  link_right(TLink& parent, TLink& leaf)
541  {
542  parent.etl_right = &leaf;
543  leaf.etl_parent = &parent;
544  }
545 
546  // Pointer, Pointer
547  template <typename TLink>
549  link_left(TLink* parent, TLink* leaf)
550  {
551  if (parent != ETL_NULLPTR)
552  {
553  parent->etl_left = leaf;
554  }
555 
556  if (leaf != ETL_NULLPTR)
557  {
558  leaf->etl_parent = parent;
559  }
560  }
561 
562  template <typename TLink>
564  link_right(TLink* parent, TLink* leaf)
565  {
566  if (parent != ETL_NULLPTR)
567  {
568  parent->etl_right = leaf;
569  }
570 
571  if (leaf != ETL_NULLPTR)
572  {
573  leaf->etl_parent = parent;
574  }
575  }
576 
577  // Reference, Pointer
578  template <typename TLink>
580  link_left(TLink& parent, TLink* leaf)
581  {
582  parent.etl_left = leaf;
583 
584  if (leaf != ETL_NULLPTR)
585  {
586  leaf->etl_parent = &parent;
587  }
588  }
589 
590  template <typename TLink>
592  link_right(TLink& parent, TLink* leaf)
593  {
594  parent.etl_right = leaf;
595 
596  if (leaf != ETL_NULLPTR)
597  {
598  leaf->etl_parent = &parent;
599  }
600  }
601 
602  // Pointer, Reference
603  template <typename TLink>
605  link_left(TLink* parent, TLink& leaf)
606  {
607  if (parent != ETL_NULLPTR)
608  {
609  parent->etl_left = &leaf;
610  }
611 
612  leaf.etl_parent = parent;
613  }
614 
615  template <typename TLink>
617  link_right(TLink* parent, TLink& leaf)
618  {
619  if (parent != ETL_NULLPTR)
620  {
621  parent->etl_right = &leaf;
622  }
623 
624  leaf.etl_parent = parent;
625  }
626 
627  // Reference, Reference
628  template <typename TLink>
630  link_rotate_left(TLink& parent, TLink& leaf)
631  {
632  parent.etl_right = leaf.etl_left;
633 
634  if (parent.etl_right != ETL_NULLPTR)
635  {
636  parent.etl_right->etl_parent = &parent;
637  }
638 
639  leaf.etl_parent = parent.etl_parent;
640  parent.etl_parent = &leaf;
641  leaf.etl_left = &parent;
642  }
643 
644  template <typename TLink>
646  link_rotate_right(TLink& parent, TLink& leaf)
647  {
648  parent.etl_left = leaf.etl_right;
649 
650  if (parent.etl_left != ETL_NULLPTR)
651  {
652  parent.etl_left->etl_parent = &parent;
653  }
654 
655  leaf.etl_parent = parent.etl_parent;
656  parent.etl_parent = &leaf;
657  leaf.etl_right = &parent;
658  }
659 
660  // Pointer, Pointer
661  template <typename TLink>
663  link_rotate_left(TLink* parent, TLink* leaf)
664  {
665  if ((parent != ETL_NULLPTR) && (leaf != ETL_NULLPTR))
666  {
667  link_rotate_left(*parent, *leaf);
668  }
669  }
670 
671  template <typename TLink>
673  link_rotate_right(TLink* parent, TLink* leaf)
674  {
675  if ((parent != ETL_NULLPTR) && (leaf != ETL_NULLPTR))
676  {
677  link_rotate_right(*parent, *leaf);
678  }
679  }
680 
681  // Reference, Pointer
682  template <typename TLink>
684  link_rotate_left(TLink& parent, TLink* leaf)
685  {
686  if (leaf != ETL_NULLPTR)
687  {
688  link_rotate_left(parent, *leaf);
689  }
690  }
691 
692  template <typename TLink>
694  link_rotate_right(TLink& parent, TLink* leaf)
695  {
696  if (leaf != ETL_NULLPTR)
697  {
698  link_rotate_right(parent, *leaf);
699  }
700  }
701 
702  // Pointer, Reference
703  template <typename TLink>
705  link_rotate_left(TLink* parent, TLink& leaf)
706  {
707  if (parent != ETL_NULLPTR)
708  {
709  link_rotate_left(*parent, leaf);
710  }
711  }
712 
713  template <typename TLink>
715  link_rotate_right(TLink* parent, TLink& leaf)
716  {
717  if (parent != ETL_NULLPTR)
718  {
719  link_rotate_right(*parent, leaf);
720  }
721  }
722 
723  // Reference, Reference
725  template <typename TLink>
727  link_rotate(TLink& parent, TLink& leaf)
728  {
729  if (parent.etl_left == &leaf)
730  {
731  etl::link_rotate_right(parent, leaf);
732  }
733  else
734  {
735  etl::link_rotate_left(parent, leaf);
736  }
737  }
738 
739  // Pointer, Pointer
741  template <typename TLink>
743  link_rotate(TLink* parent, TLink* leaf)
744  {
745  if ((parent != ETL_NULLPTR) && (leaf != ETL_NULLPTR))
746  {
747  if (parent->etl_left == leaf)
748  {
749  etl::link_rotate_right(*parent, *leaf);
750  }
751  else
752  {
753  etl::link_rotate_left(*parent, *leaf);
754  }
755  }
756  }
757 
758  // Reference, Pointer
760  template <typename TLink>
762  link_rotate(TLink& parent, TLink* leaf)
763  {
764  if (leaf != ETL_NULLPTR)
765  {
766  if (parent.etl_left == leaf)
767  {
768  etl::link_rotate_right(parent, *leaf);
769  }
770  else
771  {
772  etl::link_rotate_left(parent, *leaf);
773  }
774  }
775  }
776 
777  // Pointer, Reference
779  template <typename TLink>
781  link_rotate(TLink* parent, TLink& leaf)
782  {
783  if (parent != ETL_NULLPTR)
784  {
785  if (parent->etl_left == &leaf)
786  {
787  etl::link_rotate_right(*parent, leaf);
788  }
789  else
790  {
791  etl::link_rotate_left(*parent, leaf);
792  }
793  }
794  }
795 }
796 
797 #undef ETL_FILE
798 #endif
not unlinked exception.
Definition: intrusive_links.h:78
exception(string_type reason_, string_type file_, numeric_type line_)
Constructor.
Definition: exception.h:67
Definition: exception.h:47
enable_if
Definition: type_traits_generator.h:1228
Definition: absolute.h:37
etl::enable_if< etl::is_same< TLink, etl::tree_link< TLink::ID > >::value, void >::type link_rotate(TLink &parent, TLink &leaf)
Automatically detects whether a left or right rotate is expected.
Definition: intrusive_links.h:727
void swap(etl::array< T, SIZE > &lhs, etl::array< T, SIZE > &rhs)
Template deduction guides.
Definition: array.h:570