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