Skip to main content

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
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
174 {
175 }
176
177 // ==========================================================================
178
179 template <class T, class N, class U>
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>
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>
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>
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
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>
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>
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>
484 {
485 return get_pointer ();
486 }
487
488 template <class T, class N, N T::*MP, class U>
491 {
492 return *get_pointer ();
493 }
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>
566 {
567 return node_;
568 }
569
570 // ==========================================================================
571
572 template <class T, class N, N T::*MP, class L, class U>
574 {
575 }
576
577 template <class T, class N, N T::*MP, class L, class U>
579 {
580 }
581
595 template <class T, class N, N T::*MP, class L, class U>
596 void
598 {
600 }
601
602 template <class T, class N, N T::*MP, class L, class U>
603 constexpr bool
605 {
607 }
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> (
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// ----------------------------------------------------------------------------

Generated via docusaurus-plugin-doxygen by Doxygen 1.13.2