The inlines.h File Reference
The file with the implementations of the µOS++ lists inlined methods. More...
Namespaces
namespace | |
The top µOS++ namespace. | |
namespace | |
The µOS++ utilities definitions. | |
Description
The inlines.h
header file contains the C++ implementations of the inlined methods for the µOS++ Intrusive Lists classes, delivering an efficient and lightweight linked list management system tailored for embedded applications.
The class definitions are in the lists.h file.
File Listing
The file content with the documentation metadata removed is:
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
45namespace micro_os_plus::utils
46{
47 // ==========================================================================
48
65 constexpr double_list_links_base::double_list_links_base ()
66 {
67 // Must be empty! No members must be changed by this constructor!
68 }
69
75 constexpr double_list_links_base::~double_list_links_base ()
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*
104 double_list_links_base::next (void) const
105 {
106 return next_;
107 }
108
109 constexpr double_list_links_base*
110 double_list_links_base::previous (void) const
111 {
112 return previous_;
113 }
114
115#pragma GCC diagnostic pop
116
117 // ==========================================================================
118
132 constexpr static_double_list_links::static_double_list_links ()
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
155 constexpr static_double_list_links::~static_double_list_links ()
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
166 constexpr double_list_links::double_list_links ()
167 {
168 // For regular (non static) classes the members
169 // must be explicitly initialised.
170 initialize ();
171 }
172
173 constexpr double_list_links::~double_list_links ()
174 {
175 }
176
177 // ==========================================================================
178
179 template <class T, class N, class U>
180 constexpr double_list_iterator<T, N, U>::double_list_iterator () : node_{}
181 {
182 }
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>
193 constexpr double_list_iterator<T, N, U>::double_list_iterator (
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>
203 constexpr typename double_list_iterator<T, N, U>::pointer
205 {
206 return get_pointer ();
207 }
208
209 template <class T, class N, class U>
210 constexpr typename double_list_iterator<T, N, U>::reference
212 {
213 return *get_pointer ();
214 }
215
216 template <class T, class N, class U>
217 constexpr double_list_iterator<T, N, U>&
219 {
221 return *this;
222 }
223
224 template <class T, class N, class U>
225 constexpr double_list_iterator<T, N, 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>
234 constexpr double_list_iterator<T, N, U>&
236 {
237 node_ = static_cast<iterator_pointer> (node_->previous);
238 return *this;
239 }
240
241 template <class T, class N, class U>
242 constexpr double_list_iterator<T, N, 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 {
256 }
257
258 template <class T, class N, class U>
259 constexpr bool
261 const double_list_iterator& other) const
262 {
264 }
265
266 template <class T, class N, class U>
267 constexpr typename double_list_iterator<T, N, U>::iterator_pointer
269 {
270 return node_;
271 }
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>
311 constexpr double_list<T, L>::~double_list ()
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
337 double_list<T, L>::uninitialized (void) const
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
374 double_list<T, L>::empty (void) const
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
386 double_list<T, L>::clear (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
396 double_list<T, L>::head (void) const
397 {
399 }
400
401 template <class T, class L>
402 constexpr typename double_list<T, L>::pointer
403 double_list<T, L>::tail (void) const
404 {
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
424 {
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);
432 }
433
434 template <class T, class L>
435 typename double_list<T, L>::iterator
436 double_list<T, L>::begin () const
437 {
438 if constexpr (is_statically_allocated::value)
439 {
440 assert (!links_.uninitialized ());
441 }
442
443 return iterator{ static_cast<iterator_pointer> (links_.next ()) };
444 }
445
446 template <class T, class L>
447 typename double_list<T, L>::iterator
448 double_list<T, L>::end () const
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>
461 : node_{}
462 {
463 }
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>
482 inline typename intrusive_list_iterator<T, N, MP, U>::pointer
484 {
485 return get_pointer ();
486 }
487
488 template <class T, class N, N T::*MP, class U>
489 inline typename intrusive_list_iterator<T, N, MP, U>::reference
491 {
492 return *get_pointer ();
493 }
494
495 template <class T, class N, N T::*MP, class U>
496 inline intrusive_list_iterator<T, N, MP, 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>
504 inline intrusive_list_iterator<T, N, MP, 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>
513 inline intrusive_list_iterator<T, N, MP, 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 {
535 }
536
537 template <class T, class N, N T::*MP, class U>
538 inline bool
540 const intrusive_list_iterator& other) const
541 {
543 }
544
545 template <class T, class N, N T::*MP, class U>
546 inline typename intrusive_list_iterator<T, N, MP, U>::pointer
547 intrusive_list_iterator<T, N, MP, U>::get_pointer (void) const
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>
564 inline typename intrusive_list_iterator<T, N, MP, U>::iterator_pointer
566 {
567 return node_;
568 }
569
570 // ==========================================================================
571
572 template <class T, class N, N T::*MP, class L, class U>
573 constexpr intrusive_list<T, N, MP, L, U>::intrusive_list ()
574 {
575 }
576
577 template <class T, class N, N T::*MP, class L, class U>
578 constexpr intrusive_list<T, N, MP, L, U>::~intrusive_list ()
579 {
580 }
581
595 template <class T, class N, N T::*MP, class L, class U>
596 void
598 {
599 return double_list<N, L>::initialize_once ();
600 }
601
602 template <class T, class N, N T::*MP, class L, class U>
603 constexpr bool
604 intrusive_list<T, N, MP, L, U>::empty (void) const
605 {
606 return double_list<N, L>::empty ();
607 }
608
609 template <class T, class N, N T::*MP, class L, class U>
610 void
611 intrusive_list<T, N, MP, L, U>::link_tail (U& node)
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
628 intrusive_list<T, N, MP, L, U>::link_head (U& node)
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>
649 inline typename intrusive_list<T, N, MP, L, U>::iterator
650 intrusive_list<T, N, MP, L, U>::begin () const
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>
659 inline typename intrusive_list<T, N, MP, L, U>::iterator
660 intrusive_list<T, N, MP, L, U>::end () const
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>
675 inline typename intrusive_list<T, N, MP, L, U>::pointer
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>
693 typename intrusive_list<T, N, MP, L, U>::pointer
695 {
696 // No assert here, treat empty link unlinks as nop.
697
698 // The first element in the list.
699 iterator_pointer it
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>
707 typename intrusive_list<T, N, MP, L, U>::pointer
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// ----------------------------------------------------------------------------
Generated via docusaurus-plugin-doxygen by Doxygen 1.13.2