Lumiera  0.pre.03
»edit your freedom«
scoped-collection.hpp
Go to the documentation of this file.
1 /*
2  SCOPED-COLLECTION.hpp - managing a fixed collection of noncopyable polymorphic objects
3 
4  Copyright (C) Lumiera.org
5  2012, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
69 #ifndef LIB_SCOPED_COLLECTION_H
70 #define LIB_SCOPED_COLLECTION_H
71 
72 
73 #include "lib/error.hpp"
74 #include "lib/nocopy.hpp"
75 #include "lib/meta/trait.hpp"
76 #include "lib/iter-adapter.hpp"
77 
78 #include <cstddef>
79 #include <type_traits>
80 
81 
82 namespace lib {
83 
84  namespace error = lumiera::error;
85  using LERR_(INDEX_BOUNDS);
86  using LERR_(CAPACITY);
87 
88 
89 
99  template
100  < class I
101  , size_t siz = sizeof(I)
102  >
105  {
106 
107  public:
116  {
117  alignas(I) mutable
118  std::byte buf_[siz];
119 
120  public:
121 
122  I&
123  accessObj() const
124  {
125  return * std::launder (reinterpret_cast<I*> (&buf_));
126  }
127 
128  void
129  destroy()
130  {
131  accessObj().~I();
132  }
133 
134 
135 
136 
138  template<class TY, typename...ARGS>
139  TY&
140  create (ARGS&& ...args)
141  {
142  static_assert ( meta::is_Subclass<TY,I>()
143  && sizeof(TY) <= siz,
144  "ElementHolder buffer too small");
145 
146  return *new(&buf_) TY (std::forward<ARGS> (args)...);
147  }
148  };
149 
150 
151 
152 
153 
154 
155  ~ScopedCollection ()
156  {
157  clear();
158  }
159 
160  explicit
161  ScopedCollection (size_t maxElements)
162  : level_(0)
163  , capacity_(maxElements)
164  , elements_(new ElementHolder[maxElements])
165  { }
166 
174  template<class CTOR>
175  ScopedCollection (size_t maxElements, CTOR builder)
176  : level_(0)
177  , capacity_(maxElements)
178  , elements_(new ElementHolder[maxElements])
179  {
180  populate_by (builder);
181  }
182 
191  template<class TY>
192  ScopedCollection (size_t maxElements, void (TY::*builder) (ElementHolder&), TY * const instance)
193  : level_(0)
194  , capacity_(maxElements)
195  , elements_(new ElementHolder[maxElements])
196  {
197  populate_by (builder,instance);
198  }
199 
200  /* == some pre-defined Builders == */
201 
202  class FillAll;
203 
204  template<typename TY>
205  class FillWith;
206 
207  template<typename IT>
208  class PullFrom;
209 
210  template<typename IT>
211  static PullFrom<IT>
212  pull (IT iter)
213  {
214  return PullFrom<IT> (iter);
215  }
216 
217  void
218  clear()
219  {
220  REQUIRE (level_ <= capacity_, "Storage corrupted");
221 
222  while (level_)
223  {
224  --level_;
225  try {
226  elements_[level_].destroy();
227  }
228  ERROR_LOG_AND_IGNORE (progress, "Clean-up of element in ScopedCollection")
229  }
230  }
231 
233  void
235  try {
236  while (level_ < capacity_)
237  {
238  elements_[level_].template create<I>();
239  ++level_;
240  }
241  }
242  catch(...)
243  {
244  WARN (progress, "Failure while populating ScopedCollection. "
245  "All elements will be discarded");
246  clear();
247  throw;
248  }
249 
257  template<class CTOR>
258  void
259  populate_by (CTOR builder)
260  try {
261  while (level_ < capacity_)
262  {
263  ElementHolder& storageFrame (elements_[level_]);
264  builder (storageFrame);
265  ++level_;
266  } }
267  catch(...)
268  {
269  WARN (progress, "Failure while populating ScopedCollection. "
270  "All elements will be discarded");
271  clear();
272  throw;
273  }
274 
279  template<class TY>
280  void
281  populate_by (void (TY::*builder) (ElementHolder&), TY * const instance)
282  try {
283  while (level_ < capacity_)
284  {
285  ElementHolder& storageFrame (elements_[level_]);
286  (instance->*builder) (storageFrame);
287  ++level_;
288  } }
289  catch(...)
290  {
291  WARN (progress, "Failure while populating ScopedCollection. "
292  "All elements will be discarded");
293  clear();
294  throw;
295  }
296 
297 
298 
302  I&
304  {
305  return emplace<I>();
306  }
307 
308 
313  template<class TY =I, typename...ARGS>
314  TY&
315  emplace (ARGS&& ...args)
316  {
317  __ensureSufficientCapacity();
318  TY& newElm = elements_[level_].template create<TY>(std::forward<ARGS> (args)...);
319  ++level_;
320  return newElm;
321  }
322 
323 
324 
325  /* === Element access and iteration === */
326 
327  I&
328  operator[] (size_t index) const
329  {
330  if (index < level_)
331  return elements_[index].accessObj();
332 
333  throw error::Logic ("Attempt to access not (yet) existing object in ScopedCollection"
334  , LERR_(INDEX_BOUNDS));
335  }
336 
337 
338 
341 
342 
343  iterator begin() { return iterator (this, _access_begin()); }
344  const_iterator begin() const { return const_iterator (this, _access_begin()); }
345  iterator end () { return iterator(); }
346  const_iterator end () const { return const_iterator(); }
347 
348 
349  size_t size () const { return level_; }
350  size_t capacity () const { return capacity_; }
351  bool empty () const { return 0 == level_; }
352 
353 
354  // use in standard range for loops...
355  friend iterator begin (ScopedCollection& sco) { return sco.begin(); }
356  friend const iterator begin (ScopedCollection const& sco){ return sco.begin(); }
357  friend iterator end (ScopedCollection& sco) { return sco.end(); }
358  friend const iterator end (ScopedCollection const& sco){ return sco.end(); }
359 
360 
361  private:
362  /* ==== Storage: heap allocated array of element buffers ==== */
363 
364  typedef std::unique_ptr<ElementHolder[]> ElementStorage;
365 
366  size_t level_;
367  size_t capacity_;
368  ElementStorage elements_;
369 
370 
371 
372  void
373  __ensureSufficientCapacity()
374  {
375  if (level_ >= capacity_)
376  throw error::State ("ScopedCollection exceeding the initially defined capacity"
377  , LERR_(CAPACITY));
378  }
379 
380 
381  /* ==== internal callback API for the iterator ==== */
382 
387  friend void
388  iterNext (const ScopedCollection*, I* & pos)
389  {
390  ElementHolder* & storageLocation = reinterpret_cast<ElementHolder* &> (pos);
391  ++storageLocation;
392  }
393 
394  friend void
395  iterNext (const ScopedCollection*, const I* & pos)
396  {
397  const ElementHolder* & storageLocation = reinterpret_cast<const ElementHolder* &> (pos);
398  ++storageLocation;
399  }
400 
402  template<typename POS>
403  friend bool
404  checkPoint (const ScopedCollection* src, POS & pos)
405  {
406  REQUIRE (src);
407  if ((pos) && (pos < src->_access_end()))
408  return true;
409  else
410  {
411  pos = 0;
412  return false;
413  } }
414 
415 
416  I* _access_begin() const { return & elements_[0].accessObj(); }
417  I* _access_end() const { return & elements_[level_].accessObj(); }
418 
419  };
420 
421 
422 
423 
424  /* === Supplement: pre-defined element builders === */
425 
435  template<class I, size_t siz>
436  class ScopedCollection<I,siz>::FillAll
437  {
438  public:
439  void
440  operator() (typename ScopedCollection<I,siz>::ElementHolder& storage)
441  {
442  storage.template create<I>();
443  }
444  };
445 
446  template<class I, size_t siz>
447  template<typename TY>
448  class ScopedCollection<I,siz>::FillWith
449  {
450  public:
451  void
452  operator() (typename ScopedCollection<I,siz>::ElementHolder& storage)
453  {
454  storage.template create<TY>();
455  }
456  };
457 
467  template<class I, size_t siz>
468  template<typename IT>
469  class ScopedCollection<I,siz>::PullFrom
470  {
471  IT iter_;
472 
473  using ElementType = typename meta::ValueTypeBinding<IT>::value_type;
474 
475  public:
476  PullFrom (IT source)
477  : iter_(source)
478  { }
479 
480  void
481  operator() (typename ScopedCollection<I,siz>::ElementHolder& storage)
482  {
483  storage.template create<ElementType> (*iter_);
484  ++iter_;
485  }
486  };
487 
488 
489 
490 } // namespace lib
491 #endif
A fixed collection of non-copyable polymorphic objects.
TY & create(ARGS &&...args)
place object of type TY, forwarding ctor arguments
ScopedCollection(size_t maxElements, void(TY::*builder)(ElementHolder &), TY *const instance)
variation of RAII-style: using a builder function, which is a member of some object.
#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:275
Helper template(s) for creating Lumiera Forward Iterators.
Any copy and copy construction prohibited.
Definition: nocopy.hpp:46
TY & emplace(ARGS &&...args)
push new entry at the end of this container and build object of type TY in place there ...
Implementation namespace for support and library code.
void populate_by(CTOR builder)
init all elements at once, invoking a builder functor for each.
Storage Frame to hold one Child object.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:199
Mix-Ins to allow or prohibit various degrees of copying and cloning.
ScopedCollection(size_t maxElements, CTOR builder)
creating a ScopedCollection in RAII-style: The embedded elements will be created immediately.
friend bool checkPoint(const ScopedCollection *src, POS &pos)
Iteration-logic: detect iteration end.
void populate()
init all elements default constructed
Helpers for type detection, type rewriting and metaprogramming.
Lumiera error handling (C++ interface).
void populate_by(void(TY::*builder)(ElementHolder &), TY *const instance)
variation of element initialisation, invoking a member function of some manager object for each colle...
static PullFrom< IT > pull(IT iter)
fills by copy-constructing values pulled from the iterator IT
fills the ScopedCollection with default constructed TY-instances
fills the ScopedCollection with default constructed I-instances
I & emplaceElement()
push a new element of default type to the end of this container
verify compliance to an interface by subtype check
Definition: trait.hpp:318
Adapter for building an implementation of the »Lumiera Forward Iterator« concept. ...
friend void iterNext(const ScopedCollection *, I *&pos)
Iteration-logic: switch to next position.