utils-lists 4.0.2
The µOS++ Intrusive Lists
Loading...
Searching...
No Matches
inlines.h
Go to the documentation of this file.
1/*
2 * This file is part of the µOS++ project (https://micro-os-plus.github.com/).
3 * Copyright (c) 2016 Liviu Ionescu. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software
6 * for any purpose is hereby granted, under the terms of the MIT license.
7 *
8 * If a copy of the license was not distributed with this file, it can
9 * be obtained from https://opensource.org/licenses/mit.
10 */
11
24
25#ifndef MICRO_OS_PLUS_UTILS_LISTS_INLINES_H_
26#define MICRO_OS_PLUS_UTILS_LISTS_INLINES_H_
27
28// ----------------------------------------------------------------------------
29
30#ifdef __cplusplus
31
32// ----------------------------------------------------------------------------
33
34#if defined(__GNUC__)
35#pragma GCC diagnostic push
36
37#pragma GCC diagnostic ignored "-Waggregate-return"
38#if defined(__clang__)
39#pragma clang diagnostic ignored "-Wc++98-compat"
40#endif
41#endif
42
43// ----------------------------------------------------------------------------
44
46{
47 // ==========================================================================
48
66 {
67 // Must be empty! No members must be changed by this constructor!
68 }
69
76 {
77 // Must be empty! No members must be changed by this constructor!
78 }
79
90 constexpr void
92 {
93 previous_ = this;
94 next_ = this;
95 }
96
97#pragma GCC diagnostic push
98
99#if defined(__GNUC__) && !defined(__clang__)
100#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
101#endif
102
103 constexpr double_list_links_base*
105 {
106 return next_;
107 }
108
109 constexpr double_list_links_base*
111 {
112 return previous_;
113 }
114
115#pragma GCC diagnostic pop
116
117 // ==========================================================================
118
133 {
134 // Must be empty! No members must be changed by this constructor!
135 }
136
137#pragma GCC diagnostic push
138
139#if defined(__clang__)
140#pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
141#endif
154#pragma GCC diagnostic pop
156 {
157 // The goal is to revert the content to a state similar to the
158 // statically initialised state (BSS zero).
159 // Unfortunately GCC does not honour this.
160 // next_ = nullptr;
161 // previous_ = nullptr;
162 }
163
164 // ==========================================================================
165
167 {
168 // For regular (non static) classes the members
169 // must be explicitly initialised.
170 initialize ();
171 }
172
176
177 // ==========================================================================
178
179 template <class T, class N, class U>
183
184 template <class T, class N, class U>
186 iterator_pointer const node)
187 : node_{ node }
188 {
189 }
190
191#if 0
192 template <class T, class N, class U>
194 reference element)
195 : node_{ &(element.*MP) }
196 {
197 static_assert (std::is_convertible<U, T>::value == true,
198 "U must be implicitly convertible to T!");
199 }
200#endif
201
202 template <class T, class N, class U>
205 {
206 return get_pointer ();
207 }
208
209 template <class T, class N, class U>
212 {
213 return *get_pointer ();
214 }
215
216 template <class T, class N, class U>
219 {
220 node_ = static_cast<N*> (node_->next ());
221 return *this;
222 }
223
224 template <class T, class N, class U>
227 {
228 const auto tmp = *this;
229 node_ = static_cast<iterator_pointer> (node_->next);
230 return tmp;
231 }
232
233 template <class T, class N, class U>
236 {
237 node_ = static_cast<iterator_pointer> (node_->previous);
238 return *this;
239 }
240
241 template <class T, class N, class U>
244 {
245 const auto tmp = *this;
246 node_ = static_cast<iterator_pointer> (node_->previous);
247 return tmp;
248 }
249
250 template <class T, class N, class U>
251 constexpr bool
253 const double_list_iterator& other) const
254 {
255 return node_ == other.node_;
256 }
257
258 template <class T, class N, class U>
259 constexpr bool
261 const double_list_iterator& other) const
262 {
263 return node_ != other.node_;
264 }
265
266 template <class T, class N, class U>
272
273 // ==========================================================================
274
282 template <class T, class L>
284 {
285#if defined(MICRO_OS_PLUS_TRACE_UTILS_LISTS_CONSTRUCT)
286 trace::printf ("%s() @%p \n", __func__, this);
287#endif
288
289 if constexpr (is_statically_allocated::value)
290 {
291 // By all means, do not add any code to clear the pointers, since
292 // the links node was statically initialised.
293 }
294 else
295 {
296 clear ();
297 }
298 }
299
310 template <class T, class L>
312 {
313#if defined(MICRO_OS_PLUS_TRACE_UTILS_LISTS_CONSTRUCT)
314 trace::printf ("%s() @%p \n", __func__, this);
315#endif
316
317 // Perhaps enable it for non statically allocated lists.
318 // assert (empty ());
319#if defined(MICRO_OS_PLUS_TRACE_UTILS_LISTS)
320 if (!empty ())
321 {
322 trace::printf ("%s() @%p list not empty\n", __func__, this);
323 }
324#endif
325 }
326
335 template <class T, class L>
336 bool
338 {
339 if constexpr (is_statically_allocated::value)
340 {
341 return links_.uninitialized ();
342 }
343 else
344 {
345 return false;
346 }
347 }
348
362 template <class T, class L>
363 void
365 {
366 if constexpr (is_statically_allocated::value)
367 {
368 links_.initialize_once ();
369 }
370 }
371
372 template <class T, class L>
373 bool
375 {
376 // If the links node is not linked, the list is empty.
377 return !links_.linked ();
378 }
379
384 template <class T, class L>
385 void
387 {
388#if defined(MICRO_OS_PLUS_TRACE_UTILS_LISTS)
389 trace::printf ("%s() @%p\n", __func__, this);
390#endif
391 links_.initialize ();
392 }
393
394 template <class T, class L>
395 constexpr typename double_list<T, L>::pointer
397 {
398 return reinterpret_cast<pointer> (links_.next ());
399 }
400
401 template <class T, class L>
402 constexpr typename double_list<T, L>::pointer
404 {
405 return reinterpret_cast<pointer> (links_.previous ());
406 }
407
408 template <class T, class L>
409 void
411 {
412 if constexpr (is_statically_allocated::value)
413 {
414 assert (!links_.uninitialized ());
415 }
416
417 // Add new node at the end of the list.
418 tail ()->link_next (&node);
419 }
420
421 template <class T, class L>
422 void
425 if constexpr (is_statically_allocated::value)
426 {
427 assert (!links_.uninitialized ());
428 }
429
430 // Add the new node at the head of the list.
431 head ()->link_previous (&node);
433
434 template <class T, class L>
437 {
438 if constexpr (is_statically_allocated::value)
439 {
440 assert (!links_.uninitialized ());
442
443 return iterator{ static_cast<iterator_pointer> (links_.next ()) };
445
446 template <class T, class L>
449 {
450 // The assert would probably be redundant, since it was
451 // already tested in `begin()`.
452
453 return iterator{ reinterpret_cast<iterator_pointer> (
454 const_cast<links_type*> (&links_)) };
455 }
456
457 // ==========================================================================
458
459 template <class T, class N, N T::*MP, class U>
464
465 template <class T, class N, N T::*MP, class U>
467 N* const node)
468 : node_{ node }
469 {
470 }
471
472 template <class T, class N, N T::*MP, class U>
474 reference element)
475 : node_{ &(element.*MP) }
476 {
477 static_assert (std::is_convertible<U, T>::value == true,
478 "U must be implicitly convertible to T!");
479 }
480
481 template <class T, class N, N T::*MP, class U>
487
488 template <class T, class N, N T::*MP, class U>
494
495 template <class T, class N, N T::*MP, class U>
498 {
499 node_ = static_cast<iterator_pointer> (node_->next ());
500 return *this;
501 }
502
503 template <class T, class N, N T::*MP, class U>
506 {
507 const auto tmp = *this;
508 node_ = static_cast<iterator_pointer> (node_->next ());
509 return tmp;
510 }
511
512 template <class T, class N, N T::*MP, class U>
515 {
516 node_ = static_cast<iterator_pointer> (node_->previous ());
517 return *this;
518 }
519
520 template <class T, class N, N T::*MP, class U>
523 {
524 const auto tmp = *this;
525 node_ = static_cast<iterator_pointer> (node_->previous ());
526 return tmp;
527 }
528
529 template <class T, class N, N T::*MP, class U>
530 inline bool
532 const intrusive_list_iterator& other) const
533 {
534 return node_ == other.node_;
535 }
536
537 template <class T, class N, N T::*MP, class U>
538 inline bool
540 const intrusive_list_iterator& other) const
541 {
542 return node_ != other.node_;
543 }
544
545 template <class T, class N, N T::*MP, class U>
548 {
549 // static_assert(std::is_convertible<U, T>::value == true, "U must be
550 // implicitly convertible to T!");
551
552 // Compute the distance between the member intrusive link
553 // node and the class begin.
554 const auto offset = reinterpret_cast<difference_type> (
555 &(static_cast<T*> (nullptr)->*MP));
556
557 // Compute the address of the object which includes the
558 // intrusive node, by adjusting down the node address.
559 return reinterpret_cast<pointer> (reinterpret_cast<difference_type> (node_)
560 - offset);
561 }
562
563 template <class T, class N, N T::*MP, class U>
569
570 // ==========================================================================
571
572 template <class T, class N, N T::*MP, class L, class U>
576
577 template <class T, class N, N T::*MP, class L, class U>
581
584 * If the statically allocated list is still in the initial
585 * _uninitialised_ state (with both
586 * pointers null), initialise the list to the empty state,
587 * with both pointers pointing to itself.
588 *
589 * For non-statically initialised lists, this method is ineffective.
590 *
591 * @note
592 * Must be manually called for statically allocated list before
593 * inserting elements, or any other operations.
594 */
595 template <class T, class N, N T::*MP, class L, class U>
596 void
601
602 template <class T, class N, N T::*MP, class L, class U>
603 constexpr bool
608
609 template <class T, class N, N T::*MP, class L, class U>
610 void
612 {
613 // The assert(links_.initialised()) is checked by the L class.
615 // Compute the distance between the member intrusive link
616 // node and the class begin.
617 const auto offset = reinterpret_cast<difference_type> (
618 &(static_cast<T*> (nullptr)->*MP));
619
620 // Add thread intrusive node at the end of the list.
621 (const_cast<N*> (double_list<N, L>::tail ()))
622 ->link_next (reinterpret_cast<N*> (
623 reinterpret_cast<difference_type> (&node) + offset));
624 }
625
626 template <class T, class N, N T::*MP, class L, class U>
627 void
629 {
630 // The assert(links_.initialised()) is checked by the L class.
631
632 // Compute the distance between the member intrusive link
633 // node and the class begin.
634 const auto offset = reinterpret_cast<difference_type> (
635 &(static_cast<T*> (nullptr)->*MP));
636
637 // Add thread intrusive node at the end of the list.
638 (const_cast<N*> (double_list<N, L>::head ()))
639 ->link_previous (reinterpret_cast<N*> (
640 reinterpret_cast<difference_type> (&node) + offset));
641 }
642
643#if defined(__GNUC__)
644#pragma GCC diagnostic push
645#pragma GCC diagnostic ignored "-Waggregate-return"
646#endif
647
648 template <class T, class N, N T::*MP, class L, class U>
651 {
652 // The assert(links_.initialised()) is checked by the L class.
654 return iterator{ static_cast<iterator_pointer> (
655 double_list<N, L>::links_.next ()) };
656 }
657
658 template <class T, class N, N T::*MP, class L, class U>
661 {
662 // The assert would probably be redundant, since it was
663 // already tested in `begin()`.
664
665 using head_type_ = typename double_list<N, L>::links_type;
666 return iterator{ reinterpret_cast<iterator_pointer> (
667 const_cast<head_type_*> (double_list<N, L>::links_pointer ())) };
668 }
669
670#if defined(__GNUC__)
671#pragma GCC diagnostic pop
672#endif
673
674 template <class T, class N, N T::*MP, class L, class U>
677 {
678 // static_assert(std::is_convertible<U, T>::value == true, "U must be
679 // implicitly convertible to T!");
680
681 // Compute the distance between the member intrusive link
682 // node and the class begin.
683 const auto offset = reinterpret_cast<difference_type> (
684 &(static_cast<T*> (nullptr)->*MP));
685
686 // Compute the address of the object which includes the
687 // intrusive node, by adjusting down the node address.
688 return reinterpret_cast<pointer> (reinterpret_cast<difference_type> (node)
689 - offset);
690 }
691
692 template <class T, class N, N T::*MP, class L, class U>
695 {
696 // No assert here, treat empty link unlinks as nop.
697
698 // The first element in the list.
700 = static_cast<iterator_pointer> (double_list<N, L>::links_.next ());
701 it->unlink ();
702
703 return get_pointer (it);
704 }
705
706 template <class T, class N, N T::*MP, class L, class U>
709 {
710 // No assert here, treat empty link unlinks as nop.
711
712 // The last element in the list.
713 iterator_pointer it = static_cast<iterator_pointer> (
714 double_list<N, L>::links_.previous ());
715 it->unlink ();
716
717 return get_pointer (it);
718 }
719
720 // ==========================================================================
721} // namespace micro_os_plus::utils
722
723#if defined(__GNUC__)
724#pragma GCC diagnostic pop
725#endif
726
727// ----------------------------------------------------------------------------
728
729#endif // __cplusplus
730
731// ----------------------------------------------------------------------------
732
733#endif // MICRO_OS_PLUS_UTILS_LISTS_INLINES_H_
734
735// ----------------------------------------------------------------------------
A class template for a doubly linked list forward iterator.
Definition lists.h:389
constexpr bool operator==(const double_list_iterator &other) const
Definition inlines.h:252
constexpr pointer get_pointer() const
constexpr pointer operator->() const
Definition inlines.h:204
value_type * pointer
Type of pointer to object pointed to by the iterator.
Definition lists.h:399
constexpr double_list_iterator & operator--()
Definition inlines.h:235
constexpr bool operator!=(const double_list_iterator &other) const
Definition inlines.h:260
constexpr iterator_pointer get_iterator_pointer() const
Definition inlines.h:268
constexpr double_list_iterator & operator++()
Definition inlines.h:218
constexpr reference operator*() const
Definition inlines.h:211
value_type & reference
Type of reference to object pointed to by the iterator.
Definition lists.h:404
iterator_pointer node_
Pointer to the node.
Definition lists.h:465
N * iterator_pointer
Type of reference to the iterator internal pointer.
Definition lists.h:409
void link_head(reference node)
Add a node to the head of the list.
Definition inlines.h:423
links_type links_
The list top node used to point to head and tail nodes.
Definition lists.h:688
L links_type
Type of the links node object where the pointers to the list head and tail are stored.
Definition lists.h:513
constexpr pointer tail(void) const
Get the list tail.
Definition inlines.h:403
void initialize_once(void)
Initialize the list only at first run.
Definition inlines.h:364
value_type * pointer
Type of pointer to object pointed to by the iterator.
Definition lists.h:523
constexpr const links_type * links_pointer() const
Get the address of the node storing the list links.
Definition lists.h:669
constexpr ~double_list()
Destruct the list.
Definition inlines.h:311
value_type & reference
Type of reference to object pointed to by the iterator.
Definition lists.h:528
double_list()
Construct a doubly linked list.
Definition inlines.h:283
void clear(void)
Clear the list.
Definition inlines.h:386
constexpr pointer head(void) const
Get the list head.
Definition inlines.h:396
iterator end() const
Iterator end.
Definition inlines.h:448
iterator begin() const
Iterator begin.
Definition inlines.h:436
double_list_iterator< value_type > iterator
Type of iterator over the values.
Definition lists.h:533
bool empty(void) const
Check if the list is empty.
Definition inlines.h:374
void link_tail(reference node)
Add a node to the tail of the list.
Definition inlines.h:410
bool uninitialized(void) const
Check if the list is uninitialised (only statically allocated lists can be uninitialised).
Definition inlines.h:337
A class template for the intrusive list iterator.
Definition lists.h:710
value_type * pointer
Type of pointer to object pointed to by the iterator.
Definition lists.h:720
pointer get_pointer(void) const
Get the object node from the intrusive node.
Definition inlines.h:547
intrusive_list_iterator & operator++()
Definition inlines.h:497
N * iterator_pointer
Type of reference to the iterator internal pointer.
Definition lists.h:730
bool operator==(const intrusive_list_iterator &other) const
Definition inlines.h:531
iterator_pointer get_iterator_pointer() const
Definition inlines.h:565
value_type & reference
Type of reference to object pointed to by the iterator.
Definition lists.h:725
bool operator!=(const intrusive_list_iterator &other) const
Definition inlines.h:539
intrusive_list_iterator & operator--()
Definition inlines.h:514
iterator_pointer node_
Pointer to intrusive node.
Definition lists.h:790
constexpr intrusive_list()
Construct an intrusive doubly linked list.
Definition inlines.h:573
constexpr bool empty(void) const
Check if the list is empty.
Definition inlines.h:604
void link_tail(reference node)
Add a node to the tail of the list.
Definition inlines.h:611
N * iterator_pointer
Type of reference to the iterator internal pointer.
Definition lists.h:881
iterator begin() const
Iterator begin.
Definition inlines.h:650
pointer unlink_head(void)
Unlink the first element from the list.
Definition inlines.h:694
void link_head(reference node)
Add a node to the head of the list.
Definition inlines.h:628
constexpr ~intrusive_list()
Destruct the list.
Definition inlines.h:578
intrusive_list_iterator< T, N, MP, U > iterator
Type of iterator over the values.
Definition lists.h:870
void initialize_once(void)
Initialize the list only at first run.
Definition inlines.h:597
iterator end() const
Iterator begin.
Definition inlines.h:660
ptrdiff_t difference_type
Type of pointer difference.
Definition lists.h:886
value_type * pointer
Type of pointer to object pointed to by the iterator.
Definition lists.h:860
pointer unlink_tail(void)
Unlink the last element from the list.
Definition inlines.h:708
pointer get_pointer(iterator_pointer node) const
Get the address of the node.
Definition inlines.h:676
The µOS++ utilities definitions.
Definition inlines.h:46