ALib C++ Framework
by
Library Version: 2605 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
sidilist.hpp
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/// Copyright 2013-2026 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 no-op),
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 /// A pointer to the next element in the list.
56 /// \attention
57 /// In case of using type #"BidiListHook", this may point to an instance of the
58 /// base type #"BidiNodeBase".
59 TElement* n;
60
61
62 /// Default constructor. (Does not initialize the pointer.)
63 SidiNodeBase() noexcept =default;
64
65 /// Deleted copy constructor. This is deleted because it is dangerous, respectively often
66 /// not possible and also mostly not wanted to be able to create copies of derived type
67 /// \p{TElement}
68 SidiNodeBase( const SidiNodeBase& ) =delete;
69
70 /// Defaulted move constructor.
71 SidiNodeBase( SidiNodeBase&& ) noexcept =default;
72
73 /// Deleted copy assignment operator. This is deleted because it is dangerous, respectively
74 /// often not possible and also mostly not wanted to create copies of derived type
75 /// \p{TElement}
76 /// @return Not defined.
77 SidiNodeBase& operator=( const SidiNodeBase& ) =delete;
78
79 /// Defaulted move assignment operator.
80 /// @return A reference to this object.
81 SidiNodeBase& operator=( SidiNodeBase&& ) noexcept =default;
82
83 /// Constructor accepting a pointer to the next element.
84 /// @param next Pointer to the next element. Assigned to field #"n".
85 explicit
86 SidiNodeBase( TElement* next ) noexcept
87 : n(next) {}
88
89 /// Sets the successor of this node or element.
90 /// @param p The node that this node should point to, respectively \c nullptr if this node
91 /// should represent the last element of the list.
92 void next(SidiNodeBase* p) { n= static_cast<TElement*>(p); }
93
94 /// Returns the successor of this node or element.
95 /// @return The element following this one, respectively \c nullptr if this is the last
96 /// element of the list.
97 TElement* next() const { return n; }
98
99 /// Test if this node or element has set an element in filed #"n".
100 /// @return \c false if field #"n" equals \c nullptr, otherwise \c true.
101 [[nodiscard]]
102 bool hasNext() const { return n != nullptr; }
103
104 /// Test if \p{elem} is the successor for this node or element.
105 /// @param elem The element to test for being a successor of this.
106 /// @return \c true if field #"n" equals \p{elem} , otherwise \c false.
107 [[nodiscard]]
108 bool pointsTo( const SidiNodeBase* elem ) const { return n == elem; }
109
110 /// Unhooks and returns the element after this node or element.
111 /// \note
112 /// Field #"n" of the returned element is \b not set to \c nullptr.
113 ///
114 /// @return The unhooked element.
115 TElement* removeNext() noexcept {
116 auto* result= next();
117 next( next()->next() );
118 return result;
119 }
120
121 /// Unhooks successors until \p{last}. If \p{last} equals field #"n", only this next
122 /// element is unhooked.
123 /// \attention
124 /// Field #"n" of given \p{last} is \b not set to \c nullptr.
125 ///
126 /// @param last The last element of the range
127 /// <b>[</b>#"SidiNodeBase::n"<b>, </b> \p{last}<b>]</b> which is removed.
128 ///
129 /// @return The start of the range (the current successor of this node or element).
130 TElement* removeRangeBehind( TElement* last ) noexcept {
131 TElement* result= next();
132 next( last->next() );
133 return result;
134 }
135
136 /// Hooks the given element behind this node or element.
137 /// @param elem The element to insert behind this node or element.
138 /// @return The element that given \p{elem} pointed to before the insertion.
139 TElement* addBehind( TElement* elem ) noexcept {
140 TElement* result = elem->next();
141 elem->next(next());
142 next( elem );
143 return result;
144 }
145
146 /// Counts the number of elements found in the range starting with the next node (in
147 /// consideration that this node is the 'hook' node) and ending with the element before \p{end}.
148 ///
149 /// @param end Pointer to the element after the last one to count.
150 /// Defaults to \c nullptr, marking the end of a list.
151 /// @return The number of elements in the range.
152 [[nodiscard]]
153 integer count( SidiNodeBase* end= nullptr ) const noexcept {
154 integer result= 0;
155 SidiNodeBase* start= next();
156 while( start != end ) {
157 start= start->next();
158 ++result;
159 }
160 return result;
161 }
162}; // struct SidiNodeBase
163
164
165//==================================================================================================
166/// This class, together with sibling class #"SidiNodeBase" provide the tools to
167/// implement a single linked list of \p{TElement} instances.
168///
169/// \see Types #"SidiNodeBase",<br>
170/// #"BidiNodeBase", and<br>
171/// #"BidiListHook".
172///
173/// @tparam TElement The "final" custom type that (by contract) is derived from
174/// #"SidiNodeBase".
175//==================================================================================================
176template<typename TElement>
177struct SidiListHook : SidiNodeBase<TElement> {
178 /// An alias for the node type.
180
181 /// Default constructor. Initializes this list to be empty.
182 SidiListHook() noexcept
183 : TNode(nullptr) {}
184
185 /// Deleted copy constructor.
186 /// \note Copy construction is a duty of derived usable types.
187 SidiListHook( const SidiListHook& copy ) =delete;
188
189 /// Move constructor.
190 /// Copies the link from \p{move} and sets the link of \p{move} to \c nullptr.
191 SidiListHook( SidiListHook&& ) noexcept =default;
192
193 /// Deleted copy assignment operator.
194 /// @return Not applicable
195 SidiListHook& operator= ( const SidiListHook& ) noexcept =delete;
196
197 /// Move assignment operator.
198 /// Copies the link to the first element from \p{move} and sets the link in \p{move} to
199 /// \c nullptr.
200 /// @return A reference to this list object.
201 SidiListHook& operator= ( SidiListHook&& ) noexcept =default;
202
203 /// Tests if this list is empty.
204 /// @return \c false if the list is empty, \c true otherwise.
205 [[nodiscard]]
206 bool isEmpty() const noexcept { return first() == nullptr; }
207
208 /// Resets this list to zero elements.
209 void reset() noexcept { TNode::next(nullptr); }
210
211 /// Returns the start element of this list.
212 /// @return The first element of this list, respectively \c nullptr if this list is empty.
213 [[nodiscard]]
214 TElement* first() const noexcept { return TNode::next(); }
215
216 /// Hooks the given element to the beginning of this list.
217 /// @param elem The element to insert to at the start.
218 void pushFront( TElement* elem ) noexcept {
219 elem->next( TNode::next() );
220 TNode::next( elem );
221 }
222
223 /// Hooks the given range of elements to the front of this list.
224 /// @param first The first element of the range to insert.
225 /// @param last The last element of the range to insert.
226 void pushFront( TElement* first, TElement* last )
227 {
228 last->next(this->first());
229 TNode::next(first);
230 }
231
232 /// Removes and returns the first element from this list.
233 /// @return A pointer to the element, respectively \c nullptr if the list was empty.
234 TElement* popFront() noexcept {
235 TElement* result= first();
236 if( result )
237 TNode::next(result->next());
238 return result;
239 }
240
241 /// Searches and returns the last element.
242 /// \note
243 /// This method must only be invoked on non-empty lists (#".isEmpty" returns \c false).
244 /// Otherwise, this method has undefined behavior (dereference of a \c nullptr).
245 /// To find the pointer to the last element, use #"findLastBefore" providing \c nullptr.
246 /// @return The last element of this list.
247 [[nodiscard]]
248 TElement* findLast() const noexcept {
249 TElement* elem= first();
250 while( elem->hasNext() )
251 elem= elem->next();
252 return elem;
253 }
254
255 /// Searches and returns the last element.
256 /// @param hint An element of this list used to start the search.
257 /// @return The last element of this list.
258 [[nodiscard]]
259 TElement* findLast( TElement* hint ) const noexcept {
260 TElement* elem= hint;
261 while( elem->hasNext() )
262 elem= elem->next();
263 return elem;
264 }
265
266 /// Searches the node or element that points to the given element.
267 /// \attention The element has to exist. Otherwise, a \c nullptr exception will occur!
268 /// @param elem The element to search for.
269 /// @return The node (this object) or element pointing to \p{elem}.
270 [[nodiscard]]
271 TElement* findLastBefore( TElement* elem ) noexcept {
272 TNode* it= this;
273 while( !it->pointsTo(elem) )
274 it= it->next();
275 return static_cast<TElement*>( it );
276 }
277
278 /// Searches the predecessor of the given element using #"findLastBefore" and unhooks the element
279 /// from the list.
280 /// \attention
281 /// It is not checked whether a predecessor was found, aka whether \p{elem} is an element
282 /// of this list. If not, the behavior is undefined (<c>nullptr access</c>).<br>
283 /// Furthermore, the successor of given \p{elem} is not changed, although it is removed
284 /// from the list.
285 ///
286 /// @param elem The element to remove.
287 /// @return The node (this object) or element that pointed to given \p{elem} before the
288 /// invocation and now points to the successor of \p{elem}.
289 TNode* findAndRemove( TElement* elem ) noexcept {
290 TNode* previous= findLastBefore(elem);
291 previous->removeNext();
292 return previous;
293 }
294
295 /// Counts the number of elements found in the range starting with this list's first element and
296 /// ending with the element before \p{end}.
297 /// @param end The element after the last one to count.
298 /// Defaults to a \c nullptr marking the end of the list.
299 /// @return The number of elements in the range.
300 [[nodiscard]]
301 integer count( TElement* end= nullptr ) const noexcept { return TNode::count( end ); }
302}; // struct SidiListHook
303
304} // namespace [alib::lang]
#define ALIB_EXPORT
platform_specific integer
Definition integers.hpp:32
SidiListHook(const SidiListHook &copy)=delete
void reset() noexcept
Resets this list to zero elements.
Definition sidilist.hpp:209
TElement * first() const noexcept
Definition sidilist.hpp:214
TElement * findLast(TElement *hint) const noexcept
Definition sidilist.hpp:259
void pushFront(TElement *elem) noexcept
Definition sidilist.hpp:218
SidiListHook() noexcept
Default constructor. Initializes this list to be empty.
Definition sidilist.hpp:182
TElement * findLast() const noexcept
Definition sidilist.hpp:248
SidiNodeBase< Element > TNode
Definition sidilist.hpp:179
TNode * findAndRemove(TElement *elem) noexcept
Definition sidilist.hpp:289
TElement * popFront() noexcept
Definition sidilist.hpp:234
bool isEmpty() const noexcept
Definition sidilist.hpp:206
void pushFront(TElement *first, TElement *last)
Definition sidilist.hpp:226
SidiListHook(SidiListHook &&) noexcept=default
TElement * findLastBefore(TElement *elem) noexcept
Definition sidilist.hpp:271
integer count(TElement *end=nullptr) const noexcept
Definition sidilist.hpp:301
SidiNodeBase() noexcept=default
Default constructor. (Does not initialize the pointer.).
TElement * addBehind(TElement *elem) noexcept
Definition sidilist.hpp:139
TElement * removeNext() noexcept
Definition sidilist.hpp:115
TElement * removeRangeBehind(TElement *last) noexcept
Definition sidilist.hpp:130
TElement * next() const
Definition sidilist.hpp:97
bool pointsTo(const SidiNodeBase *elem) const
Definition sidilist.hpp:108
integer count(SidiNodeBase *end=nullptr) const noexcept
Definition sidilist.hpp:153