SuperTinyKernel™ RTOS 1.06.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk_linked_list.h
Go to the documentation of this file.
1/*
2 * SuperTinyKernel(TM) RTOS: Lightweight High-Performance Deterministic C++ RTOS for Embedded Systems.
3 *
4 * Source: https://github.com/SuperTinyKernel-RTOS
5 *
6 * Copyright (c) 2022-2026 Neutron Code Limited <stk@neutroncode.com>. All Rights Reserved.
7 * License: MIT License, see LICENSE for a full text.
8 */
9
10#ifndef STK_LINKED_LIST_H_
11#define STK_LINKED_LIST_H_
12
29
30namespace stk {
31namespace util {
32
33// Forward declaration required so DListEntry can reference DListHead as a friend
34// and store a back-pointer to the owning list head.
35template <class T, bool TClosedLoop> class DListHead;
36
57template <class T, bool TClosedLoop> class DListEntry
58{
59 friend class DListHead<T, TClosedLoop>;
60
61public:
64 explicit DListEntry() : m_head(nullptr), m_next(nullptr), m_prev(nullptr)
65 {}
66
70 enum { DLEntryTag = 1 };
71
76
81
85 DLHeadType *GetHead() { return m_head; }
86
90 const DLHeadType *GetHead() const { return m_head; }
91
98 DLEntryType *GetNext() { return m_next; }
99
106 const DLEntryType *GetNext() const { return m_next; }
107
115
122 const DLEntryType *GetPrev() const { return m_prev; }
123
127 bool IsLinked() const { return (GetHead() != nullptr); }
128
134 operator T *() { return static_cast<T *>(this); }
135
141 operator const T *() const { return static_cast<const T *>(this); }
142
143protected:
152 ~DListEntry() = default;
153
154private:
162 void Link(DLHeadType *head, DLEntryType *next, DLEntryType *prev)
163 {
164 m_head = head;
165 m_next = next;
166 m_prev = prev;
167
168 if (m_prev != nullptr)
169 {
170 m_prev->m_next = this;
171 }
172
173 if (m_next != nullptr)
174 {
175 m_next->m_prev = this;
176 }
177 }
178
186 void Unlink()
187 {
188 if (m_prev != nullptr)
189 {
190 m_prev->m_next = m_next;
191 }
192
193 if (m_next != nullptr)
194 {
195 m_next->m_prev = m_prev;
196 }
197
198 m_head = nullptr;
199 m_next = nullptr;
200 m_prev = nullptr;
201 }
202
206};
207
228template <class T, bool TClosedLoop> class DListHead
229{
230 friend class DListEntry<T, TClosedLoop>;
231
232public:
237
240 explicit DListHead(): m_count(0U), m_first(nullptr), m_last(nullptr)
241 {}
242
246 size_t GetSize() const { return m_count; }
247
251 bool IsEmpty() const { return (m_count == 0U); }
252
257
261 const DLEntryType *GetFirst() const { return m_first; }
262
267
271 const DLEntryType *GetLast() const { return m_last; }
272
277 void Clear() { while (!IsEmpty()) Unlink(m_first); }
278
282 void LinkBack(DLEntryType *entry) { Link(entry, nullptr, m_last); }
283
287 void LinkBack(DLEntryType &entry) { Link(&entry, nullptr, m_last); }
288
294 void LinkFront(DLEntryType *entry) { Link(entry, m_last, nullptr); }
295
299 void LinkFront(DLEntryType &entry) { Link(&entry, m_last, nullptr); }
300
307 {
308 DLEntryType *ret = m_last;
309 Unlink(ret);
310 return ret;
311 }
312
319 {
320 DLEntryType *ret = m_first;
321 Unlink(ret);
322 return ret;
323 }
324
330 void Unlink(DLEntryType *entry)
331 {
332 STK_ASSERT(entry != nullptr);
333 STK_ASSERT(entry->IsLinked());
334 STK_ASSERT(entry->GetHead() == this);
335
336 if (m_first == entry)
337 {
338 m_first = entry->GetNext();
339 }
340
341 if (m_last == entry)
342 {
343 m_last = entry->GetPrev();
344 }
345
346 entry->Unlink();
347 --m_count;
348
349 UpdateEnds();
350 }
351
359 {
360 STK_ASSERT(&to != this);
361
362 while (!this->IsEmpty())
363 {
364 to.LinkBack(this->PopFront());
365 }
366 }
367
377 void Link(DLEntryType *entry, DLEntryType *next = nullptr, DLEntryType *prev = nullptr)
378 {
379 STK_ASSERT(entry != nullptr);
380 STK_ASSERT(!entry->IsLinked());
381
382 if (prev == nullptr)
383 {
384 next = m_first;
385 }
386
387 ++m_count;
388 entry->Link(this, next, prev);
389
390 if (m_first == nullptr)
391 {
392 m_first = entry;
393 }
394 else if (m_first == entry->GetNext())
395 {
396 m_first = entry;
397 }
398 else
399 {
400 // noop
401 }
402
403 if (m_last == nullptr)
404 {
405 m_last = entry;
406 }
407 else if (m_last == entry->GetPrev())
408 {
409 m_last = entry;
410 }
411 else
412 {
413 // noop
414 }
415
416 if __stk_constexpr_cpp17 (TClosedLoop)
417 {
418 UpdateEnds();
419 }
420 }
421
422private:
434 {
435 if (IsEmpty())
436 {
437 m_first = nullptr;
438 m_last = nullptr;
439 }
440 else
441 {
442 if __stk_constexpr_cpp17 (TClosedLoop)
443 {
444 m_first->m_prev = m_last;
445 m_last->m_next = m_first;
446 }
447 }
448 }
449
450 size_t m_count;
453};
454
459{
464 template <typename TTargetType, typename TSourceType>
465 static __stk_forceinline TTargetType *ListEntryToParent(TSourceType *const lentry)
466 {
467 STK_STATIC_ASSERT_N(TT, TTargetType::DLEntryTag == 1); // TTargetType must inherit DLEntryType
468 STK_STATIC_ASSERT_N(ST, TSourceType::DLEntryTag == 1); // TSourceType must inherit DLEntryType
469
470 return static_cast<TTargetType *>(lentry);
471 }
472};
473
474} // namespace util
475} // namespace stk
476
477
478#endif /* STK_LINKED_LIST_H_ */
#define STK_STATIC_ASSERT_N(NAME, X)
Compile-time assertion with a user-defined name suffix.
Definition stk_defs.h:438
#define __stk_forceinline
Forces compiler to always inline the decorated function, regardless of optimisation level.
Definition stk_defs.h:175
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:409
#define __stk_constexpr_cpp17
constexpr definition for C++17 and above.
Definition stk_defs.h:382
Namespace of STK package.
Internal utility namespace containing data structure helpers (linked lists, etc.) used by the kernel ...
Intrusive doubly-linked list container. Manages a collection of DListEntry nodes embedded in host obj...
DLEntryType * GetLast()
Get the last (back) entry without removing it.
DLEntryType * m_first
Pointer to the first (front) entry, or NULL when empty.
void LinkBack(DLEntryType *entry)
Append entry to the back of the list (pointer overload).
void Unlink(DLEntryType *entry)
Remove entry from this list.
DListHead()
Construct an empty list head (count = 0, first = last = NULL).
void Clear()
Remove and unlink all entries. After this call the list is empty.
const DLEntryType * GetFirst() const
Get the first (front) entry without removing it.
const DLEntryType * GetLast() const
Get the last (back) entry without removing it.
void LinkBack(DLEntryType &entry)
Append entry to the back of the list (reference overload).
void RelinkTo(DListHead &to)
Move all entries from this list to the back of to, preserving order.
void UpdateEnds()
Repair the boundary and circular pointers after every structural change.
void LinkFront(DLEntryType *entry)
Prepend entry to the front of the list (pointer overload).
DLEntryType * PopBack()
Remove and return the last entry.
size_t GetSize() const
Get the number of entries currently in the list.
DLEntryType * PopFront()
Remove and return the first entry.
DLEntryType * m_last
Pointer to the last (back) entry, or NULL when empty.
DLEntryType * GetFirst()
Get the first (front) entry without removing it.
DListEntry< T, TClosedLoop > DLEntryType
Convenience alias for the node type stored in this list.
bool IsEmpty() const
Check whether the list contains no entries.
void Link(DLEntryType *entry, DLEntryType *next=nullptr, DLEntryType *prev=nullptr)
Insert entry into the list between prev and next.
void LinkFront(DLEntryType &entry)
Prepend entry to the front of the list (reference overload).
size_t m_count
Number of entries currently in the list.
Intrusive doubly-linked list node. Embed this as a base class in any object (T) that needs to partici...
DListEntry< T, TClosedLoop > DLEntryType
Convenience alias for this entry type. Used to avoid repeating the full template spelling.
DLHeadType * m_head
Owning list head, or NULL when the entry is not linked.
~DListEntry()=default
Protected non-virtual destructor.
const DLHeadType * GetHead() const
Get the list head this entry currently belongs to.
void Unlink()
Remove this entry from its current list.
DLEntryType * GetNext()
Get the next entry in the list.
DLEntryType * m_next
Next entry in the list, or NULL (open list boundary) / first entry (closed loop).
const DLEntryType * GetPrev() const
Get the previous entry in the list.
DLEntryType * m_prev
Previous entry in the list, or NULL (open list boundary) / last entry (closed loop).
DLHeadType * GetHead()
Get the list head this entry currently belongs to.
void Link(DLHeadType *head, DLEntryType *next, DLEntryType *prev)
Wire this entry into a list between prev and next.
DLEntryType * GetPrev()
Get the previous entry in the list.
DListEntry()
Construct an unlinked entry. All pointers initialized to NULL.
bool IsLinked() const
Check whether this entry is currently a member of any list.
DListHead< T, TClosedLoop > DLHeadType
Convenience alias for the corresponding list head type.
const DLEntryType * GetNext() const
Get the next entry in the list.
Helper for casting list entries to concrete (parent) types.
static __stk_forceinline TTargetType * ListEntryToParent(TSourceType *const lentry)
Safely casts an intrusive list entry to its concrete parent container object type.