Lumiera  0.pre.03
»edit your freedom«
linked-elements.hpp
Go to the documentation of this file.
1 /*
2  LINKED-ELEMENTS.hpp - configurable intrusive single linked list template
3 
4  Copyright (C)
5  2012, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 */
13 
53 #ifndef LIB_LINKED_ELEMENTS_H
54 #define LIB_LINKED_ELEMENTS_H
55 
56 
57 #include "lib/error.hpp"
58 #include "lib/nocopy.hpp"
59 #include "lib/iter-adapter.hpp"
60 #include "lib/allocator-handle.hpp"
61 #include "lib/util.hpp"
62 
63 #include <utility>
64 #include <memory>
65 
66 
67 namespace lib {
68 
69  namespace error = lumiera::error;
70  using LERR_(INDEX_BOUNDS);
71  using util::unConst;
72 
73 
74  namespace linked_elements {
75 
83  template<class ALO>
87  {
89 
90  using CustomAllocator = ALO;
91  };
92 
93 
95  template<class N>
97 
98 
99 
100 
110  struct NoOwnership
111  {
112  typedef void* CustomAllocator;
113 
117  void
118  dispose (void*)
119  {
120  /* does nothing */
121  }
122 
123  template<class TY, typename...ARGS>
124  TY&
125  create (ARGS&&...)
126  {
127  static_assert ("NoOwnership allocation strategy can not allocate elements");
128  } // ... you'll have to do that yourself (that's the whole point of using this strategy)
129  };
130 
131  }//(END)namespace linked_elements (predefined policies)
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142  /****************************************************************************/
154  template
155  < class N
157  >
159  : ALO
160  {
161  N* head_;
162 
163 
164  public:
165 
166  ~LinkedElements() noexcept
167  {
168  clear();
169  }
170 
172  : head_{nullptr}
173  { }
174 
175  LinkedElements (LinkedElements const&) = default;
177  : head_{rr.head_}
178  { // possibly transfer ownership
179  rr.head_ = nullptr;
180  }
181 
186  explicit
187  LinkedElements (typename ALO::CustomAllocator allo)
188  : ALO{allo}
189  , head_{nullptr}
190  { }
191 
199  template<class IT>
201  : head_{nullptr}
202  {
203  try {
204  pushAll (std::forward<IT> (elements));
205  }
206  catch(...)
207  {
208  WARN (progress, "Failure while populating LinkedElements list. "
209  "All elements will be discarded");
210  clear();
211  throw;
212  } }
213 
214 
215 
217  void
218  clear() noexcept
219  {
220  while (head_)
221  {
222  N* elm = head_;
223  head_ = head_->next;
224  try {
225  ALO::dispose (elm);
226  }
227  ERROR_LOG_AND_IGNORE (progress, "Clean-up of element in LinkedElements list")
228  }
229  }
230 
231 
236  template<class IT>
237  void
239  {
240  for ( ; elements; ++elements )
241  push (*elements);
242  }
243 
244 
245 
246 
251  template<typename TY>
252  TY&
253  push (TY& elm) noexcept
254  {
255  elm.next = head_;
256  head_ = &elm;
257  return elm;
258  }
259 
260 
261 
263  template<class TY =N, typename...ARGS>
264  TY&
265  emplace (ARGS&& ...args)
266  {
267  return push (* ALO::template create<TY> (std::forward<ARGS> (args)...));
268  }
269 
270 
271 
280  {
281  if (not empty())
282  {
283  N* p = head_->next;
284  head_->next = nullptr;
285  while (p)
286  {
287  N& n = *p;
288  p = p->next;
289  push (n);
290  } }
291  return *this;
292  }
293 
294 
295 
296 
297  /* === Element access and iteration === */
298 
299  N&
300  operator[] (size_t index) const
301  {
302  N* p = head_;
303  while (p and index)
304  {
305  p = p->next;
306  --index;
307  }
308 
309  if (!p or index)
310  throw error::Logic ("Attempt to access element beyond the end of LinkedElements list"
311  , LERR_(INDEX_BOUNDS));
312  else
313  return *p;
314  }
315 
316 
318  N&
319  top() const
320  {
321  REQUIRE (head_, "NIL");
322  return *(unConst(this)->head_);
323  }
324 
325 
327  size_t
328  size() const
329  {
330  uint count=0;
331  N* p = head_;
332  while (p)
333  {
334  p = p->next;
335  ++count;
336  }
337  return count;
338  }
339 
340 
341  bool
342  empty() const
343  {
344  return !head_;
345  }
346 
347  private:
355  {
356  N* node;
357 
358  IterationState (N* p =nullptr)
359  : node{p}
360  { }
361 
362  /* ==== internal callback API for the iterator ==== */
363 
369  void
371  {
372  node = node->next;
373  }
374 
376  bool
377  checkPoint() const
378  {
379  return bool(node);
380  }
381 
382  N&
383  yield() const
384  {
385  REQUIRE (node);
386  return * unConst(this)->node;
387  }
388 
389  friend bool
390  operator== (IterationState const& il, IterationState const& ir)
391  {
392  return il.node == ir.node;
393  }
394  };
395 
396  public:
399 
400 
401  iterator begin() { return iterator (head_); }
402  const_iterator begin() const { return const_iterator (head_); }
403  iterator end () { return iterator(); }
404  const_iterator end () const { return const_iterator(); }
405 
406  };
407 
408 
411  template<class N>
412  auto&
413  asLinkedElements (N* const& anchor)
414  {
416  return reinterpret_cast<Linked const&>(anchor);
417  }
418 
419 
420 
421 } // namespace lib
422 #endif /*LIB_LINKED_ELEMENTS_H*/
LinkedElements & reverse()
Mutate the complete list to change the order of elements.
IterQueue< T > elements(T const &elm)
convenience free function to build an iterable sequence
Definition: iter-stack.hpp:292
TY & emplace(ARGS &&...args)
prepend object of type TY, forwarding ctor args
Iteration is just following the single linked list.
< Concepts and Adaptors for custom memory management
TY * create(ARGS &&...args)
create new element using the embedded allocator
void pushAll(IT elements)
convenience shortcut to add all the elements yielded by the given Lumiera Forward Iterator ...
#define ERROR_LOG_AND_IGNORE(_FLAG_, _OP_DESCR_)
convenience shortcut for a sequence of catch blocks just logging and consuming an error...
Definition: error.hpp:266
Intrusive single linked list, possibly taking ownership of node elements.
Helper template(s) for creating Lumiera Forward Iterators.
Types marked with this mix-in may be moved but not copied.
Definition: nocopy.hpp:49
A front-end/concept to allow access to custom memory management.
< allocation policies for the LinkedElements list container
LinkedElements(IT &&elements)
creating a LinkedElements list in RAII-style:
Implementation namespace for support and library code.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
void iterNext()
Iteration-logic: switch to next position.
Mix-Ins to allow or prohibit various degrees of copying and cloning.
Another Lumiera Forward Iterator building block, based on incorporating a state type as »*State Core*...
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
void dispose(void *)
this policy doesn&#39;t take ownership and thus never discards anything
void clear() noexcept
Lumiera error handling (C++ interface).
auto & asLinkedElements(N *const &anchor)
transiently reinterpret an element pointer as const LinkedElements, allowing to count, iterate or subscript a chain of elements
TY & push(TY &elm) noexcept
accept the given element and prepend it to the list of elements; depending on the allocation policy...
bool checkPoint() const
Iteration-logic: detect iteration end.
LinkedElements(typename ALO::CustomAllocator allo)
Policy for LinkedElements: never create or destroy any elements, only allow to add already existing n...