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
12#ifndef MICRO_OS_PLUS_UTILS_LISTS_INLINES_H_
13#define MICRO_OS_PLUS_UTILS_LISTS_INLINES_H_
14
15// ----------------------------------------------------------------------------
16
17#ifdef __cplusplus
18
19// ----------------------------------------------------------------------------
20
21#if defined(__GNUC__)
22#pragma GCC diagnostic push
23
24#pragma GCC diagnostic ignored "-Waggregate-return"
25#if defined(__clang__)
26#pragma clang diagnostic ignored "-Wc++98-compat"
27#endif
28#endif
29
30// ----------------------------------------------------------------------------
31
33{
34 // ==========================================================================
35
53 {
54 // Must be empty! No members must be changed by this constructor!
55 }
56
63 {
64 // Must be empty! No members must be changed by this constructor!
65 }
66
77 constexpr void
79 {
80 previous_ = this;
81 next_ = this;
82 }
83
84#pragma GCC diagnostic push
85
86#if defined(__GNUC__) && !defined(__clang__)
87#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
88#endif
89
90 constexpr double_list_links_base*
92 {
93 return next_;
94 }
95
96 constexpr double_list_links_base*
98 {
99 return previous_;
100 }
101
102#pragma GCC diagnostic pop
103
104 // ==========================================================================
105
120 {
121 // Must be empty! No members must be changed by this constructor!
122 }
123
124#pragma GCC diagnostic push
125
126#if defined(__clang__)
127#pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
128#endif
138#pragma GCC diagnostic pop
140 {
141 // The goal is to revert the content to a state similar to the
142 // statically initialised state (BSS zero).
143 // Unfortunately GCC does not honour this.
144 // next_ = nullptr;
145 // previous_ = nullptr;
146 }
147
148 // ==========================================================================
149
151 {
152 // For regular (non static) classes the members
153 // must be explicitly initialised.
154 initialize ();
155 }
156
160
161 // ==========================================================================
162
163 template <class T, class N, class U>
167
168 template <class T, class N, class U>
170 iterator_pointer const node)
171 : node_{ node }
172 {
173 }
174
175#if 0
176 template <class T, class N, class U>
178 reference element)
179 : node_{ &(element.*MP) }
180 {
181 static_assert (std::is_convertible<U, T>::value == true,
182 "U must be implicitly convertible to T!");
183 }
184#endif
185
186 template <class T, class N, class U>
189 {
190 return get_pointer ();
191 }
192
193 template <class T, class N, class U>
196 {
197 return *get_pointer ();
198 }
199
200 template <class T, class N, class U>
203 {
204 node_ = static_cast<N*> (node_->next ());
205 return *this;
206 }
207
208 template <class T, class N, class U>
211 {
212 const auto tmp = *this;
213 node_ = static_cast<iterator_pointer> (node_->next);
214 return tmp;
215 }
216
217 template <class T, class N, class U>
220 {
221 node_ = static_cast<iterator_pointer> (node_->previous);
222 return *this;
223 }
224
225 template <class T, class N, class U>
228 {
229 const auto tmp = *this;
230 node_ = static_cast<iterator_pointer> (node_->previous);
231 return tmp;
232 }
233
234 template <class T, class N, class U>
235 constexpr bool
237 const double_list_iterator& other) const
238 {
239 return node_ == other.node_;
240 }
241
242 template <class T, class N, class U>
243 constexpr bool
245 const double_list_iterator& other) const
246 {
247 return node_ != other.node_;
248 }
249
250 template <class T, class N, class U>
256
257 // ==========================================================================
258
266 template <class T, class L>
268 {
269#if defined(MICRO_OS_PLUS_TRACE_UTILS_LISTS_CONSTRUCT)
270 trace::printf ("%s() @%p \n", __func__, this);
271#endif
272
273 if constexpr (is_statically_allocated::value)
274 {
275 // By all means, do not add any code to clear the pointers, since
276 // the links node was statically initialised.
277 }
278 else
279 {
280 clear ();
281 }
282 }
283
294 template <class T, class L>
296 {
297#if defined(MICRO_OS_PLUS_TRACE_UTILS_LISTS_CONSTRUCT)
298 trace::printf ("%s() @%p \n", __func__, this);
299#endif
300
301 // Perhaps enable it for non statically allocated lists.
302 // assert (empty ());
303#if defined(MICRO_OS_PLUS_TRACE_UTILS_LISTS)
304 if (!empty ())
305 {
306 trace::printf ("%s() @%p list not empty\n", __func__, this);
307 }
308#endif
309 }
310
319 template <class T, class L>
320 bool
322 {
323 if constexpr (is_statically_allocated::value)
324 {
325 return links_.uninitialized ();
326 }
327 else
328 {
329 return false;
330 }
331 }
332
346 template <class T, class L>
347 void
349 {
350 if constexpr (is_statically_allocated::value)
351 {
352 links_.initialize_once ();
353 }
354 }
355
356 template <class T, class L>
357 bool
359 {
360 // If the links node is not linked, the list is empty.
361 return !links_.linked ();
362 }
363
368 template <class T, class L>
369 void
371 {
372#if defined(MICRO_OS_PLUS_TRACE_UTILS_LISTS)
373 trace::printf ("%s() @%p\n", __func__, this);
374#endif
375 links_.initialize ();
376 }
377
378 template <class T, class L>
379 constexpr typename double_list<T, L>::pointer
381 {
382 return reinterpret_cast<pointer> (links_.next ());
383 }
384
385 template <class T, class L>
386 constexpr typename double_list<T, L>::pointer
388 {
389 return reinterpret_cast<pointer> (links_.previous ());
390 }
391
392 template <class T, class L>
393 void
395 {
396 if constexpr (is_statically_allocated::value)
397 {
398 assert (!links_.uninitialized ());
399 }
400
401 // Add new node at the end of the list.
402 tail ()->link_next (&node);
404
405 template <class T, class L>
406 void
408 {
409 if constexpr (is_statically_allocated::value)
410 {
411 assert (!links_.uninitialized ());
412 }
413
414 // Add the new node at the head of the list.
415 head ()->link_previous (&node);
416 }
418 template <class T, class L>
421 {
422 if constexpr (is_statically_allocated::value)
424 assert (!links_.uninitialized ());
425 }
427 return iterator{ static_cast<iterator_pointer> (links_.next ()) };
428 }
430 template <class T, class L>
433 {
434 // The assert would probably be redundant, since it was
435 // already tested in `begin()`.
436
437 return iterator{ reinterpret_cast<iterator_pointer> (
438 const_cast<links_type*> (&links_)) };
439 }
440
441 // ==========================================================================
442
443 template <class T, class N, N T::*MP, class U>
448
449 template <class T, class N, N T::*MP, class U>
451 N* const node)
452 : node_{ node }
453 {
454 }
455
456 template <class T, class N, N T::*MP, class U>
458 reference element)
459 : node_{ &(element.*MP) }
460 {
461 static_assert (std::is_convertible<U, T>::value == true,
462 "U must be implicitly convertible to T!");
463 }
464
465 template <class T, class N, N T::*MP, class U>
471
472 template <class T, class N, N T::*MP, class U>
478
479 template <class T, class N, N T::*MP, class U>
482 {
483 node_ = static_cast<iterator_pointer> (node_->next ());
484 return *this;
485 }
486
487 template <class T, class N, N T::*MP, class U>
490 {
491 const auto tmp = *this;
492 node_ = static_cast<iterator_pointer> (node_->next ());
493 return tmp;
494 }
495
496 template <class T, class N, N T::*MP, class U>
499 {
500 node_ = static_cast<iterator_pointer> (node_->previous ());
501 return *this;
502 }
503
504 template <class T, class N, N T::*MP, class U>
507 {
508 const auto tmp = *this;
509 node_ = static_cast<iterator_pointer> (node_->previous ());
510 return tmp;
511 }
512
513 template <class T, class N, N T::*MP, class U>
514 inline bool
516 const intrusive_list_iterator& other) const
517 {
518 return node_ == other.node_;
519 }
520
521 template <class T, class N, N T::*MP, class U>
522 inline bool
524 const intrusive_list_iterator& other) const
525 {
526 return node_ != other.node_;
527 }
529 template <class T, class N, N T::*MP, class U>
532 {
533 // static_assert(std::is_convertible<U, T>::value == true, "U must be
534 // implicitly convertible to T!");
535
536 // Compute the distance between the member intrusive link
537 // node and the class begin.
538 const auto offset = reinterpret_cast<difference_type> (
539 &(static_cast<T*> (nullptr)->*MP));
540
541 // Compute the address of the object which includes the
542 // intrusive node, by adjusting down the node address.
543 return reinterpret_cast<pointer> (reinterpret_cast<difference_type> (node_)
544 - offset);
545 }
546
547 template <class T, class N, N T::*MP, class U>
550 {
551 return node_;
552 }
553
554 // ==========================================================================
555
556 template <class T, class N, N T::*MP, class L, class U>
560
561 template <class T, class N, N T::*MP, class L, class U>
564 }
565
573 * For non-statically initialised lists, this method is ineffective.
574 *
575 * @note
576 * Must be manually called for statically allocated list before
577 * inserting elements, or any other operations.
578 */
579 template <class T, class N, N T::*MP, class L, class U>
580 void
582 {
584 }
585
586 template <class T, class N, N T::*MP, class L, class U>
587 constexpr bool
592
593 template <class T, class N, N T::*MP, class L, class U>
594 void
596 {
597 // The assert(links_.initialised()) is checked by the L class.
598
599 // Compute the distance between the member intrusive link
600 // node and the class begin.
601 const auto offset = reinterpret_cast<difference_type> (
602 &(static_cast<T*> (nullptr)->*MP));
603
604 // Add thread intrusive node at the end of the list.
605 (const_cast<N*> (double_list<N, L>::tail ()))
606 ->link_next (reinterpret_cast<N*> (
607 reinterpret_cast<difference_type> (&node) + offset));
608 }
609
610 template <class T, class N, N T::*MP, class L, class U>
611 void
613 {
614 // The assert(links_.initialised()) is checked by the L class.
615
616 // Compute the distance between the member intrusive link
617 // node and the class begin.
618 const auto offset = reinterpret_cast<difference_type> (
619 &(static_cast<T*> (nullptr)->*MP));
620
621 // Add thread intrusive node at the end of the list.
622 (const_cast<N*> (double_list<N, L>::head ()))
623 ->link_previous (reinterpret_cast<N*> (
624 reinterpret_cast<difference_type> (&node) + offset));
625 }
626
627#if defined(__GNUC__)
628#pragma GCC diagnostic push
629#pragma GCC diagnostic ignored "-Waggregate-return"
630#endif
631
632 template <class T, class N, N T::*MP, class L, class U>
635 {
636 // The assert(links_.initialised()) is checked by the L class.
637
638 return iterator{ static_cast<iterator_pointer> (
640 }
641
642 template <class T, class N, N T::*MP, class L, class U>
645 {
646 // The assert would probably be redundant, since it was
647 // already tested in `begin()`.
648
649 using head_type_ = typename double_list<N, L>::links_type;
650 return iterator{ reinterpret_cast<iterator_pointer> (
651 const_cast<head_type_*> (double_list<N, L>::links_pointer ())) };
652 }
653
654#if defined(__GNUC__)
655#pragma GCC diagnostic pop
656#endif
657
658 template <class T, class N, N T::*MP, class L, class U>
661 {
662 // static_assert(std::is_convertible<U, T>::value == true, "U must be
663 // implicitly convertible to T!");
664
665 // Compute the distance between the member intrusive link
666 // node and the class begin.
667 const auto offset = reinterpret_cast<difference_type> (
668 &(static_cast<T*> (nullptr)->*MP));
669
670 // Compute the address of the object which includes the
671 // intrusive node, by adjusting down the node address.
672 return reinterpret_cast<pointer> (reinterpret_cast<difference_type> (node)
673 - offset);
674 }
675
676 template <class T, class N, N T::*MP, class L, class U>
679 {
680 // No assert here, treat empty link unlinks as nop.
681
682 // The first element in the list.
684 = static_cast<iterator_pointer> (double_list<N, L>::links_.next ());
685 it->unlink ();
686
687 return get_pointer (it);
688 }
689
690 template <class T, class N, N T::*MP, class L, class U>
693 {
694 // No assert here, treat empty link unlinks as nop.
695
696 // The last element in the list.
697 iterator_pointer it = static_cast<iterator_pointer> (
698 double_list<N, L>::links_.previous ());
699 it->unlink ();
700
701 return get_pointer (it);
702 }
703
704 // ==========================================================================
705} // namespace micro_os_plus::utils
706
707#if defined(__GNUC__)
708#pragma GCC diagnostic pop
709#endif
710
711// ----------------------------------------------------------------------------
712
713#endif // __cplusplus
714
715// ----------------------------------------------------------------------------
716
717#endif // MICRO_OS_PLUS_UTILS_LISTS_INLINES_H_
718
719// ----------------------------------------------------------------------------
A class template for a doubly linked list forward iterator.
Definition lists.h:368
constexpr bool operator==(const double_list_iterator &other) const
Definition inlines.h:236
constexpr pointer get_pointer() const
constexpr pointer operator->() const
Definition inlines.h:188
value_type * pointer
Type of pointer to object "pointed to" by the iterator.
Definition lists.h:378
constexpr double_list_iterator & operator--()
Definition inlines.h:219
constexpr bool operator!=(const double_list_iterator &other) const
Definition inlines.h:244
constexpr iterator_pointer get_iterator_pointer() const
Definition inlines.h:252
constexpr double_list_iterator & operator++()
Definition inlines.h:202
constexpr reference operator*() const
Definition inlines.h:195
value_type & reference
Type of reference to object "pointed to" by the iterator.
Definition lists.h:383
iterator_pointer node_
Pointer to the node.
Definition lists.h:444
N * iterator_pointer
Type of reference to the iterator internal pointer.
Definition lists.h:388
void link_head(reference node)
Add a node to the head of the list.
Definition inlines.h:407
links_type links_
The list top node used to point to head and tail nodes.
Definition lists.h:667
L links_type
Type of the links node object where the pointers to the list head and tail are stored.
Definition lists.h:492
value_type * iterator_pointer
Type of reference to the iterator internal pointer.
Definition lists.h:517
constexpr pointer tail(void) const
Get the list tail.
Definition inlines.h:387
void initialize_once(void)
Initialize the list only at first run.
Definition inlines.h:348
value_type * pointer
Type of pointer to object "pointed to" by the iterator.
Definition lists.h:502
constexpr const links_type * links_pointer() const
Get the address of the node storing the list links.
Definition lists.h:648
constexpr ~double_list()
Destruct the list.
Definition inlines.h:295
value_type & reference
Type of reference to object "pointed to" by the iterator.
Definition lists.h:507
double_list()
Construct a doubly linked list.
Definition inlines.h:267
void clear(void)
Clear the list.
Definition inlines.h:370
constexpr pointer head(void) const
Get the list head.
Definition inlines.h:380
iterator end() const
Iterator end.
Definition inlines.h:432
iterator begin() const
Iterator begin.
Definition inlines.h:420
double_list_iterator< value_type > iterator
Type of iterator over the values.
Definition lists.h:512
bool empty(void) const
Check if the list is empty.
Definition inlines.h:358
void link_tail(reference node)
Add a node to the tail of the list.
Definition inlines.h:394
bool uninitialized(void) const
Check if the list is uninitialised (only statically allocated can be).
Definition inlines.h:321
A class template for an intrusive list iterator.
Definition lists.h:689
value_type * pointer
Type of pointer to object "pointed to" by the iterator.
Definition lists.h:699
pointer get_pointer(void) const
Get the object node from the intrusive node.
Definition inlines.h:531
intrusive_list_iterator & operator++()
Definition inlines.h:481
N * iterator_pointer
Type of reference to the iterator internal pointer.
Definition lists.h:709
bool operator==(const intrusive_list_iterator &other) const
Definition inlines.h:515
iterator_pointer get_iterator_pointer() const
Definition inlines.h:549
value_type & reference
Type of reference to object "pointed to" by the iterator.
Definition lists.h:704
bool operator!=(const intrusive_list_iterator &other) const
Definition inlines.h:523
intrusive_list_iterator & operator--()
Definition inlines.h:498
ptrdiff_t difference_type
Type of pointer difference.
Definition lists.h:714
iterator_pointer node_
Pointer to intrusive node.
Definition lists.h:769
constexpr intrusive_list()
Construct an intrusive doubly linked list.
Definition inlines.h:557
constexpr bool empty(void) const
Check if the list is empty.
Definition inlines.h:588
void link_tail(reference node)
Add a node to the tail of the list.
Definition inlines.h:595
N * iterator_pointer
Type of reference to the iterator internal pointer.
Definition lists.h:860
iterator begin() const
Iterator begin.
Definition inlines.h:634
pointer unlink_head(void)
Unlink the first element from the list.
Definition inlines.h:678
void link_head(reference node)
Add a node to the head of the list.
Definition inlines.h:612
constexpr ~intrusive_list()
Destruct the list.
Definition inlines.h:562
intrusive_list_iterator< T, N, MP, U > iterator
Type of iterator over the values.
Definition lists.h:849
void initialize_once(void)
Initialize the list only at first run.
Definition inlines.h:581
iterator end() const
Iterator begin.
Definition inlines.h:644
ptrdiff_t difference_type
Type of pointer difference.
Definition lists.h:865
value_type * pointer
Type of pointer to object "pointed to" by the iterator.
Definition lists.h:839
pointer unlink_tail(void)
Unlink the last element from the list.
Definition inlines.h:692
pointer get_pointer(iterator_pointer node) const
Get the address of the node.
Definition inlines.h:660
µOS++ utility definitions.
Definition inlines.h:33