2024-05-12 19:05:50 +02:00
|
|
|
/*
|
|
|
|
|
SEVERAL-BUILDER.hpp - builder for a limited fixed collection of elements
|
|
|
|
|
|
|
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2024, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
|
|
|
|
published by the Free Software Foundation; either version 2 of
|
|
|
|
|
the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** @file several-builder.hpp
|
|
|
|
|
** Some (library-) implementations of the RefArray interface.
|
|
|
|
|
**
|
|
|
|
|
** Being an array-like object exposing just a const ref, it is typically used
|
|
|
|
|
** on interfaces, and the type of the array "elements" usually is a ABC or interface.
|
|
|
|
|
** The actual implementation typically holds a subclass, and is either based on a vector,
|
|
|
|
|
** or a fixed storage contained within the implementation. The only price to pay is
|
|
|
|
|
** a virtual call on element access.
|
|
|
|
|
**
|
|
|
|
|
** For advanced uses it would be possible to have a pointer-array or even an embedded
|
|
|
|
|
** storage of variant-records, able to hold a mixture of subclasses. (the latter cases
|
|
|
|
|
** will be implemented when needed).
|
|
|
|
|
**
|
|
|
|
|
** @warning WIP and in rework 5/2025 -- not clear yet where this design leads to...
|
|
|
|
|
** @see several-builder-test.cpp
|
|
|
|
|
**
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef LIB_SEVERAL_BUILDER_H
|
|
|
|
|
#define LIB_SEVERAL_BUILDER_H
|
|
|
|
|
|
|
|
|
|
|
2024-06-07 19:04:06 +02:00
|
|
|
#include "lib/error.hpp"
|
2024-05-12 19:05:50 +02:00
|
|
|
#include "lib/several.hpp"
|
2024-06-07 19:04:06 +02:00
|
|
|
#include "include/limits.hpp"
|
2024-05-28 18:52:01 +02:00
|
|
|
#include "lib/iter-explorer.hpp"
|
2024-06-07 19:04:06 +02:00
|
|
|
#include "lib/format-string.hpp"
|
2024-05-28 18:52:01 +02:00
|
|
|
#include "lib/util.hpp"
|
2024-05-12 19:05:50 +02:00
|
|
|
|
2024-06-04 23:24:11 +02:00
|
|
|
#include <type_traits>
|
2024-05-29 01:01:16 +02:00
|
|
|
#include <cstring>
|
2024-05-28 18:07:08 +02:00
|
|
|
#include <utility>
|
2024-05-12 19:05:50 +02:00
|
|
|
#include <vector>
|
2024-05-28 18:07:08 +02:00
|
|
|
|
2024-05-12 19:05:50 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
2024-06-07 19:04:06 +02:00
|
|
|
namespace err = lumiera::error;
|
|
|
|
|
|
2024-05-28 18:52:01 +02:00
|
|
|
using std::vector;
|
|
|
|
|
using std::forward;
|
|
|
|
|
using std::move;
|
2024-05-29 01:01:16 +02:00
|
|
|
using std::byte;
|
2024-05-12 19:05:50 +02:00
|
|
|
|
2024-05-29 01:01:16 +02:00
|
|
|
namespace {// Allocation management policies
|
2024-05-28 17:20:34 +02:00
|
|
|
|
2024-06-07 19:04:06 +02:00
|
|
|
using util::max;
|
|
|
|
|
using util::min;
|
|
|
|
|
using util::_Fmt;
|
2024-06-06 23:15:49 +02:00
|
|
|
|
2024-06-06 21:13:50 +02:00
|
|
|
template<class I, template<typename> class ALO>
|
2024-06-06 21:53:04 +02:00
|
|
|
class ElementFactory
|
2024-06-06 21:13:50 +02:00
|
|
|
: private ALO<std::byte>
|
2024-06-06 18:41:07 +02:00
|
|
|
{
|
2024-06-06 21:13:50 +02:00
|
|
|
using Allo = ALO<std::byte>;
|
2024-06-06 18:41:07 +02:00
|
|
|
using AlloT = std::allocator_traits<Allo>;
|
2024-06-06 21:53:04 +02:00
|
|
|
using Bucket = ArrayBucket<I>;
|
2024-06-06 18:41:07 +02:00
|
|
|
|
2024-06-06 21:13:50 +02:00
|
|
|
Allo& baseAllocator() { return *this; }
|
|
|
|
|
|
2024-06-06 18:41:07 +02:00
|
|
|
template<typename X>
|
2024-06-06 21:13:50 +02:00
|
|
|
auto
|
2024-06-06 18:41:07 +02:00
|
|
|
adaptAllocator()
|
|
|
|
|
{
|
|
|
|
|
using XAllo = typename AlloT::template rebind_alloc<X>;
|
|
|
|
|
if constexpr (std::is_constructible_v<XAllo, Allo>)
|
2024-06-06 21:13:50 +02:00
|
|
|
return XAllo{baseAllocator()};
|
2024-06-06 18:41:07 +02:00
|
|
|
else
|
|
|
|
|
return XAllo{};
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 21:53:04 +02:00
|
|
|
public:
|
2024-06-06 21:13:50 +02:00
|
|
|
ElementFactory (Allo allo = Allo{})
|
|
|
|
|
: Allo{std::move (allo)}
|
|
|
|
|
{ }
|
|
|
|
|
|
2024-06-06 21:53:04 +02:00
|
|
|
Bucket*
|
|
|
|
|
create (size_t cnt, size_t spread)
|
|
|
|
|
{
|
2024-06-07 22:50:24 +02:00
|
|
|
size_t storageBytes = Bucket::requiredStorage (cnt, spread);
|
2024-06-06 21:53:04 +02:00
|
|
|
std::byte* loc = AlloT::allocate (baseAllocator(), storageBytes);
|
2024-06-07 22:50:24 +02:00
|
|
|
Bucket* bucket = reinterpret_cast<Bucket*> (loc);
|
2024-06-06 21:53:04 +02:00
|
|
|
|
|
|
|
|
using BucketAlloT = typename AlloT::template rebind_traits<Bucket>;
|
|
|
|
|
auto bucketAllo = adaptAllocator<Bucket>();
|
2024-06-07 22:50:24 +02:00
|
|
|
try { BucketAlloT::construct (bucketAllo, bucket, storageBytes, spread); }
|
2024-06-06 21:53:04 +02:00
|
|
|
catch(...)
|
|
|
|
|
{
|
|
|
|
|
AlloT::deallocate (baseAllocator(), loc, storageBytes);
|
|
|
|
|
throw;
|
|
|
|
|
}
|
2024-06-07 22:50:24 +02:00
|
|
|
return bucket;
|
2024-06-06 21:53:04 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<class E, typename...ARGS>
|
|
|
|
|
E&
|
|
|
|
|
createAt (Bucket* bucket, size_t idx, ARGS&& ...args)
|
|
|
|
|
{
|
|
|
|
|
REQUIRE (bucket);
|
|
|
|
|
using ElmAlloT = typename AlloT::template rebind_traits<E>;
|
|
|
|
|
auto elmAllo = adaptAllocator<E>();
|
|
|
|
|
E* loc = & bucket->subscript (idx);
|
|
|
|
|
ElmAlloT::construct (elmAllo, loc, forward<ARGS> (args)...);
|
|
|
|
|
ENSURE (loc);
|
|
|
|
|
return *loc;
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-06 21:13:50 +02:00
|
|
|
template<class E>
|
|
|
|
|
void
|
2024-06-07 22:50:24 +02:00
|
|
|
destroy (ArrayBucket<I>* bucket)
|
2024-06-06 18:41:07 +02:00
|
|
|
{
|
2024-06-06 21:13:50 +02:00
|
|
|
REQUIRE (bucket);
|
2024-06-07 22:50:24 +02:00
|
|
|
size_t cnt = bucket->cnt;
|
|
|
|
|
size_t storageBytes = bucket->buffSiz;
|
2024-06-06 21:13:50 +02:00
|
|
|
using ElmAlloT = typename AlloT::template rebind_traits<E>;
|
|
|
|
|
auto elmAllo = adaptAllocator<E>();
|
2024-06-07 22:50:24 +02:00
|
|
|
for (size_t idx=0; idx<cnt; ++idx)
|
|
|
|
|
ElmAlloT::destroy (elmAllo, & bucket->subscript(idx));
|
2024-06-06 18:41:07 +02:00
|
|
|
|
2024-06-07 22:50:24 +02:00
|
|
|
std::byte* loc = reinterpret_cast<std::byte*> (bucket);
|
|
|
|
|
AlloT::deallocate (baseAllocator(), loc, storageBytes);
|
2024-06-06 18:41:07 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-08 22:44:07 +02:00
|
|
|
using std::is_trivially_copyable_v;
|
2024-06-06 18:41:07 +02:00
|
|
|
|
2024-06-08 21:58:04 +02:00
|
|
|
template<class I, class E, template<typename> class ALO>
|
2024-06-06 23:15:49 +02:00
|
|
|
struct AllocationPolicy
|
|
|
|
|
: ElementFactory<I, ALO>
|
|
|
|
|
{
|
|
|
|
|
using Fac = ElementFactory<I, ALO>;
|
2024-06-07 19:04:06 +02:00
|
|
|
using Bucket = ArrayBucket<I>;
|
|
|
|
|
|
|
|
|
|
using Fac::Fac; // pass-through ctor
|
2024-06-06 23:15:49 +02:00
|
|
|
|
2024-06-08 01:51:32 +02:00
|
|
|
const bool isDisposable{false}; ///< memory must be explicitly deallocated
|
2024-06-08 17:35:14 +02:00
|
|
|
|
|
|
|
|
bool canExpand(size_t){ return false; }
|
2024-06-08 01:51:32 +02:00
|
|
|
|
2024-06-07 19:04:06 +02:00
|
|
|
Bucket*
|
2024-06-08 22:44:07 +02:00
|
|
|
realloc (Bucket* data, size_t cnt, size_t spread)
|
2024-06-06 23:15:49 +02:00
|
|
|
{
|
2024-06-08 22:44:07 +02:00
|
|
|
Bucket* newBucket = Fac::create (cnt, spread);
|
|
|
|
|
if (data)
|
|
|
|
|
{
|
|
|
|
|
size_t elms = min (cnt, data->cnt);
|
|
|
|
|
for (size_t idx=0; idx<elms; ++idx)
|
|
|
|
|
moveElem(idx, data, newBucket);
|
|
|
|
|
data->destroy();
|
|
|
|
|
}
|
|
|
|
|
return newBucket;
|
|
|
|
|
/*
|
2024-06-07 22:50:24 +02:00
|
|
|
size_t buffSiz{data? data->buffSiz : 0};
|
|
|
|
|
if (demand == buffSiz)
|
2024-06-07 19:04:06 +02:00
|
|
|
return data;
|
2024-06-07 22:50:24 +02:00
|
|
|
if (demand > buffSiz)
|
2024-06-07 19:04:06 +02:00
|
|
|
{// grow into exponentially expanded new allocation
|
|
|
|
|
size_t spread = data? data->spread : sizeof(I);
|
|
|
|
|
size_t safetyLim = LUMIERA_MAX_ORDINAL_NUMBER * spread;
|
|
|
|
|
size_t expandAlloc = min (safetyLim
|
2024-06-07 22:50:24 +02:00
|
|
|
,max (2*buffSiz, demand));
|
2024-06-07 19:04:06 +02:00
|
|
|
if (expandAlloc < demand)
|
|
|
|
|
throw err::State{_Fmt{"Storage expansion for Several-collection "
|
|
|
|
|
"exceeds safety limit of %d bytes"} % safetyLim
|
|
|
|
|
,LERR_(SAFETY_LIMIT)};
|
|
|
|
|
// allocate new storage block...
|
|
|
|
|
size_t newCnt = demand / spread;
|
|
|
|
|
if (newCnt * spread < demand) ++newCnt;
|
|
|
|
|
Bucket* newBucket = Fac::create (newCnt, spread);
|
|
|
|
|
// move (or copy) existing data...
|
2024-06-07 22:50:24 +02:00
|
|
|
size_t cnt = data? data->cnt : 0;
|
|
|
|
|
for (size_t idx=0; idx<cnt; ++idx)
|
|
|
|
|
Fac::template createAt<I> (newBucket, idx
|
|
|
|
|
,std::move_if_noexcept (data->subscript(idx)));
|
2024-06-07 19:04:06 +02:00
|
|
|
////////////////////////////////////////////////////////OOO schee... aba mia brauchn E, ned I !!!!!
|
|
|
|
|
// discard old storage
|
|
|
|
|
if (data)
|
2024-06-07 22:50:24 +02:00
|
|
|
Fac::template destroy<I> (data);
|
2024-06-07 19:04:06 +02:00
|
|
|
return newBucket;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{// shrink into precisely fitting new allocation
|
|
|
|
|
Bucket* newBucket{nullptr};
|
2024-06-07 22:50:24 +02:00
|
|
|
if (data)
|
2024-06-07 19:04:06 +02:00
|
|
|
{
|
2024-06-08 01:51:32 +02:00
|
|
|
size_t cnt{data->cnt};
|
2024-06-07 22:50:24 +02:00
|
|
|
ASSERT (cnt > 0);
|
2024-06-07 19:04:06 +02:00
|
|
|
newBucket = Fac::create (cnt, data->spread);
|
2024-06-07 22:50:24 +02:00
|
|
|
for (size_t idx=0; idx<cnt; ++idx)
|
|
|
|
|
Fac::template createAt<I> (newBucket, idx
|
|
|
|
|
,std::move_if_noexcept (data->subscript(idx))); ////////////OOO selbes Problem: E hier
|
|
|
|
|
Fac::template destroy<I> (data);
|
2024-06-07 19:04:06 +02:00
|
|
|
}
|
|
|
|
|
return newBucket;
|
|
|
|
|
}
|
2024-06-08 22:44:07 +02:00
|
|
|
*/
|
2024-06-08 21:58:04 +02:00
|
|
|
// // ensure sufficient storage or verify the ability to re-allocate
|
|
|
|
|
// if (not (Coll::hasReserve(sizeof(TY))
|
|
|
|
|
// or POL::canExpand(sizeof(TY))
|
|
|
|
|
// or handling_.template canDynGrow<TY>()))
|
|
|
|
|
// throw err::Invalid{_Fmt{"Unable to accommodate further element of type %s "}
|
|
|
|
|
// % util::typeStr<TY>()};
|
2024-06-06 23:15:49 +02:00
|
|
|
}
|
2024-06-08 22:44:07 +02:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
moveElem (size_t idx, Bucket* src, Bucket* tar)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (is_trivially_copyable_v<E>)
|
|
|
|
|
{
|
|
|
|
|
void* oldPos = & src->subscript(idx);
|
|
|
|
|
void* newPos = & tar->subscript(idx);
|
|
|
|
|
size_t amount = min (src->spread, tar->spread);
|
|
|
|
|
std::memmove (newPos, oldPos, amount);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Fac::template createAt<E> (tar, idx
|
|
|
|
|
,std::move_if_noexcept (src->subscript(idx)));
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-06 23:15:49 +02:00
|
|
|
};
|
|
|
|
|
|
2024-06-08 21:58:04 +02:00
|
|
|
template<class I, class E>
|
|
|
|
|
using HeapOwn = AllocationPolicy<I, E, std::allocator>;
|
2024-06-06 23:15:49 +02:00
|
|
|
|
|
|
|
|
|
2024-06-04 23:24:11 +02:00
|
|
|
using std::is_trivially_move_constructible_v;
|
|
|
|
|
using std::is_trivially_destructible_v;
|
|
|
|
|
using std::has_virtual_destructor_v;
|
2024-06-08 21:58:04 +02:00
|
|
|
using std::is_trivially_copyable_v;
|
2024-06-04 23:24:11 +02:00
|
|
|
using std::is_same_v;
|
|
|
|
|
using lib::meta::is_Subclass;
|
|
|
|
|
|
|
|
|
|
template<class I, class E>
|
2024-06-08 17:35:14 +02:00
|
|
|
struct HandlingStrategy
|
2024-06-04 23:24:11 +02:00
|
|
|
{
|
2024-06-08 21:58:04 +02:00
|
|
|
bool disposable ;
|
|
|
|
|
bool lock_move ;
|
2024-06-04 23:24:11 +02:00
|
|
|
|
2024-06-08 17:35:14 +02:00
|
|
|
HandlingStrategy (bool unmanaged)
|
2024-06-08 01:51:32 +02:00
|
|
|
: disposable{unmanaged or (is_trivially_destructible_v<E> and
|
|
|
|
|
is_trivially_destructible_v<I>)}
|
2024-06-08 21:58:04 +02:00
|
|
|
, lock_move{false}
|
2024-06-08 01:51:32 +02:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
/** mark that we're about to accept an otherwise unknown type,
|
2024-06-08 21:58:04 +02:00
|
|
|
* which can not be trivially moved. This irrevocably disables
|
|
|
|
|
* relocations by low-level `memove` for this container instance */
|
2024-06-08 01:51:32 +02:00
|
|
|
template<typename TY>
|
2024-06-08 21:58:04 +02:00
|
|
|
void
|
|
|
|
|
probeMoveCapability()
|
2024-06-08 01:51:32 +02:00
|
|
|
{
|
2024-06-08 21:58:04 +02:00
|
|
|
if (not (is_same_v<TY,E> or is_trivially_copyable_v<TY>))
|
|
|
|
|
lock_move = true;
|
2024-06-08 01:51:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2024-06-08 21:58:04 +02:00
|
|
|
canWildMove()
|
2024-06-08 01:51:32 +02:00
|
|
|
{
|
2024-06-08 21:58:04 +02:00
|
|
|
return is_trivially_copyable_v<E> and not lock_move;
|
2024-06-08 01:51:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-06-04 23:24:11 +02:00
|
|
|
template<typename TY>
|
|
|
|
|
bool
|
|
|
|
|
canDestroy()
|
|
|
|
|
{
|
2024-06-08 17:35:14 +02:00
|
|
|
return (disposable and is_trivially_destructible_v<TY>)
|
2024-06-04 23:24:11 +02:00
|
|
|
or (is_trivially_destructible_v<TY> and is_trivially_destructible_v<I>)
|
|
|
|
|
or (has_virtual_destructor_v<I> and is_Subclass<TY,I>())
|
|
|
|
|
or (is_same_v<TY,E> and is_Subclass<E,I>());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto
|
|
|
|
|
getDeleter()
|
|
|
|
|
{
|
2024-06-08 01:51:32 +02:00
|
|
|
if (disposable)
|
2024-06-04 23:24:11 +02:00
|
|
|
return nullptr;
|
2024-06-08 01:51:32 +02:00
|
|
|
if (has_virtual_destructor_v<I>)
|
2024-06-04 23:24:11 +02:00
|
|
|
return nullptr;
|
|
|
|
|
else
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-05-28 17:20:34 +02:00
|
|
|
}
|
|
|
|
|
|
2024-05-12 19:05:50 +02:00
|
|
|
/**
|
|
|
|
|
* Wrap a vector holding objects of a subtype and
|
|
|
|
|
* provide array-like access using the interface type.
|
|
|
|
|
*/
|
2024-06-08 21:58:04 +02:00
|
|
|
template<class I ///< Interface or base type visible on resulting Several<I>
|
|
|
|
|
,class E =I ///< a subclass element element type (relevant when not trivially movable and destructible)
|
|
|
|
|
,class POL =HeapOwn<I,E> ///< Allocator policy
|
2024-06-04 23:24:11 +02:00
|
|
|
>
|
2024-05-28 04:03:51 +02:00
|
|
|
class SeveralBuilder
|
2024-05-28 17:20:34 +02:00
|
|
|
: Several<I>
|
2024-06-06 18:41:07 +02:00
|
|
|
, util::MoveOnly
|
2024-05-28 17:20:34 +02:00
|
|
|
, POL
|
2024-05-12 19:05:50 +02:00
|
|
|
{
|
2024-06-07 19:04:06 +02:00
|
|
|
using Coll = Several<I>;
|
2024-05-28 18:52:01 +02:00
|
|
|
|
2024-06-08 17:35:14 +02:00
|
|
|
HandlingStrategy<I,E> handling_{POL::isDisposable};
|
2024-06-08 01:51:32 +02:00
|
|
|
|
2024-05-12 19:05:50 +02:00
|
|
|
public:
|
2024-05-28 18:52:01 +02:00
|
|
|
SeveralBuilder() = default;
|
|
|
|
|
|
|
|
|
|
/** start Several build using a custom allocator */
|
|
|
|
|
template<typename...ARGS, typename = meta::enable_if<std::is_constructible<POL,ARGS...>>>
|
|
|
|
|
SeveralBuilder (ARGS&& ...alloInit)
|
|
|
|
|
: Several<I>{}
|
|
|
|
|
, POL{forward<ARGS> (alloInit)...}
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SeveralBuilder&&
|
|
|
|
|
reserve (size_t cntElm)
|
|
|
|
|
{
|
2024-06-07 19:04:06 +02:00
|
|
|
adjustStorage (cntElm, sizeof(E));
|
2024-05-28 18:52:01 +02:00
|
|
|
return move(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class IT>
|
|
|
|
|
SeveralBuilder&&
|
|
|
|
|
appendAll (IT&& data)
|
|
|
|
|
{
|
2024-06-08 01:51:32 +02:00
|
|
|
explore(data).foreach ([this](auto it){ emplaceCopy(it); });
|
2024-05-28 18:52:01 +02:00
|
|
|
return move(*this);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-28 04:03:51 +02:00
|
|
|
Several<I>
|
|
|
|
|
build()
|
2024-05-12 19:05:50 +02:00
|
|
|
{
|
2024-05-28 18:07:08 +02:00
|
|
|
return move (*this);
|
2024-05-12 19:05:50 +02:00
|
|
|
}
|
2024-05-28 18:52:01 +02:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void
|
|
|
|
|
adjustStorage (size_t cnt, size_t spread)
|
|
|
|
|
{
|
2024-06-07 19:04:06 +02:00
|
|
|
size_t demand{cnt*spread};
|
2024-06-08 22:44:07 +02:00
|
|
|
Coll::data_ = POL::realloc (Coll::data_, cnt,spread); /////////////////OOO anpassen
|
2024-06-07 19:04:06 +02:00
|
|
|
ENSURE (Coll::data_);
|
2024-06-07 23:02:51 +02:00
|
|
|
if (spread != Coll::spread())
|
2024-05-29 01:01:16 +02:00
|
|
|
adjustSpread (spread);
|
2024-06-07 19:04:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fitStorage()
|
|
|
|
|
{
|
|
|
|
|
if (not Coll::data_) return;
|
2024-06-07 23:02:51 +02:00
|
|
|
size_t demand{Coll::size() * Coll::spread()};
|
2024-06-07 22:50:24 +02:00
|
|
|
Coll::data_ = POL::realloc (Coll::data_, demand);
|
2024-05-29 01:01:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** move existing data to accommodate spread */
|
|
|
|
|
void
|
|
|
|
|
adjustSpread (size_t newSpread)
|
|
|
|
|
{
|
2024-06-07 19:04:06 +02:00
|
|
|
REQUIRE (Coll::data_);
|
2024-06-07 23:02:51 +02:00
|
|
|
REQUIRE (newSpread * Coll::size() <= Coll::data_->buffSiz);
|
|
|
|
|
size_t oldSpread = Coll::spread();
|
2024-05-29 01:01:16 +02:00
|
|
|
if (newSpread > oldSpread)
|
|
|
|
|
// need to spread out
|
2024-06-07 22:23:06 +02:00
|
|
|
for (size_t i=Coll::size()-1; 0<i; --i)
|
2024-05-29 01:01:16 +02:00
|
|
|
shiftStorage (i, oldSpread, newSpread);
|
|
|
|
|
else
|
|
|
|
|
// attempt to condense spread
|
2024-06-07 22:23:06 +02:00
|
|
|
for (size_t i=1; i<Coll::size(); ++i)
|
2024-05-29 01:01:16 +02:00
|
|
|
shiftStorage (i, oldSpread, newSpread);
|
|
|
|
|
// data elements now spaced by new spread
|
2024-06-07 19:04:06 +02:00
|
|
|
Coll::data_->spread = newSpread;
|
2024-05-29 01:01:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
shiftStorage (size_t idx, size_t oldSpread, size_t newSpread)
|
|
|
|
|
{
|
|
|
|
|
REQUIRE (idx);
|
|
|
|
|
REQUIRE (oldSpread);
|
|
|
|
|
REQUIRE (newSpread);
|
2024-06-07 19:04:06 +02:00
|
|
|
REQUIRE (Coll::data_);
|
|
|
|
|
byte* oldPos = Coll::data_->storage;
|
2024-05-29 01:01:16 +02:00
|
|
|
byte* newPos = oldPos;
|
|
|
|
|
oldPos += idx * oldSpread;
|
|
|
|
|
newPos += idx * newSpread;
|
|
|
|
|
std::memmove (newPos, oldPos, util::min (oldSpread,newSpread));
|
2024-05-28 18:52:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class IT>
|
|
|
|
|
void
|
2024-06-08 01:51:32 +02:00
|
|
|
emplaceCopy (IT& dataSrc)
|
|
|
|
|
{
|
|
|
|
|
using Val = std::remove_cv_t<typename IT::value_type>;
|
|
|
|
|
emplaceElm<Val> (*dataSrc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class TY, typename...ARGS>
|
|
|
|
|
void
|
|
|
|
|
emplaceElm (ARGS&& ...args)
|
2024-05-28 18:52:01 +02:00
|
|
|
{
|
2024-06-08 17:35:14 +02:00
|
|
|
if (not handling_.template canDestroy<TY>())
|
2024-06-08 01:51:32 +02:00
|
|
|
throw err::Invalid{_Fmt{"Unable to handle destructor for element type %s"}
|
|
|
|
|
% util::typeStr<TY>()};
|
|
|
|
|
|
2024-06-08 21:58:04 +02:00
|
|
|
// mark when target type is not trivially movable
|
|
|
|
|
handling_.template probeMoveCapability<TY>();
|
2024-06-08 01:51:32 +02:00
|
|
|
|
2024-06-08 17:35:14 +02:00
|
|
|
// ensure sufficient element capacity or the ability to adapt element spread
|
2024-06-08 21:58:04 +02:00
|
|
|
if (Coll::spread() < sizeof(TY) and not (Coll::empty() or handling_.canWildMove()))
|
2024-06-08 17:35:14 +02:00
|
|
|
throw err::Invalid{_Fmt{"Unable to place element of type %s (size=%d)"
|
|
|
|
|
"into container for element size %d."}
|
|
|
|
|
% util::typeStr<TY>() % sizeof(TY) % Coll::spread()};
|
2024-06-08 01:51:32 +02:00
|
|
|
|
|
|
|
|
size_t elmSiz = sizeof(TY);
|
|
|
|
|
size_t newCnt = Coll::size()+1;
|
2024-06-08 17:35:14 +02:00
|
|
|
adjustStorage (newCnt, max (elmSiz, Coll::spread()));
|
2024-06-08 01:51:32 +02:00
|
|
|
Coll::data_->cnt = newCnt;
|
2024-06-08 17:35:14 +02:00
|
|
|
POL::template createAt<TY> (Coll::data_, newCnt-1, forward<ARGS> (args)...);
|
2024-05-28 18:52:01 +02:00
|
|
|
}
|
2024-05-12 19:05:50 +02:00
|
|
|
};
|
|
|
|
|
|
2024-05-28 18:52:01 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-05-28 04:03:51 +02:00
|
|
|
template<typename X>
|
|
|
|
|
SeveralBuilder<X>
|
|
|
|
|
makeSeveral (std::initializer_list<X> ili)
|
|
|
|
|
{
|
2024-05-28 18:52:01 +02:00
|
|
|
return SeveralBuilder<X>{}
|
|
|
|
|
.reserve (ili.size())
|
|
|
|
|
.appendAll (ili);
|
2024-05-28 04:03:51 +02:00
|
|
|
}
|
2024-05-12 19:05:50 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace lib
|
|
|
|
|
#endif /*LIB_SEVERAL_BUILDER_H*/
|