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 <type_traits>
79 
80 
81 namespace lib {
82 
83  namespace error = lumiera::error;
84  using error::LERR_(CAPACITY);
85  using error::LERR_(INDEX_BOUNDS);
86 
87 
88 
98  template
99  < class I
100  , size_t siz = sizeof(I)
101  >
104  {
105 
106  public:
115  {
116 
117  mutable char buf_[siz];
118 
119  public:
120 
121  I&
122  accessObj() const
123  {
124  return reinterpret_cast<I&> (buf_);
125  }
126 
127  void
128  destroy()
129  {
130  accessObj().~I();
131  }
132 
133 
134 
135 
137  template<class TY, typename...ARGS>
138  TY&
139  create (ARGS&& ...args)
140  {
141  static_assert ( meta::is_Subclass<TY,I>()
142  && sizeof(TY) <= siz,
143  "ElementHolder buffer too small");
144 
145  return *new(&buf_) TY (std::forward<ARGS> (args)...);
146  }
147  };
148 
149 
150 
151 
152 
153 
154  ~ScopedCollection ()
155  {
156  clear();
157  }
158 
159  explicit
160  ScopedCollection (size_t maxElements)
161  : level_(0)
162  , capacity_(maxElements)
163  , elements_(new ElementHolder[maxElements])
164  { }
165 
173  template<class CTOR>
174  ScopedCollection (size_t maxElements, CTOR builder)
175  : level_(0)
176  , capacity_(maxElements)
177  , elements_(new ElementHolder[maxElements])
178  {
179  populate_by (builder);
180  }
181 
190  template<class TY>
191  ScopedCollection (size_t maxElements, void (TY::*builder) (ElementHolder&), TY * const instance)
192  : level_(0)
193  , capacity_(maxElements)
194  , elements_(new ElementHolder[maxElements])
195  {
196  populate_by (builder,instance);
197  }
198 
199  /* == some pre-defined Builders == */
200 
201  class FillAll;
202 
203  template<typename TY>
204  class FillWith;
205 
206  template<typename IT>
207  class PullFrom;
208 
209  template<typename IT>
210  static PullFrom<IT>
211  pull (IT iter)
212  {
213  return PullFrom<IT> (iter);
214  }
215 
216  void
217  clear()
218  {
219  REQUIRE (level_ <= capacity_, "Storage corrupted");
220 
221  while (level_)
222  {
223  --level_;
224  try {
225  elements_[level_].destroy();
226  }
227  ERROR_LOG_AND_IGNORE (progress, "Clean-up of element in ScopedCollection")
228  }
229  }
230 
232  void
234  try {
235  while (level_ < capacity_)
236  {
237  elements_[level_].template create<I>();
238  ++level_;
239  }
240  }
241  catch(...)
242  {
243  WARN (progress, "Failure while populating ScopedCollection. "
244  "All elements will be discarded");
245  clear();
246  throw;
247  }
248 
256  template<class CTOR>
257  void
258  populate_by (CTOR builder)
259  try {
260  while (level_ < capacity_)
261  {
262  ElementHolder& storageFrame (elements_[level_]);
263  builder (storageFrame);
264  ++level_;
265  } }
266  catch(...)
267  {
268  WARN (progress, "Failure while populating ScopedCollection. "
269  "All elements will be discarded");
270  clear();
271  throw;
272  }
273 
278  template<class TY>
279  void
280  populate_by (void (TY::*builder) (ElementHolder&), TY * const instance)
281  try {
282  while (level_ < capacity_)
283  {
284  ElementHolder& storageFrame (elements_[level_]);
285  (instance->*builder) (storageFrame);
286  ++level_;
287  } }
288  catch(...)
289  {
290  WARN (progress, "Failure while populating ScopedCollection. "
291  "All elements will be discarded");
292  clear();
293  throw;
294  }
295 
296 
297 
301  I&
303  {
304  return emplace<I>();
305  }
306 
307 
312  template<class TY =I, typename...ARGS>
313  TY&
314  emplace (ARGS&& ...args)
315  {
316  __ensureSufficientCapacity();
317  TY& newElm = elements_[level_].template create<TY>(std::forward<ARGS> (args)...);
318  ++level_;
319  return newElm;
320  }
321 
322 
323 
324  /* === Element access and iteration === */
325 
326  I&
327  operator[] (size_t index) const
328  {
329  if (index < level_)
330  return elements_[index].accessObj();
331 
332  throw error::Logic ("Attempt to access not (yet) existing object in ScopedCollection"
333  , LERR_(INDEX_BOUNDS));
334  }
335 
336 
337 
340 
341 
342  iterator begin() { return iterator (this, _access_begin()); }
343  const_iterator begin() const { return const_iterator (this, _access_begin()); }
344  iterator end () { return iterator(); }
345  const_iterator end () const { return const_iterator(); }
346 
347 
348  size_t size () const { return level_; }
349  size_t capacity () const { return capacity_; }
350  bool empty () const { return 0 == level_; }
351 
352 
353  // use in standard range for loops...
354  friend iterator begin (ScopedCollection& sco) { return sco.begin(); }
355  friend const iterator begin (ScopedCollection const& sco){ return sco.begin(); }
356  friend iterator end (ScopedCollection& sco) { return sco.end(); }
357  friend const iterator end (ScopedCollection const& sco){ return sco.end(); }
358 
359 
360  private:
361  /* ==== Storage: heap allocated array of element buffers ==== */
362 
363  typedef std::unique_ptr<ElementHolder[]> ElementStorage;
364 
365  size_t level_;
366  size_t capacity_;
367  ElementStorage elements_;
368 
369 
370 
371  void
372  __ensureSufficientCapacity()
373  {
374  if (level_ >= capacity_)
375  throw error::State ("ScopedCollection exceeding the initially defined capacity"
376  , LERR_(CAPACITY));
377  }
378 
379 
380  /* ==== internal callback API for the iterator ==== */
381 
386  friend void
387  iterNext (const ScopedCollection*, I* & pos)
388  {
389  ElementHolder* & storageLocation = reinterpret_cast<ElementHolder* &> (pos);
390  ++storageLocation;
391  }
392 
393  friend void
394  iterNext (const ScopedCollection*, const I* & pos)
395  {
396  const ElementHolder* & storageLocation = reinterpret_cast<const ElementHolder* &> (pos);
397  ++storageLocation;
398  }
399 
401  template<typename POS>
402  friend bool
403  checkPoint (const ScopedCollection* src, POS & pos)
404  {
405  REQUIRE (src);
406  if ((pos) && (pos < src->_access_end()))
407  return true;
408  else
409  {
410  pos = 0;
411  return false;
412  } }
413 
414 
415  I* _access_begin() const { return & elements_[0].accessObj(); }
416  I* _access_end() const { return & elements_[level_].accessObj(); }
417 
418  };
419 
420 
421 
422 
423  /* === Supplement: pre-defined element builders === */
424 
434  template<class I, size_t siz>
435  class ScopedCollection<I,siz>::FillAll
436  {
437  public:
438  void
439  operator() (typename ScopedCollection<I,siz>::ElementHolder& storage)
440  {
441  storage.template create<I>();
442  }
443  };
444 
445  template<class I, size_t siz>
446  template<typename TY>
447  class ScopedCollection<I,siz>::FillWith
448  {
449  public:
450  void
451  operator() (typename ScopedCollection<I,siz>::ElementHolder& storage)
452  {
453  storage.template create<TY>();
454  }
455  };
456 
466  template<class I, size_t siz>
467  template<typename IT>
468  class ScopedCollection<I,siz>::PullFrom
469  {
470  IT iter_;
471 
472  using ElementType = typename meta::ValueTypeBinding<IT>::value_type;
473 
474  public:
475  PullFrom (IT source)
476  : iter_(source)
477  { }
478 
479  void
480  operator() (typename ScopedCollection<I,siz>::ElementHolder& storage)
481  {
482  storage.template create<ElementType> (*iter_);
483  ++iter_;
484  }
485  };
486 
487 
488 
489 } // namespace lib
490 #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:272
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:196
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:316
Adapter for building an implementation of the »Lumiera Forward Iterator« concept. ...
friend void iterNext(const ScopedCollection *, I *&pos)
Iteration-logic: switch to next position.