ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
sidilist.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_lang of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under #"mainpage_license".
7//==================================================================================================
8ALIB_EXPORT namespace alib::lang {
9
10//==================================================================================================
11/// This is a generic base type that may be used to represent a node of a single linked list.
12/// The effective (instantiated) nodes of the list are to be derived from this type by specifying
13/// their very own type name as template parameter \p{TElement}. The following quick sample
14/// demonstrates this:
15///
16/// \code{.cpp}
17/// // The contents to store with each element of a list
18/// class MyData
19/// {
20/// //...
21/// };
22///
23/// // The custom list node derived from this type, giving its own type as template parameter
24/// struct MyElement : public lang::SidiNodeBase<MyElement>
25/// {
26/// MyData nodeValue;
27/// };
28/// \endcode
29///
30/// With this mechanism in place, pointers to nodes of this type may either point to a node
31/// or to a "full" element of derived class.
32/// This concept allows having field #"n" of this class of derived type \p{TElement}, which makes
33/// debugging end-user code much easier because the custom values of the derived types are
34/// visible within debugging tools.
35///
36/// This type provides some helper methods, which, together with those of sibling
37/// struct #"SidiListHook", provide all basic mechanisms to implement a single linked
38/// list.
39///
40/// Because pointers to nodes and elements are statically castable to each other (which is a noop),
41/// most helper methods accept and/or return pointers to derived type \p{TElement}. It has
42/// to be ensured by the caller that these pointers are only dereferenced when it is ensured that
43/// they do not refer to this base type! Therefore, the helper-classes are designed for
44/// "internal use" and reside in the \e detail namespace.
45/// As an example, class #"List" of module \alib_containers is built using these
46/// helpers internally but publishes a full type safe interface, including iterator classes.
47///
48/// \see Types #"SidiListHook", #"BidiNodeBase", and #"BidiListHook".
49///
50/// @tparam TElement The "final" node type, containing custom data fields, that is to be derived from
51/// this struct.
52//==================================================================================================
53template<typename TElement>
55{
56 /// A pointer to the next element in the list.
57 /// \attention
58 /// In case of using type #"BidiListHook", this may point to an instance of the
59 /// base type #"BidiNodeBase".
60 TElement* n;
61
62
63 /// Default constructor. (Does not initialize the pointer.)
64 SidiNodeBase() noexcept =default;
65
66 /// Deleted copy constructor. This is deleted because it is dangerous, respectively often
67 /// not possible and also mostly not wanted to be able to create copies of derived type
68 /// \p{TElement}
69 SidiNodeBase( const SidiNodeBase& ) =delete;
70
71 /// Defaulted move constructor.
72 SidiNodeBase( SidiNodeBase&& ) noexcept =default;
73
74 /// Deleted copy assignment operator. This is deleted because it is dangerous, respectively
75 /// often not possible and also mostly not wanted to create copies of derived type
76 /// \p{TElement}
77 /// @return Not defined.
78 SidiNodeBase& operator=( const SidiNodeBase& ) =delete;
79
80 /// Defaulted move assignment operator.
81 /// @return A reference to this object.
82 SidiNodeBase& operator=( SidiNodeBase&& ) noexcept =default;
83
84 /// Constructor accepting a pointer to the next element.
85 /// @param next Pointer to the next element. Assigned to field #"n".
86 explicit
87 SidiNodeBase( TElement* next ) noexcept
88 : n(next) {}
89
90 /// Sets the successor of this node or element.
91 /// @param p The node that this node should point to, respectively \c nullptr if this node
92 /// should represent the last element of the list.
93 void next(SidiNodeBase* p) { n= static_cast<TElement*>(p); }
94
95 /// Returns the successor of this node or element.
96 /// @return The element following this one, respectively \c nullptr if this is the last
97 /// element of the list.
98 TElement* next() const { return n; }
99
100 /// Test if this node or element has set an element in filed #"n".
101 /// @return \c false if field #"n" equals \c nullptr, otherwise \c true.
102 [[nodiscard]]
103 bool hasNext() const { return n != nullptr; }
104
105 /// Test if \p{elem} is the successor for this node or element.
106 /// @param elem The element to test for being a successor of this.
107 /// @return \c true if field #"n" equals \p{elem} , otherwise \c false.
108 [[nodiscard]]
109 bool pointsTo( const SidiNodeBase* elem ) const { return n == elem; }
110
111 /// Unhooks and returns the element after this node or element.
112 /// \note
113 /// Field #"n" of the returned element is \b not set to \c nullptr.
114 ///
115 /// @return The unhooked element.
116 TElement* removeNext() noexcept {
117 auto* result= next();
118 next( next()->next() );
119 return result;
120 }
121
122 /// Unhooks successors until \p{last}. If \p{last} equals field #"n", only this next
123 /// element is unhooked.
124 /// \attention
125 /// Field #"n" of given \p{last} is \b not set to \c nullptr.
126 ///
127 /// @param last The last element of the range
128 /// <b>[</b>#"SidiNodeBase::n"<b>, </b> \p{last}<b>]</b> which is removed.
129 ///
130 /// @return The start of the range (the current successor of this node or element).
131 TElement* removeRangeBehind( TElement* last ) noexcept {
132 TElement* result= next();
133 next( last->next() );
134 return result;
135 }
136
137 /// Hooks the given element behind this node or element.
138 /// @param elem The element to insert behind this node or element.
139 /// @return The element that given \p{elem} pointed to before the insertion.
140 TElement* addBehind( TElement* elem ) noexcept {
141 TElement* result = elem->next();
142 elem->next(next());
143 next( elem );
144 return result;
145 }
146
147 /// Counts the number of elements found in the range starting with the next node (in
148 /// consideration that this node is the 'hook' node) and ending with the element before \p{end}.
149 ///
150 /// @param end Pointer to the element after the last one to count.
151 /// Defaults to \c nullptr, marking the end of a list.
152 /// @return The number of elements in the range.
153 [[nodiscard]]
154 integer count( SidiNodeBase* end= nullptr ) const noexcept {
155 integer result= 0;
156 SidiNodeBase* start= next();
157 while( start != end ) {
158 start= start->next();
159 ++result;
160 }
161 return result;
162 }
163}; // struct SidiNodeBase
164
165
166//==================================================================================================
167/// This class, together with sibling class #"SidiNodeBase" provide the tools to
168/// implement a single linked list of \p{TElement} instances.
169///
170/// \see Types #"SidiNodeBase",<br>
171/// #"BidiNodeBase", and<br>
172/// #"BidiListHook".
173///
174/// @tparam TElement The "final" custom type that (by contract) is derived from
175/// #"SidiNodeBase".
176//==================================================================================================
177template<typename TElement>
178struct SidiListHook : SidiNodeBase<TElement>
179{
180 /// An alias for the node type.
182
183 /// Default constructor. Initializes this list to be empty.
184 SidiListHook() noexcept
185 : TNode(nullptr) {}
186
187 /// Deleted copy constructor.
188 /// \note Copy construction is a duty of derived usable types.
189 SidiListHook( const SidiListHook& copy ) =delete;
190
191 /// Move constructor.
192 /// Copies the link from \p{move} and sets the link of \p{move} to \c nullptr.
193 SidiListHook( SidiListHook&& ) noexcept =default;
194
195 /// Deleted copy assignment operator.
196 /// @return Not applicable
197 SidiListHook& operator= ( const SidiListHook& ) noexcept =delete;
198
199 /// Move assignment operator.
200 /// Copies the link to the first element from \p{move} and sets the link in \p{move} to
201 /// \c nullptr.
202 /// @return A reference to this list object.
203 SidiListHook& operator= ( SidiListHook&& ) noexcept =default;
204
205 /// Tests if this list is empty.
206 /// @return \c false if the list is empty, \c true otherwise.
207 [[nodiscard]]
208 bool isEmpty() const noexcept { return first() == nullptr; }
209
210 /// Resets this list to zero elements.
211 void reset() noexcept { TNode::next(nullptr); }
212
213 /// Returns the start element of this list.
214 /// @return The first element of this list, respectively \c nullptr if this list is empty.
215 [[nodiscard]]
216 TElement* first() const noexcept { return TNode::next(); }
217
218 /// Hooks the given element to the beginning of this list.
219 /// @param elem The element to insert to at the start.
220 void pushFront( TElement* elem ) noexcept {
221 elem->next( TNode::next() );
222 TNode::next( elem );
223 }
224
225 /// Hooks the given range of elements to the front of this list.
226 /// @param first The first element of the range to insert.
227 /// @param last The last element of the range to insert.
228 void pushFront( TElement* first, TElement* last )
229 {
230 last->next(this->first());
231 TNode::next(first);
232 }
233
234 /// Removes and returns the first element from this list.
235 /// @return A pointer to the element, respectively \c nullptr if the list was empty.
236 TElement* popFront() noexcept {
237 TElement* result= first();
238 if( result )
239 TNode::next(result->next());
240 return result;
241 }
242
243 /// Searches and returns the last element.
244 /// \note
245 /// This method must only be invoked on non-empty lists (#".isEmpty" returns \c false).
246 /// Otherwise, this method has undefined behavior (dereference of a \c nullptr).
247 /// To find the pointer to the last element, use #"findLastBefore" providing \c nullptr.
248 /// @return The last element of this list.
249 [[nodiscard]]
250 TElement* findLast() const noexcept {
251 TElement* elem= first();
252 while( elem->hasNext() )
253 elem= elem->next();
254 return elem;
255 }
256
257 /// Searches and returns the last element.
258 /// @param hint An element of this list used to start the search.
259 /// @return The last element of this list.
260 [[nodiscard]]
261 TElement* findLast( TElement* hint ) const noexcept {
262 TElement* elem= hint;
263 while( elem->hasNext() )
264 elem= elem->next();
265 return elem;
266 }
267
268 /// Searches the node or element that points to the given element.
269 /// \attention The element has to exist. Otherwise, a \c nullptr exception will occur!
270 /// @param elem The element to search for.
271 /// @return The node (this object) or element pointing to \p{elem}.
272 [[nodiscard]]
273 TElement* findLastBefore( TElement* elem ) noexcept {
274 TNode* it= this;
275 while( !it->pointsTo(elem) )
276 it= it->next();
277 return static_cast<TElement*>( it );
278 }
279
280 /// Searches the predecessor of the given element using #"findLastBefore" and unhooks the element
281 /// from the list.
282 /// \attention
283 /// It is not checked whether a predecessor was found, aka whether \p{elem} is an element
284 /// of this list. If not, the behavior is undefined (<c>nullptr access</c>).<br>
285 /// Furthermore, the successor of given \p{elem} is not changed, although it is removed
286 /// from the list.
287 ///
288 /// @param elem The element to remove.
289 /// @return The node (this object) or element that pointed to given \p{elem} before the
290 /// invocation and now points to the successor of \p{elem}.
291 TNode* findAndRemove( TElement* elem ) noexcept {
292 TNode* previous= findLastBefore(elem);
293 previous->removeNext();
294 return previous;
295 }
296
297 /// Counts the number of elements found in the range starting with this list's first element and
298 /// ending with the element before \p{end}.
299 /// @param end The element after the last one to count.
300 /// Defaults to a \c nullptr marking the end of the list.
301 /// @return The number of elements in the range.
302 [[nodiscard]]
303 integer count( TElement* end= nullptr ) const noexcept { return TNode::count( end ); }
304}; // struct SidiListHook
305
306} // namespace [alib::lang]
#define ALIB_EXPORT
Definition alib.inl:562
platform_specific integer
Definition integers.inl:32
SidiListHook(const SidiListHook &copy)=delete
void reset() noexcept
Resets this list to zero elements.
Definition sidilist.inl:211
TElement * first() const noexcept
Definition sidilist.inl:216
TElement * findLast(TElement *hint) const noexcept
Definition sidilist.inl:261
void pushFront(TElement *elem) noexcept
Definition sidilist.inl:220
SidiListHook() noexcept
Default constructor. Initializes this list to be empty.
Definition sidilist.inl:184
TElement * findLast() const noexcept
Definition sidilist.inl:250
SidiNodeBase< Element > TNode
Definition sidilist.inl:181
TNode * findAndRemove(TElement *elem) noexcept
Definition sidilist.inl:291
TElement * popFront() noexcept
Definition sidilist.inl:236
bool isEmpty() const noexcept
Definition sidilist.inl:208
void pushFront(TElement *first, TElement *last)
Definition sidilist.inl:228
SidiListHook(SidiListHook &&) noexcept=default
TElement * findLastBefore(TElement *elem) noexcept
Definition sidilist.inl:273
integer count(TElement *end=nullptr) const noexcept
Definition sidilist.inl:303
SidiNodeBase() noexcept=default
Default constructor. (Does not initialize the pointer.).
TElement * addBehind(TElement *elem) noexcept
Definition sidilist.inl:140
TElement * removeNext() noexcept
Definition sidilist.inl:116
TElement * removeRangeBehind(TElement *last) noexcept
Definition sidilist.inl:131
TElement * next() const
Definition sidilist.inl:98
bool pointsTo(const SidiNodeBase *elem) const
Definition sidilist.inl:109
integer count(SidiNodeBase *end=nullptr) const noexcept
Definition sidilist.inl:154