utils-lists 4.0.0
µOS++ C++ intrusive lists utilities
Loading...
Searching...
No Matches
inlines.h
Go to the documentation of this file.
1/*
2 * This file is part of the µOS++ distribution.
3 * (https://github.com/micro-os-plus/)
4 * Copyright (c) 2016 Liviu Ionescu. All rights reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software
7 * for any purpose is hereby granted, under the terms of the MIT license.
8 *
9 * If a copy of the license was not distributed with this file, it can
10 * be obtained from https://opensource.org/licenses/MIT/.
11 */
12
13#ifndef MICRO_OS_PLUS_UTILS_LISTS_INLINES_H_
14#define MICRO_OS_PLUS_UTILS_LISTS_INLINES_H_
15
16// ----------------------------------------------------------------------------
17
18#ifdef __cplusplus
19
20// ----------------------------------------------------------------------------
21
22#if defined(__GNUC__)
23#pragma GCC diagnostic push
24
25#pragma GCC diagnostic ignored "-Waggregate-return"
26#if defined(__clang__)
27#pragma clang diagnostic ignored "-Wc++98-compat"
28#endif
29#endif
30
31// ----------------------------------------------------------------------------
32
34{
35 // ==========================================================================
36
54 {
55 // Must be empty! No members must be changed by this constructor!
56 }
57
64 {
65 // Must be empty! No members must be changed by this constructor!
66 }
67
78 constexpr void
80 {
81 previous_ = this;
82 next_ = this;
83 }
84
85#pragma GCC diagnostic push
86
87#if defined(__GNUC__) && !defined(__clang__)
88#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
89#endif
90
91 constexpr double_list_links_base*
93 {
94 return next_;
95 }
96
97 constexpr double_list_links_base*
99 {
100 return previous_;
101 }
102
103#pragma GCC diagnostic pop
104
105 // ==========================================================================
106
121 {
122 // Must be empty! No members must be changed by this constructor!
123 }
124
125#pragma GCC diagnostic push
126
127#if defined(__clang__)
128#pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
129#endif
139#pragma GCC diagnostic pop
141 {
142 // The goal is to revert the content to a state similar to the
143 // statically initialised state (BSS zero).
144 // Unfortunately GCC does not honour this.
145 // next_ = nullptr;
146 // previous_ = nullptr;
147 }
148
149 // ==========================================================================
150
152 {
153 // For regular (non static) classes the members
154 // must be explicitly initialised.
155 initialize ();
156 }
157
161
162 // ==========================================================================
163
164 template <class T, class N, class U>
166 {
167 }
168
169 template <class T, class N, class U>
171 iterator_pointer const node)
172 : node_{ node }
173 {
174 }
175
176#if 0
177 template <class T, class N, class U>
179 reference element)
180 : node_{ &(element.*MP) }
181 {
182 static_assert (std::is_convertible<U, T>::value == true,
183 "U must be implicitly convertible to T!");
184 }
185#endif
186
187 template <class T, class N, class U>
190 {
191 return get_pointer ();
192 }
193
194 template <class T, class N, class U>
197 {
198 return *get_pointer ();
199 }
200
201 template <class T, class N, class U>
204 {
205 node_ = static_cast<N*> (node_->next ());
206 return *this;
207 }
208
209 template <class T, class N, class U>
212 {
213 const auto tmp = *this;
214 node_ = static_cast<iterator_pointer> (node_->next);
215 return tmp;
216 }
217
218 template <class T, class N, class U>
221 {
222 node_ = static_cast<iterator_pointer> (node_->previous);
223 return *this;
224 }
225
226 template <class T, class N, class U>
229 {
230 const auto tmp = *this;
231 node_ = static_cast<iterator_pointer> (node_->previous);
232 return tmp;
233 }
234
235 template <class T, class N, class U>
236 constexpr bool
238 const double_list_iterator& other) const
239 {
240 return node_ == other.node_;
241 }
242
243 template <class T, class N, class U>
244 constexpr bool
246 const double_list_iterator& other) const
247 {
248 return node_ != other.node_;
249 }
250
251 template <class T, class N, class U>
254 {
255 return node_;
256 }
257
258 // ==========================================================================
259
267 template <class T, class L>
269 {
270#if defined(MICRO_OS_PLUS_TRACE_UTILS_LISTS_CONSTRUCT)
271 trace::printf ("%s() @%p \n", __func__, this);
272#endif
273
274 if constexpr (is_statically_allocated::value)
275 {
276 // By all means, do not add any code to clear the pointers, since
277 // the links node was statically initialised.
278 }
279 else
280 {
281 clear ();
282 }
283 }
284
295 template <class T, class L>
297 {
298#if defined(MICRO_OS_PLUS_TRACE_UTILS_LISTS_CONSTRUCT)
299 trace::printf ("%s() @%p \n", __func__, this);
300#endif
301
302 // Perhaps enable it for non statically allocated lists.
303 // assert (empty ());
304#if defined(MICRO_OS_PLUS_TRACE_UTILS_LISTS)
305 if (!empty ())
306 {
307 trace::printf ("%s() @%p list not empty\n", __func__, this);
308 }
309#endif
310 }
311
320 template <class T, class L>
321 bool
323 {
324 if constexpr (is_statically_allocated::value)
325 {
326 return links_.uninitialized ();
327 }
328 else
329 {
330 return false;
331 }
332 }
333
347 template <class T, class L>
348 void
350 {
351 if constexpr (is_statically_allocated::value)
352 {
353 links_.initialize_once ();
354 }
355 }
356
357 template <class T, class L>
358 bool
360 {
361 // If the links node is not linked, the list is empty.
362 return !links_.linked ();
363 }
364
369 template <class T, class L>
370 void
372 {
373#if defined(MICRO_OS_PLUS_TRACE_UTILS_LISTS)
374 trace::printf ("%s() @%p\n", __func__, this);
375#endif
376 links_.initialize ();
377 }
378
379 template <class T, class L>
380 constexpr typename double_list<T, L>::pointer
382 {
383 return reinterpret_cast<pointer> (links_.next ());
384 }
385
386 template <class T, class L>
387 constexpr typename double_list<T, L>::pointer
389 {
390 return reinterpret_cast<pointer> (links_.previous ());
391 }
392
393 template <class T, class L>
394 void
396 {
397 if constexpr (is_statically_allocated::value)
398 {
399 assert (!links_.uninitialized ());
400 }
401
402 // Add new node at the end of the list.
403 tail ()->link_next (&node);
404 }
405
406 template <class T, class L>
407 void
409 {
410 if constexpr (is_statically_allocated::value)
411 {
412 assert (!links_.uninitialized ());
413 }
414
415 // Add the new node at the head of the list.
416 head ()->link_previous (&node);
417 }
418
419 template <class T, class L>
422 {
423 if constexpr (is_statically_allocated::value)
424 {
425 assert (!links_.uninitialized ());
426 }
427
428 return iterator{ static_cast<iterator_pointer> (links_.next ()) };
429 }
430
431 template <class T, class L>
434 {
435 // The assert would probably be redundant, since it was
436 // already tested in `begin()`.
437
438 return iterator{ reinterpret_cast<iterator_pointer> (
439 const_cast<links_type*> (&links_)) };
440 }
441
442 // ==========================================================================
443
444 template <class T, class N, N T::*MP, class U>
449
450 template <class T, class N, N T::*MP, class U>
452 N* const node)
453 : node_{ node }
454 {
455 }
456
457 template <class T, class N, N T::*MP, class U>
459 reference element)
460 : node_{ &(element.*MP) }
461 {
462 static_assert (std::is_convertible<U, T>::value == true,
463 "U must be implicitly convertible to T!");
464 }
465
466 template <class T, class N, N T::*MP, class U>
469 {
470 return get_pointer ();
471 }
472
473 template <class T, class N, N T::*MP, class U>
476 {
477 return *get_pointer ();
478 }
479
480 template <class T, class N, N T::*MP, class U>
483 {
484 node_ = static_cast<iterator_pointer> (node_->next ());
485 return *this;
486 }
487
488 template <class T, class N, N T::*MP, class U>
491 {
492 const auto tmp = *this;
493 node_ = static_cast<iterator_pointer> (node_->next ());
494 return tmp;
495 }
496
497 template <class T, class N, N T::*MP, class U>
500 {
501 node_ = static_cast<iterator_pointer> (node_->previous ());
502 return *this;
503 }
504
505 template <class T, class N, N T::*MP, class U>
508 {
509 const auto tmp = *this;
510 node_ = static_cast<iterator_pointer> (node_->previous ());
511 return tmp;
512 }
513
514 template <class T, class N, N T::*MP, class U>
515 inline bool
517 const intrusive_list_iterator& other) const
518 {
519 return node_ == other.node_;
520 }
521
522 template <class T, class N, N T::*MP, class U>
523 inline bool
525 const intrusive_list_iterator& other) const
526 {
527 return node_ != other.node_;
528 }
529
530 template <class T, class N, N T::*MP, class U>
533 {
534 // static_assert(std::is_convertible<U, T>::value == true, "U must be
535 // implicitly convertible to T!");
536
537 // Compute the distance between the member intrusive link
538 // node and the class begin.
539 const auto offset = reinterpret_cast<difference_type> (
540 &(static_cast<T*> (nullptr)->*MP));
541
542 // Compute the address of the object which includes the
543 // intrusive node, by adjusting down the node address.
544 return reinterpret_cast<pointer> (reinterpret_cast<difference_type> (node_)
545 - offset);
546 }
547
548 template <class T, class N, N T::*MP, class U>
554
555 // ==========================================================================
556
557 template <class T, class N, N T::*MP, class L, class U>
561
562 template <class T, class N, N T::*MP, class L, class U>
566
580 template <class T, class N, N T::*MP, class L, class U>
581 void
586
587 template <class T, class N, N T::*MP, class L, class U>
588 constexpr bool
593
594 template <class T, class N, N T::*MP, class L, class U>
595 void
597 {
598 // The assert(links_.initialised()) is checked by the L class.
600 // Compute the distance between the member intrusive link
601 // node and the class begin.
602 const auto offset = reinterpret_cast<difference_type> (
603 &(static_cast<T*> (nullptr)->*MP));
604
605 // Add thread intrusive node at the end of the list.
606 (const_cast<N*> (double_list<N, L>::tail ()))
607 ->link_next (reinterpret_cast<N*> (
608 reinterpret_cast<difference_type> (&node) + offset));
609 }
610
611 template <class T, class N, N T::*MP, class L, class U>
612 void
614 {
615 // The assert(links_.initialised()) is checked by the L class.
616
617 // Compute the distance between the member intrusive link
618 // node and the class begin.
619 const auto offset = reinterpret_cast<difference_type> (
620 &(static_cast<T*> (nullptr)->*MP));
621
622 // Add thread intrusive node at the end of the list.
623 (const_cast<N*> (double_list<N, L>::head ()))
624 ->link_previous (reinterpret_cast<N*> (
625 reinterpret_cast<difference_type> (&node) + offset));
626 }
627
628#if defined(__GNUC__)
629#pragma GCC diagnostic push
630#pragma GCC diagnostic ignored "-Waggregate-return"
631#endif
632
633 template <class T, class N, N T::*MP, class L, class U>
636 {
637 // The assert(links_.initialised()) is checked by the L class.
639 return iterator{ static_cast<iterator_pointer> (
640 double_list<N, L>::links_.next ()) };
641 }
642
643 template <class T, class N, N T::*MP, class L, class U>
646 {
647 // The assert would probably be redundant, since it was
648 // already tested in `begin()`.
649
650 using head_type_ = typename double_list<N, L>::links_type;
651 return iterator{ reinterpret_cast<iterator_pointer> (
652 const_cast<head_type_*> (double_list<N, L>::links_pointer ())) };
653 }
654
655#if defined(__GNUC__)
656#pragma GCC diagnostic pop
657#endif
658
659 template <class T, class N, N T::*MP, class L, class U>
662 {
663 // static_assert(std::is_convertible<U, T>::value == true, "U must be
664 // implicitly convertible to T!");
665
666 // Compute the distance between the member intrusive link
667 // node and the class begin.
668 const auto offset = reinterpret_cast<difference_type> (
669 &(static_cast<T*> (nullptr)->*MP));
670
671 // Compute the address of the object which includes the
672 // intrusive node, by adjusting down the node address.
673 return reinterpret_cast<pointer> (reinterpret_cast<difference_type> (node)
674 - offset);
675 }
676
677 template <class T, class N, N T::*MP, class L, class U>
680 {
681 // No assert here, treat empty link unlinks as nop.
682
683 // The first element in the list.
685 = static_cast<iterator_pointer> (double_list<N, L>::links_.next ());
686 it->unlink ();
687
688 return get_pointer (it);
689 }
690
691 template <class T, class N, N T::*MP, class L, class U>
694 {
695 // No assert here, treat empty link unlinks as nop.
696
697 // The last element in the list.
698 iterator_pointer it = static_cast<iterator_pointer> (
699 double_list<N, L>::links_.previous ());
700 it->unlink ();
701
702 return get_pointer (it);
703 }
704
705 // ==========================================================================
706} // namespace micro_os_plus::utils
707
708#if defined(__GNUC__)
709#pragma GCC diagnostic pop
710#endif
711
712// ----------------------------------------------------------------------------
713
714#endif // __cplusplus
715
716// ----------------------------------------------------------------------------
717
718#endif // MICRO_OS_PLUS_UTILS_LISTS_INLINES_H_
719
720// ----------------------------------------------------------------------------
A class template for a double linked list forward iterator.
Definition lists.h:373
constexpr bool operator==(const double_list_iterator &other) const
Definition inlines.h:237
constexpr pointer operator->() const
Definition inlines.h:189
value_type * pointer
Type of pointer to object "pointed to" by the iterator.
Definition lists.h:383
constexpr double_list_iterator & operator--()
Definition inlines.h:220
constexpr bool operator!=(const double_list_iterator &other) const
Definition inlines.h:245
constexpr iterator_pointer get_iterator_pointer() const
Definition inlines.h:253
constexpr double_list_iterator & operator++()
Definition inlines.h:203
constexpr reference operator*() const
Definition inlines.h:196
value_type & reference
Type of reference to object "pointed to" by the iterator.
Definition lists.h:388
iterator_pointer node_
Pointer to the node.
Definition lists.h:449
N * iterator_pointer
Type of reference to the iterator internal pointer.
Definition lists.h:393
A class template for a double linked list of nodes.
Definition lists.h:487
void link_head(reference node)
Add a node to the head of the list.
Definition inlines.h:408
L links_type
Type of the links node object where the pointers to the list head and tail are stored.
Definition lists.h:498
value_type * iterator_pointer
Type of reference to the iterator internal pointer.
Definition lists.h:523
constexpr pointer tail(void) const
Get the list tail.
Definition inlines.h:388
void initialize_once(void)
Initialize the list only at first run.
Definition inlines.h:349
value_type * pointer
Type of pointer to object "pointed to" by the iterator.
Definition lists.h:508
constexpr const links_type * links_pointer() const
Get the address of the node storing the list links.
Definition lists.h:654
constexpr ~double_list()
Destruct the list.
Definition inlines.h:296
value_type & reference
Type of reference to object "pointed to" by the iterator.
Definition lists.h:513
double_list()
Construct a double linked list.
Definition inlines.h:268
void clear(void)
Clear the list.
Definition inlines.h:371
constexpr pointer head(void) const
Get the list head.
Definition inlines.h:381
iterator end() const
Iterator end.
Definition inlines.h:433
iterator begin() const
Iterator begin.
Definition inlines.h:421
bool empty(void) const
Check if the list is empty.
Definition inlines.h:359
void link_tail(reference node)
Add a node to the tail of the list.
Definition inlines.h:395
bool uninitialized(void) const
Check if the list is uninitialised (only statically allocated can be).
Definition inlines.h:322
A class template for an intrusive list iterator.
Definition lists.h:696
value_type * pointer
Type of pointer to object "pointed to" by the iterator.
Definition lists.h:706
pointer get_pointer(void) const
Get the object node from the intrusive node.
Definition inlines.h:532
intrusive_list_iterator & operator++()
Definition inlines.h:482
N * iterator_pointer
Type of reference to the iterator internal pointer.
Definition lists.h:716
bool operator==(const intrusive_list_iterator &other) const
Definition inlines.h:516
iterator_pointer get_iterator_pointer() const
Definition inlines.h:550
value_type & reference
Type of reference to object "pointed to" by the iterator.
Definition lists.h:711
bool operator!=(const intrusive_list_iterator &other) const
Definition inlines.h:524
intrusive_list_iterator & operator--()
Definition inlines.h:499
iterator_pointer node_
Pointer to intrusive node.
Definition lists.h:776
constexpr intrusive_list()
Construct an intrusive double linked list.
Definition inlines.h:558
constexpr bool empty(void) const
Check if the list is empty.
Definition inlines.h:589
void link_tail(reference node)
Add a node to the tail of the list.
Definition inlines.h:596
N * iterator_pointer
Type of reference to the iterator internal pointer.
Definition lists.h:861
iterator begin() const
Iterator begin.
Definition inlines.h:635
pointer unlink_head(void)
Unlink the first element from the list.
Definition inlines.h:679
void link_head(reference node)
Add a node to the head of the list.
Definition inlines.h:613
constexpr ~intrusive_list()
Destruct the list.
Definition inlines.h:563
intrusive_list_iterator< T, N, MP, U > iterator
Type of iterator over the values.
Definition lists.h:850
void initialize_once(void)
Initialize the list only at first run.
Definition inlines.h:582
iterator end() const
Iterator begin.
Definition inlines.h:645
ptrdiff_t difference_type
Type of pointer difference.
Definition lists.h:866
value_type * pointer
Type of pointer to object "pointed to" by the iterator.
Definition lists.h:840
pointer unlink_tail(void)
Unlink the last element from the list.
Definition inlines.h:693
pointer get_pointer(iterator_pointer node) const
Get the address of the node.
Definition inlines.h:661
µOS++ utility definitions.
Definition inlines.h:34