Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
several-builder.hpp
Go to the documentation of this file.
1/*
2 SEVERAL-BUILDER.hpp - builder for a limited fixed collection of elements
3
4 Copyright (C)
5 2024, 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
91#ifndef LIB_SEVERAL_BUILDER_H
92#define LIB_SEVERAL_BUILDER_H
93
94
95#include "lib/error.hpp"
96#include "lib/several.hpp"
97#include "include/limits.hpp"
98#include "lib/iter-explorer.hpp"
99#include "lib/format-string.hpp"
100#include "lib/meta/trait.hpp"
101#include "lib/util.hpp"
102
103#include <functional>
104#include <cstring>
105#include <utility>
106#include <vector>
107
108
109
110namespace lib {
111 namespace err = lumiera::error;
112
113 using std::vector;
114 using std::forward;
115 using std::move;
116 using std::byte;
117
118 namespace {
123
124
125 using util::max;
126 using util::min;
127 using util::_Fmt;
128 using util::unConst;
129 using util::positiveDiff;
130 using std::is_nothrow_move_constructible_v;
131 using std::is_trivially_move_constructible_v;
132 using std::is_trivially_destructible_v;
133 using std::has_virtual_destructor_v;
134 using std::is_trivially_copyable_v;
135 using std::is_copy_constructible_v;
136 using std::is_object_v;
137 using std::is_volatile_v;
138 using std::is_const_v;
139 using std::is_same_v;
141
143
144
149 template<typename TY>
150 inline constexpr size_t
152 {
153 size_t quant = alignof(TY);
154 size_t siz = max (sizeof(TY), quant);
155 size_t req = (siz/quant) * quant;
156 if (req < siz)
157 req += quant;
158 return req;
159 }
160
162 inline constexpr size_t
163 alignRes (size_t alignment)
164 {
165 return positiveDiff (alignment, alignof(void*));
166 }
167 }//(End)helpers
168
169
170 namespace allo {// Allocation management policies
171
179 template<class I, template<typename> class ALO>
181 : protected ALO<std::byte>
182 {
183 using Allo = ALO<std::byte>;
184 using AlloT = std::allocator_traits<Allo>;
185 using Bucket = ArrayBucket<I>;
186
187 template<typename X>
188 using XAlloT = AlloT::template rebind_traits<std::remove_cv_t<X>>;
189
190 Allo& baseAllocator() { return *this; }
191
192 template<typename X>
193 auto
195 {
196 using XAllo = XAlloT<X>::allocator_type;
197 if constexpr (std::is_constructible_v<XAllo, Allo>)
198 return XAllo{baseAllocator()};
199 else
200 return XAllo{};
201 }
202
203 public:
205 : Allo{std::move (allo)}
206 { }
207
209 template<typename X>
211 : ElementFactory{relatedFac.baseAllocator()}
212 { }
213
214 template<typename O, template<typename> class XALO>
215 friend class ElementFactory;
216
217
218 Bucket*
219 create (size_t cnt, size_t spread, size_t alignment =alignof(I))
220 {
221 REQUIRE (cnt);
222 REQUIRE (spread);
223 size_t storageBytes = Bucket::storageOffset + cnt*spread;
224 storageBytes += alignRes (alignment); // over-aligned data => reserve for alignment padding
225 // Step-1 : acquire the raw storage buffer
226 std::byte* loc = AlloT::allocate (baseAllocator(), storageBytes);
227 ENSURE (0 == size_t(loc) % alignof(void*));
228
229 size_t offset = (size_t(loc) + Bucket::storageOffset) % alignment;
230 if (offset) // padding needed to next aligned location
231 offset = alignment - offset;
232 offset += Bucket::storageOffset;
233 ASSERT (storageBytes - offset >= cnt*spread);
234 Bucket* bucket = reinterpret_cast<Bucket*> (loc);
235
236 using BucketAlloT = XAlloT<Bucket>;
237 auto bucketAllo = adaptAllocator<Bucket>();
238 // Step-2 : construct the Bucket metadata | ▽ ArrayBucket ctor arg ▽
239 try { BucketAlloT::construct (bucketAllo, bucket, storageBytes, offset, spread); }
240 catch(...)
241 {
242 AlloT::deallocate (baseAllocator(), loc, storageBytes);
243 throw;
244 }
245 return bucket;
246 };
247
248
249 template<class E, typename...ARGS>
250 E&
251 createAt (Bucket* bucket, size_t idx, ARGS&& ...args)
252 {
253 REQUIRE (bucket);
254 using ElmAlloT = XAlloT<E>;
255 auto elmAllo = adaptAllocator<E>();
256 E* loc = reinterpret_cast<E*> (& unConst(bucket->subscript (idx)));
257 ElmAlloT::construct (elmAllo, loc, forward<ARGS> (args)...);
258 ENSURE (loc);
259 return *loc;
260 };
261
262
263 template<class E>
264 void
265 destroy (ArrayBucket<I>* bucket)
266 {
267 REQUIRE (bucket);
268 if (bucket->isArmed())
269 { // ensure the bucket's destructor is invoked
270 // and in turn itself invokes this function
271 bucket->destroy();
272 return;
273 }
274 if (not is_trivially_destructible_v<E>)
275 {
276 size_t cnt = bucket->cnt;
277 using ElmAlloT = XAlloT<E>;
278 auto elmAllo = adaptAllocator<E>();
279 for (size_t idx=0; idx<cnt; ++idx)
280 {
281 E* elm = reinterpret_cast<E*> (& unConst(bucket->subscript (idx)));
282 ElmAlloT::destroy (elmAllo, elm);
283 }
284 }
285 size_t storageBytes = bucket->getAllocSize();
286 std::byte* loc = reinterpret_cast<std::byte*> (bucket);
287 AlloT::deallocate (baseAllocator(), loc, storageBytes);
288 };
289 };
290
291
298 template<class I, class E, template<typename> class ALO>
300 : ElementFactory<I, ALO>
301 {
303 using Bucket = ArrayBucket<I>;
304
305 using Fac::Fac; // pass-through ctor
306
308 size_t static constexpr ALLOC_LIMIT = size_t(-1) / sizeof(E);
309
311 bool canExpand(Bucket*, size_t){ return false; }
312
313 Bucket*
314 realloc (Bucket* data, size_t cnt, size_t spread)
315 {
316 Bucket* newBucket = Fac::create (cnt, spread, alignof(E));
317 if (data)
318 try {
319 newBucket->installDestructor (data->getDtor());
320 size_t elms = min (cnt, data->cnt);
321 for (size_t idx=0; idx<elms; ++idx)
322 moveElem(idx, data, newBucket);
323 data->destroy();
324 }
325 catch(...)
326 { newBucket->destroy(); }
327 return newBucket;
328 }
329
330 void
331 moveElem (size_t idx, Bucket* src, Bucket* tar)
332 {
333 if constexpr (is_trivially_copyable_v<E>)
334 {
335 void* oldPos = & src->subscript(idx);
336 void* newPos = & tar->subscript(idx);
337 size_t amount = min (src->spread, tar->spread);
338 std::memmove (newPos, oldPos, amount);
339 }
340 else
341 if constexpr (is_nothrow_move_constructible_v<E>
342 or is_copy_constructible_v<E>)
343 {
344 E& oldElm = reinterpret_cast<E&> (src->subscript (idx));
345 Fac::template createAt<E> (tar, idx
346 ,std::move_if_noexcept (oldElm));
347 }
348 else
349 {
350 (void)src; (void)tar;
351 NOTREACHED("realloc immovable type (neither trivially nor typed movable)");
352 // this alternative code section is very important, because it allows
353 // to instantiate this code even for »noncopyable« types, assuming that
354 // sufficient storage is reserved beforehand, and thus copying is irrelevant.
355 // For context: the std::vector impl. from libStdC++ is lacking this option.
356 }
357 tar->cnt = idx+1; // mark fill continuously for proper clean-up after exception
358 }
359 };
360
362 template<class I, class E>
364
365 }//(End) namespace several
366
367
368
369
370
371 /*************************************************/
391 template<class I
392 ,class E =I
393 ,template<class,class> class POL =allo::HeapOwn
394 >
396 : private Several<I>
398 , POL<I,E>
399 {
401 using Policy = POL<I,E>;
402
405
406 public:
407 SeveralBuilder() = default;
408
410 template<typename...ARGS, typename = meta::enable_if<std::is_constructible<Policy,ARGS&&...>>>
411 SeveralBuilder (ARGS&& ...alloInit)
412 : Several<I>{}
413 , Policy{forward<ARGS> (alloInit)...}
414 { }
415
417 Policy& policyConnect() { return *this; }
418
419
420
421 /* ===== Builder API ===== */
422
424 template<template<typename> class ALO =std::void_t
425 ,typename...ARGS>
426 auto withAllocator (ARGS&& ...args);
427
428
430 template<typename TY =E>
432 reserve (size_t cntElm =1
433 ,size_t elmSiz =reqSiz<TY>())
434 {
435 size_t extraElm = positiveDiff (cntElm, Coll::size());
436 ensureElementCapacity<TY> (elmSiz);
437 ensureStorageCapacity<TY> (elmSiz,extraElm);
438 elmSiz = max (elmSiz, Coll::spread());
439 adjustStorage (cntElm, elmSiz);
440 return move(*this);
441 }
442
448 {
449 if (not Coll::empty()
450 or size() < capacity())
451 fitStorage();
452 return move(*this);
453 }
454
456 template<typename VAL, typename...VALS>
458 append (VAL&& val, VALS&& ...vals)
459 {
460 emplace<VAL> (forward<VAL> (val));
461 if constexpr (0 < sizeof...(VALS))
462 return append (forward<VALS> (vals)...);
463 else
464 return move(*this);
465 }
466
468 template<class IT>
470 appendAll (IT&& data)
471 {
472 explore(data).foreach ([this](auto it){ emplaceCopy(it); });
473 return move(*this);
474 }
475
476 template<class X>
478 appendAll (std::initializer_list<X> ili)
479 {
481 for (Val const& x : ili)
482 emplaceNewElm<Val> (x);
483 return move(*this);
484 }
485
487 template<class SEQ>
489 moveAll (SEQ& dataSrc)
490 {
491 explore(dataSrc).foreach ([this](auto it){ emplaceMove(it); });
492 return move(*this);
493 }
494
496 template<typename...ARGS>
498 fillElm (size_t cntNew, ARGS&& ...args)
499 {
500 for ( ; 0<cntNew; --cntNew)
501 emplaceNewElm<E> (forward<ARGS> (args)...);
502 return move(*this);
503 }
504
506 template<class TY, typename...ARGS>
508 emplace (ARGS&& ...args)
509 {
511 emplaceNewElm<Val> (forward<ARGS> (args)...);
512 return move(*this);
513 }
514
515
516 /***********************************************************/
523 {
524 return move (*this);
525 }
526
527 size_t size() const { return Coll::size(); }
528 bool empty() const { return Coll::empty();}
529 size_t capacity() const { return Coll::storageBuffSiz() / Coll::spread(); }
530 size_t capReserve() const { return capacity() - size(); }
531
535 I&
536 operator[] (size_t idx)
537 {
538 if (idx >= Coll::size())
539 throw err::Invalid{_Fmt{"Access index %d >= size(%d)."}
540 % idx % Coll::size()
541 ,LERR_(INDEX_BOUNDS)
542 };
543 return Coll::operator[] (idx);
544 }
545
546
547 private: /* ========= Implementation of element placement ================ */
548 template<class IT>
549 void
550 emplaceCopy (IT& dataSrc)
551 {
552 using Val = IT::value_type;
553 emplaceNewElm<Val> (*dataSrc);
554 }
555
556 template<class IT>
557 void
558 emplaceMove (IT& dataSrc)
559 {
560 using Val = IT::value_type;
561 emplaceNewElm<Val> (move (*dataSrc));
562 }
563
564 template<class TY, typename...ARGS>
565 void
566 emplaceNewElm (ARGS&& ...args)
567 {
568 static_assert (is_object_v<TY> and not (is_const_v<TY> or is_volatile_v<TY>));
569
570 probeMoveCapability<TY>(); // mark when target type is not (trivially) movable
571 ensureElementCapacity<TY>(); // sufficient or able to adapt spread
572 ensureStorageCapacity<TY>(); // sufficient or able to grow buffer
573
574 size_t elmSiz = reqSiz<TY>();
575 size_t newPos = Coll::size();
576 size_t newCnt = Coll::empty()? INITIAL_ELM_CNT : newPos+1;
577 adjustStorage (newCnt, max (elmSiz, Coll::spread()));
578 ENSURE (Coll::data_);
579 ensureDeleter<TY>();
580 Policy::template createAt<TY> (Coll::data_, newPos, forward<ARGS> (args)...);
581 Coll::data_->cnt = newPos+1;
582 }
583
587 template<class TY>
588 void
590 {
591 Deleter deleterFunctor = selectDestructor<TY>();
592 if (Coll::data_->isArmed()) return;
593 Coll::data_->installDestructor (move (deleterFunctor));
594 }
595
597 template<class TY>
598 void
599 ensureElementCapacity (size_t requiredSiz =reqSiz<TY>())
600 {
601 if (Coll::spread() < requiredSiz and not (Coll::empty() or canWildMove()))
602 throw err::Invalid{_Fmt{"Unable to place element of type %s (size=%d)"
603 "into Several-container for element size %d."}
604 % util::typeStr<TY>() % requiredSiz % Coll::spread()};
605 }
606
608 template<class TY>
609 void
610 ensureStorageCapacity (size_t requiredSiz =reqSiz<TY>(), size_t newElms =1)
611 {
612 if (not (Coll::empty()
613 or Coll::hasReserve (requiredSiz, newElms)
614 or Policy::canExpand (Coll::data_, requiredSiz*(Coll::size() + newElms))
615 or canDynGrow()))
616 throw err::Invalid{_Fmt{"Several-container is unable to accommodate further element of type %s; "
617 "storage reserve (%d bytes ≙ %d elms) exhausted and unable to move "
618 "elements of mixed unknown detail type, which are not trivially movable." }
619 % util::typeStr<TY>() % Coll::storageBuffSiz() % capacity()};
620 }
621
622
624 void
625 adjustStorage (size_t cnt, size_t spread)
626 {
627 size_t demand{cnt*spread};
628 size_t buffSiz{Coll::storageBuffSiz()};
629 if (demand == buffSiz)
630 return;
631 if (demand > buffSiz)
632 {// grow into exponentially expanded new allocation
633 if (spread > Coll::spread())
634 cnt = max (cnt, buffSiz / Coll::spread()); // retain reserve
635 size_t overhead = sizeof(Bucket) + alignRes(alignof(E));
636 size_t safetyLim = LUMIERA_MAX_ORDINAL_NUMBER * Coll::spread();
637 size_t expandAlloc = min (positiveDiff (min (safetyLim
638 ,Policy::ALLOC_LIMIT)
639 ,overhead)
640 ,max (2*buffSiz, cnt*spread));
641 // round down to an straight number of elements
642 size_t newCnt = expandAlloc / spread;
643 expandAlloc = newCnt * spread;
644 if (expandAlloc < demand)
645 throw err::State{_Fmt{"Storage expansion for Several-collection "
646 "exceeds safety limit of %d bytes"} % safetyLim
647 ,LERR_(SAFETY_LIMIT)};
648 // allocate new storage block...
649 Coll::data_ = Policy::realloc (Coll::data_, newCnt,spread);
650 }
651 ENSURE (Coll::data_);
652 if (canWildMove() and spread != Coll::spread())
654 }
655
656 void
658 {
659 REQUIRE (not Coll::empty());
660 if (not (Policy::canExpand (Coll::data_, Coll::size())
661 or canDynGrow()))
662 throw err::Invalid{"Unable to shrink storage for Several-collection, "
663 "since at least one element can not be moved."};
664 Coll::data_ = Policy::realloc (Coll::data_, Coll::size(), Coll::spread());
665 }
666
668 void
669 adjustSpread (size_t newSpread)
670 {
671 REQUIRE (Coll::data_);
672 REQUIRE (newSpread * Coll::size() <= Coll::storageBuffSiz());
673 size_t oldSpread = Coll::spread();
674 if (newSpread > oldSpread)
675 // need to spread out
676 for (size_t i=Coll::size()-1; 0<i; --i)
677 shiftStorage (i, oldSpread, newSpread);
678 else
679 // attempt to condense spread
680 for (size_t i=1; i<Coll::size(); ++i)
681 shiftStorage (i, oldSpread, newSpread);
682 // data elements now spaced by new spread
683 Coll::data_->spread = newSpread;
684 }
685
686 void
687 shiftStorage (size_t idx, size_t oldSpread, size_t newSpread)
688 {
689 REQUIRE (idx);
690 REQUIRE (oldSpread);
691 REQUIRE (newSpread);
692 REQUIRE (Coll::data_);
693 byte* oldPos = Coll::data_->storage();
694 byte* newPos = oldPos;
695 oldPos += idx * oldSpread;
696 newPos += idx * newSpread;
697 std::memmove (newPos, oldPos, util::min (oldSpread,newSpread));
698 }
699
700
701
702 /* ==== Logic do decide about possible element handling ==== */
703
709 static Literal
711 {
712 switch (m)
713 {
714 case TRIVIAL: return "trivial";
715 case ELEMENT: return "fixed-element-type";
716 case VIRTUAL: return "virtual-baseclass";
717 default:
718 throw err::Logic{"unknown DestructionMethod"};
719 }
720 }
721
723 bool lock_move{false};
724
725
736 template<typename TY>
737 Deleter
739 {
743
744 typename Policy::Fac& factory(*this);
745
746 if (is_Subclass<TVal,IVal>() and has_virtual_destructor_v<IVal>)
747 {
748 __ensureMark<TVal> (VIRTUAL);
749 return [factory](ArrayBucket<I>* bucket){ unConst(factory).template destroy<IVal> (bucket); };
750 }
751 if (is_trivially_destructible_v<TVal>)
752 {
753 __ensureMark<TVal> (TRIVIAL);
754 return [factory](ArrayBucket<I>* bucket){ unConst(factory).template destroy<TVal> (bucket); };
755 }
756 if (is_same_v<TVal,EVal> and is_Subclass<EVal,IVal>())
757 {
758 __ensureMark<TVal> (ELEMENT);
759 return [factory](ArrayBucket<I>* bucket){ unConst(factory).template destroy<EVal> (bucket); };
760 }
761 throw err::Invalid{_Fmt{"Unsupported kind of destructor for element type %s."}
762 % util::typeStr<TY>()};
763 }
764
765 template<typename TY>
766 void
768 {
769 if (destructor != UNKNOWN and destructor != requiredKind)
770 throw err::Invalid{_Fmt{"Unable to handle (%s-)destructor for element type %s, "
771 "since this container has been primed to use %s-destructors."}
772 % render(requiredKind)
773 % util::typeStr<TY>()
774 % render(destructor)};
775 destructor = requiredKind;
776 }
777
778
782 template<typename TY>
783 void
785 {
788
789 if (not (is_same_v<TVal,EVal> or is_trivially_copyable_v<TVal>))
790 lock_move = true;
791 }
792
793 bool
795 {
797 return is_trivially_copyable_v<EVal> and not lock_move;
798 }
799
800 bool
802 {
803 return not lock_move;
804 }
805 };
806
807
808
809
810 /* ===== Helpers and convenience-functions for creating SeveralBuilder ===== */
811
812
813 namespace allo { // Setup for custom allocator policies
814
826 template<template<typename> class ALO, typename...ARGS>
827 struct SetupSeveral;
828
830 template<template<typename> class ALO>
831 struct SetupSeveral<ALO>
832 {
833 template<class I, class E>
835 };
836
839 template<template<typename> class ALO, typename X>
840 struct SetupSeveral<ALO, ALO<X>>
841 {
842 template<class I, class E>
843 struct Policy
844 : AllocationPolicy<I,E,ALO>
845 {
846 Policy (ALO<X> refAllocator)
847 : AllocationPolicy<I,E,ALO>(move(refAllocator))
848 { }
849 };
850 };
851 //
852 }//(End)Allocator configuration
853
854
855
870 template<class I, class E, template<class,class> class POL>
871 template<template<typename> class ALO, typename...ARGS>
872 inline auto
874 {
875 if (not empty())
876 throw err::Logic{"lib::Several builder withAllocator() must be invoked "
877 "prior to adding any elements to the container"};
878
879 using Setup = allo::SetupSeveral<ALO,ARGS...>;
880 using BuilderWithAllo = SeveralBuilder<I,E, Setup::template Policy>;
881
882 return BuilderWithAllo(forward<ARGS> (args)...);
883 }
884
885
886
887
888
889 /*********************************************************/
896 template<typename I, typename E =I>
899 {
900 return SeveralBuilder<I,E>{};
901 }
902
903 template<typename X>
904 SeveralBuilder<X>
905 makeSeveral (std::initializer_list<X> ili)
906 {
907 return SeveralBuilder<X>{}
908 .reserve (ili.size())
909 .appendAll (ili);
910 }
911
912
913} // namespace lib
914#endif /*LIB_SEVERAL_BUILDER_H*/
Inline string literal.
Definition symbol.hpp:78
Builder to create and populate a lib::Several<I>.
void emplaceCopy(IT &dataSrc)
void shiftStorage(size_t idx, size_t oldSpread, size_t newSpread)
Bucket::Deleter Deleter
several::ArrayBucket< I > Bucket
auto withAllocator(ARGS &&...args)
cross-builder to use a custom allocator for the lib::Several container
SeveralBuilder && fillElm(size_t cntNew, ARGS &&...args)
emplace a number of elements of the defined element type E
size_t capReserve() const
SeveralBuilder && shrinkFit()
discard excess reserve capacity.
void adjustSpread(size_t newSpread)
move existing data to accommodate spread
SeveralBuilder(ARGS &&...alloInit)
start Several build using a custom allocator
SeveralBuilder()=default
static Literal render(DestructionMethod m)
void emplaceNewElm(ARGS &&...args)
void adjustStorage(size_t cnt, size_t spread)
possibly grow storage and re-arrange elements to accommodate desired capacity
I & operator[](size_t idx)
allow to peek into data emplaced thus far...
Policy & policyConnect()
expose policy to configure other ServeralBuilder
SeveralBuilder && appendAll(IT &&data)
append a copy of all values exposed through an iterator
SeveralBuilder && moveAll(SEQ &dataSrc)
consume all values exposed through an iterator by moving into the builder
void emplaceMove(IT &dataSrc)
SeveralBuilder && emplace(ARGS &&...args)
create a new content element within the managed storage
void probeMoveCapability()
mark that we're about to accept an otherwise unknown type, which can not be trivially moved.
void ensureElementCapacity(size_t requiredSiz=reqSiz< TY >())
ensure sufficient element capacity or the ability to adapt element spread
SeveralBuilder && append(VAL &&val, VALS &&...vals)
append copies of one or several arbitrary elements
Deleter selectDestructor()
Select a suitable method for invoking the element destructors and build a λ-object to be stored as de...
void ensureStorageCapacity(size_t requiredSiz=reqSiz< TY >(), size_t newElms=1)
ensure sufficient storage reserve for newElms or verify the ability to re-allocate
SeveralBuilder && reserve(size_t cntElm=1, size_t elmSiz=reqSiz< TY >())
ensure up-front that a desired capacity is allocated
Several< I > build()
Terminal Builder: complete and lock the collection contents.
void ensureDeleter()
ensure clean-up can be handled properly.
DestructionMethod destructor
SeveralBuilder && appendAll(std::initializer_list< X > ili)
void __ensureMark(DestructionMethod requiredKind)
Abstraction: Fixed array of elements.
Definition several.hpp:166
size_t spread() const
Definition several.hpp:241
Generic factory to manage objects within an ArrayBucket<I> storage, delegating to a custom allocator ...
E & createAt(Bucket *bucket, size_t idx, ARGS &&...args)
ElementFactory(ElementFactory< X, ALO > &relatedFac)
allow cross-initialisation when using same kind of base allocator
std::allocator_traits< Allo > AlloT
ElementFactory(Allo allo=Allo{})
void destroy(ArrayBucket< I > *bucket)
Bucket * create(size_t cnt, size_t spread, size_t alignment=alignof(I))
AlloT::template rebind_traits< std::remove_cv_t< X > > XAlloT
Derived specific exceptions within Lumiera's exception hierarchy.
Definition error.hpp:193
Types marked with this mix-in may be moved but not copied.
Definition nocopy.hpp:50
A front-end for using printf-style formatting.
Lumiera error handling (C++ interface).
#define LERR_(_NAME_)
Definition error.hpp:45
Front-end for printf-style string template interpolation.
unsigned int uint
Definition integral.hpp:29
Building tree expanding and backtracking evaluations within hierarchical scopes.
hard wired safety limits.
#define LUMIERA_MAX_ORDINAL_NUMBER
Definition limits.hpp:34
Definition Setup.py:1
AllocationPolicy< I, E, ALO > Policy
AllocationPolicy< I, E, std::allocator > HeapOwn
Default configuration to use heap memory for lib::Several.
Extension point: how to configure the SeveralBuilder to use an allocator ALO, initialised by ARGS.
const uint INITIAL_ELM_CNT
number of storage slots to open initially; starting with an over-allocation similar to std::vector
constexpr size_t alignRes(size_t alignment)
determine size of a reserve buffer to place with proper alignment
constexpr size_t reqSiz()
Helper to determine the »spread« required to hold elements of type TY in memory with proper alignment...
remove_reference_t< TypeUnconst > TypeReferred
Definition trait.hpp:257
enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition meta/util.hpp:87
Implementation namespace for support and library code.
auto explore(IT &&srcSeq)
start building a IterExplorer by suitably wrapping the given iterable source.
SeveralBuilder< I, E > makeSeveral()
Entrance Point: start building a lib::Several instance.
LumieraError< LERR_(STATE)> State
Definition error.hpp:209
LumieraError< LERR_(LOGIC)> Logic
Definition error.hpp:207
STL namespace.
auto max(IT &&elms)
constexpr UN positiveDiff(N2 newVal, UN refVal)
Definition util.hpp:107
OBJ * unConst(const OBJ *)
shortcut to save some typing when having to define const and non-const variants of member functions
Definition util.hpp:358
auto min(IT &&elms)
Abstraction interface: array-like random access by subscript.
Policy Mix-In used to adapt to the ElementFactory and Allocator.
Bucket * realloc(Bucket *data, size_t cnt, size_t spread)
void moveElem(size_t idx, Bucket *src, Bucket *tar)
bool canExpand(Bucket *, size_t)
Extension point: able to adjust dynamically to the requested size?
static size_t constexpr ALLOC_LIMIT
by default assume that memory is practically unlimited...
verify compliance to an interface by subtype check
Definition trait.hpp:330
Metadata record placed immediately before the data storage.
Definition several.hpp:115
std::function< void(ArrayBucket *)> Deleter
Definition several.hpp:123
Helpers for type detection, type rewriting and metaprogramming.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...