BufferProvider: setup implementation structure for the pool
- use boost::lockfree to implement the in-queue with new allocations - use a std::list with an internal administrative record - automatically ingest the in-queue prior to accessing the pool
This commit is contained in:
parent
e328018b05
commit
dd37600c4d
6 changed files with 296 additions and 24 deletions
|
|
@ -97,6 +97,8 @@ def configure(env):
|
||||||
problems.append('We need boost::lexical_cast')
|
problems.append('We need boost::lexical_cast')
|
||||||
if not conf.CheckCXXHeader('boost/format.hpp'):
|
if not conf.CheckCXXHeader('boost/format.hpp'):
|
||||||
problems.append('We need boost::format (header).')
|
problems.append('We need boost::format (header).')
|
||||||
|
if not conf.CheckCXXHeader('boost/lockfree/queue.hpp'):
|
||||||
|
problems.append('We need boost::lockfree (header).')
|
||||||
if not conf.CheckLibWithHeader('boost_program_options','boost/program_options.hpp','C++'):
|
if not conf.CheckLibWithHeader('boost_program_options','boost/program_options.hpp','C++'):
|
||||||
problems.append('We need boost::program_options (including binary lib for linking).')
|
problems.append('We need boost::program_options (including binary lib for linking).')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ Lumiera expects a ``standard'' desktop installation running a XServer.footnote:[
|
||||||
Wayland is ``just around the corner'' since 10 years now. Well, recently it
|
Wayland is ``just around the corner'' since 10 years now. Well, recently it
|
||||||
seems it is _really_ just around the corner. We are aware of the necessary
|
seems it is _really_ just around the corner. We are aware of the necessary
|
||||||
changes, which are not very complicated to implement (since we are using
|
changes, which are not very complicated to implement (since we are using
|
||||||
GTK-3). However, as long as Wayland simply crashes or hands in our
|
GTK-3). However, as long as Wayland simply crashes or hangs in our
|
||||||
everyday work setup with XFCE, we will not consider this topic
|
everyday work setup with XFCE, we will not consider this topic
|
||||||
a priority. In the meantime, please report any problems
|
a priority. In the meantime, please report any problems
|
||||||
you encounter with Lumiera running on XWayland.
|
you encounter with Lumiera running on XWayland.
|
||||||
|
|
@ -97,7 +97,8 @@ Languages and Tools
|
||||||
|
|
||||||
* BOOST (listed below are the Debian package names)
|
* BOOST (listed below are the Debian package names)
|
||||||
- libboost-dev (at least *1.83*)
|
- libboost-dev (at least *1.83*)
|
||||||
- libboost-program-options-dev
|
- notably including `boost::lockfree`
|
||||||
|
- libboost-program-options-dev (link dependency)
|
||||||
|
|
||||||
* Script languages
|
* Script languages
|
||||||
- Python (*3.10*) required for building (->SCons)
|
- Python (*3.10*) required for building (->SCons)
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
** under the assumption that the allocator is a _monostate_, and
|
** under the assumption that the allocator is a _monostate_, and
|
||||||
** exploiting _empty-base-optimisation,_ footprint is minimal.
|
** exploiting _empty-base-optimisation,_ footprint is minimal.
|
||||||
** @note this linked list container is _intrusive_ and thus needs the help
|
** @note this linked list container is _intrusive_ and thus needs the help
|
||||||
** of the element type, which must *provide a pointer member* `next`.
|
** of the element type, which must **provide a pointer member** `next`.
|
||||||
** Consequently, each such node element can not be member in
|
** Consequently, each such node element can not be member in
|
||||||
** several collections at the same time (unless they share all elements)
|
** several collections at the same time (unless they share all elements)
|
||||||
** @note as usual, any iterator relies on the continued existence and
|
** @note as usual, any iterator relies on the continued existence and
|
||||||
|
|
|
||||||
|
|
@ -32,16 +32,30 @@
|
||||||
#include "vault/mem/buffhandle.hpp" //////////////TODO
|
#include "vault/mem/buffhandle.hpp" //////////////TODO
|
||||||
//#include "lib/local-slice.hpp"
|
//#include "lib/local-slice.hpp"
|
||||||
//#include "lib/depend.hpp"
|
//#include "lib/depend.hpp"
|
||||||
|
#include "lib/util.hpp"
|
||||||
#include "lib/nocopy.hpp"
|
#include "lib/nocopy.hpp"
|
||||||
|
#include "lib/meta/trait.hpp"//////////////TODO
|
||||||
|
|
||||||
#include <tuple>
|
#include <boost/lockfree/queue.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
//#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
|
||||||
namespace vault {
|
namespace vault {
|
||||||
namespace mem {
|
namespace mem {
|
||||||
namespace err = lumiera::error;
|
namespace err = lumiera::error;
|
||||||
|
|
||||||
using std::tuple;
|
namespace { // Configuration tuning parameters
|
||||||
|
|
||||||
|
const size_t INQUEUE_SIZ = 30; ///< initial size of the lock-free provision queue
|
||||||
|
|
||||||
|
}//(End) config parameters and internals
|
||||||
|
|
||||||
|
using std::move;
|
||||||
|
using std::forward;
|
||||||
|
using util::unConst;
|
||||||
|
|
||||||
class PoolDiagnostic;
|
class PoolDiagnostic;
|
||||||
|
|
||||||
|
|
@ -51,42 +65,229 @@ namespace mem {
|
||||||
*/
|
*/
|
||||||
class LocalMemPool
|
class LocalMemPool
|
||||||
{
|
{
|
||||||
|
struct Alloc
|
||||||
|
{
|
||||||
|
Buff* mem;
|
||||||
|
size_t siz;
|
||||||
|
};
|
||||||
|
static_assert (std::is_trivially_copy_assignable_v<Alloc>);
|
||||||
|
|
||||||
|
struct Block
|
||||||
|
{
|
||||||
|
Alloc alloc{nullptr,0};
|
||||||
|
int32_t score{0};
|
||||||
|
bool used :1 {false};
|
||||||
|
bool resd :1 {false};
|
||||||
|
|
||||||
|
Block() = default;
|
||||||
|
Block(Alloc&& alloc)
|
||||||
|
: alloc{move(alloc)}
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
static_assert (std::is_trivially_copy_assignable_v<Block>);
|
||||||
|
|
||||||
|
using InQueue = boost::lockfree::queue<Alloc>;
|
||||||
|
using BlockList = std::list<Block>;
|
||||||
|
|
||||||
|
InQueue inQueue_;
|
||||||
|
BlockList blocks_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LocalMemPool()
|
LocalMemPool()
|
||||||
|
: inQueue_{INQUEUE_SIZ}
|
||||||
|
, blocks_{}
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
/* ===== Pool Access API ===== */
|
/* ===== Pool Access API ===== */
|
||||||
|
|
||||||
bool empty() const { return 0 == size(); }
|
|
||||||
size_t size() const { return 0; } ///////////////////////OOO
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
canServe (size_t sizRequest)
|
empty() const
|
||||||
{
|
{
|
||||||
return false; ///////////////////////////////////////OOO
|
return blocks_.empty()
|
||||||
|
and inQueue_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return overall number of descriptors in the pool, including used ones
|
||||||
|
* @warning this operation has linear complexity
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
size() const
|
||||||
|
{
|
||||||
|
return blocks_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Query if this pool can provide some chunk of memory right away. */
|
||||||
|
bool
|
||||||
|
canServe (size_t sizRequest) const
|
||||||
|
{
|
||||||
|
unConst(this)->ingest();
|
||||||
|
return bool(anyFree (sizRequest));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine to what extent the indicated allocation request
|
||||||
|
* could be handled, given the current memory available in the pool.
|
||||||
|
* An allocation promised hereby will be marked as reserved internally,
|
||||||
|
* and will thus not be considered for further `reserve()` requests.
|
||||||
|
* @return number of allocations of the indicated size,
|
||||||
|
* that are available immediately and have been reserved now.
|
||||||
|
* @note irrespective of any reservation, an immediate request to
|
||||||
|
* \ref retrieve() an allocation will use available memory.
|
||||||
|
* There is no _handle_ to refer to some specific reservation.
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
reserve (uint cnt, size_t sizRequest)
|
||||||
|
{
|
||||||
|
ingest();
|
||||||
|
return 0; ///////////////////////////////////////OOO
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transfer discretionary power over the given allocation to this pool.
|
||||||
|
* @note this call is thread-safe and asynchronous; the pool will pick up
|
||||||
|
* the given information on the next request to serve or reserve memory.
|
||||||
|
* @remark the \a mem _must not be touched_ by any other part of the system,
|
||||||
|
* unless it is [yielded](\ref yield()) or disposed as part of clean-up.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
add (Buff* mem, size_t siz)
|
add (Buff* mem, size_t siz)
|
||||||
{
|
{
|
||||||
TODO ("add new alloc to pool");
|
inQueue_.push ({mem,siz});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an used memory block back to the pool
|
||||||
|
* @param mem a chunk of memory previously handed out by \ref retrieve()
|
||||||
|
* @throw err::Logic in case the indicated allocation is not known
|
||||||
|
* @warning **not threadsafe** — invoke from worker thread only
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
reAdd (Buff* mem)
|
reAdd (Buff* mem)
|
||||||
{
|
{
|
||||||
TODO ("return known alloc into pool");
|
ingest();
|
||||||
|
Block* block = UN_CONST (anyMatch (mem));
|
||||||
|
if (not block)
|
||||||
|
throw err::Logic{"returning unknown allocation to LocalMemPool"};
|
||||||
|
if (not block->used)
|
||||||
|
throw err::Logic{"returning known allocation that is not marked as used"};
|
||||||
|
block->used = false;
|
||||||
|
ENSURE (not block->resd);
|
||||||
}
|
}
|
||||||
|
|
||||||
tuple<Buff*,size_t>
|
/**
|
||||||
|
* Acquire a block of memory for active use
|
||||||
|
* @param sizRequest minimum size of storage expected
|
||||||
|
* @return a chunk of memory of indicated size, which may be larger
|
||||||
|
* than requested. The answer can be `(nullptr, 0)` in case
|
||||||
|
* the request can not be satisfied
|
||||||
|
* @note the allocation is marked as used internally,
|
||||||
|
* and must be returned to this pool after use.
|
||||||
|
* Memory can only be disposed after \ref yield()
|
||||||
|
* @warning **not threadsafe** — invoke from worker thread only
|
||||||
|
*/
|
||||||
|
Alloc
|
||||||
retrieve (size_t sizRequest)
|
retrieve (size_t sizRequest)
|
||||||
{
|
{
|
||||||
return {nullptr, 0};
|
ingest();
|
||||||
|
Block* found = selectBestMatch (sizRequest);
|
||||||
|
if (not found)
|
||||||
|
return {nullptr, 0};
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ENSURE (not found->used);
|
||||||
|
found->score += 1; ///////////////////TODO
|
||||||
|
found->resd = false;
|
||||||
|
found->used = true;
|
||||||
|
return found->alloc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Yield control over the indicated number of allocations.
|
||||||
|
* @tparam FUN a consumer to receive the allocations removed from the pool
|
||||||
|
* @param siz precise size of the memory block(s) to yield
|
||||||
|
* @return actual number of allocations removed from the pool.
|
||||||
|
*/
|
||||||
|
template<class FUN> ////////TODO requires std::invocable<FUN,Buff*,size_t>
|
||||||
|
size_t
|
||||||
|
yield (uint cnt, size_t siz, FUN&& consumer)
|
||||||
|
{
|
||||||
|
ingest();
|
||||||
|
return 0;///////////////////////OOO
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a heuristic clean-up of the pool, based on usage statistics.
|
||||||
|
* @tparam FUN a consumer to receive the allocations removed from the pool
|
||||||
|
* @param degree a measure of how aggressively the clean-up should be performed;
|
||||||
|
* 1.0 indicates that every allocation must be released, whereas
|
||||||
|
* \a degree ≡ 0.5 retains all matches that were frequently successful.
|
||||||
|
* @return actual number of allocations removed from the pool.
|
||||||
|
*/
|
||||||
|
template<class FUN> ////////TODO requires std::invocable<FUN,Buff*,size_t>
|
||||||
|
size_t
|
||||||
|
cleanup (double degree, FUN&& consumer)
|
||||||
|
{
|
||||||
|
ingest();
|
||||||
|
return 0;///////////////////////OOO
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void
|
||||||
|
ingest()
|
||||||
|
{
|
||||||
|
inQueue_.consume_all ([this](Alloc alloc)
|
||||||
|
{
|
||||||
|
blocks_.emplace_front (move(alloc));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class PRED>
|
||||||
|
Block const*
|
||||||
|
findMatch (PRED&& predicate) const
|
||||||
|
{
|
||||||
|
auto found = std::ranges::find_if (blocks_, forward<PRED> (predicate));
|
||||||
|
return found!=blocks_.end()? & *found
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Block const*
|
||||||
|
anyFree (size_t sizRequest) const
|
||||||
|
{
|
||||||
|
return findMatch ([sizRequest](Block const& b)
|
||||||
|
{
|
||||||
|
return not b.used
|
||||||
|
and sizRequest <= b.alloc.siz;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Block const*
|
||||||
|
anyMatch (Buff* mem) const
|
||||||
|
{
|
||||||
|
return findMatch ([mem](Block const& b){ return mem == b.alloc.mem; });
|
||||||
|
}
|
||||||
|
|
||||||
|
Block*
|
||||||
|
selectBestMatch (size_t sizRequest)
|
||||||
|
{
|
||||||
|
Block* match{nullptr};
|
||||||
|
size_t waste(-1);
|
||||||
|
for (Block& block : blocks_)
|
||||||
|
if (not block.used
|
||||||
|
and sizRequest <= block.alloc.siz)
|
||||||
|
{
|
||||||
|
size_t wasted = block.alloc.siz - sizRequest;
|
||||||
|
if (wasted < waste)
|
||||||
|
{
|
||||||
|
waste = wasted;
|
||||||
|
match = █
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
friend class PoolDiagnostic;
|
friend class PoolDiagnostic;
|
||||||
};
|
};
|
||||||
|
|
@ -95,7 +296,9 @@ namespace mem {
|
||||||
class PoolDiagnostic
|
class PoolDiagnostic
|
||||||
: util::MoveOnly
|
: util::MoveOnly
|
||||||
{
|
{
|
||||||
LocalMemPool memPool_;
|
using Block = LocalMemPool::Block;
|
||||||
|
|
||||||
|
LocalMemPool& memPool_;
|
||||||
public:
|
public:
|
||||||
PoolDiagnostic (LocalMemPool& lmp)
|
PoolDiagnostic (LocalMemPool& lmp)
|
||||||
: memPool_{lmp}
|
: memPool_{lmp}
|
||||||
|
|
@ -104,13 +307,14 @@ namespace mem {
|
||||||
bool
|
bool
|
||||||
isEmpty()
|
isEmpty()
|
||||||
{
|
{
|
||||||
return true;
|
return memPool_.empty();
|
||||||
} ///////////////////OOO
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
cnt (size_t siz)
|
cnt (size_t siz)
|
||||||
{
|
{
|
||||||
return 0; ////////////////////OOO
|
return std::ranges::count_if (memPool_.blocks_
|
||||||
|
,[siz](Block const& b){ return siz == b.alloc.siz; });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ namespace test {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** @test
|
/** @test allocations are accounted by size
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
verify_matchAlloc()
|
verify_matchAlloc()
|
||||||
|
|
@ -106,7 +106,12 @@ namespace test {
|
||||||
CHECK (watch(pool).isEmpty());
|
CHECK (watch(pool).isEmpty());
|
||||||
|
|
||||||
pool.add (MEM1, SIZ10);
|
pool.add (MEM1, SIZ10);
|
||||||
|
CHECK (watch(pool).cnt(SIZ10) == 0); // new allotment not ingested yet,....
|
||||||
|
CHECK (not watch(pool).isEmpty()); // however, there is an entry in the in-queue
|
||||||
|
|
||||||
|
CHECK (pool.canServe(SIZ10)); // query causes a scan and retrieval from the in-queu
|
||||||
CHECK (watch(pool).cnt(SIZ10) == 1);
|
CHECK (watch(pool).cnt(SIZ10) == 1);
|
||||||
|
CHECK (not watch(pool).isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -145846,6 +145846,16 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
||||||
<node CREATED="1777050440887" ID="ID_1006627416" MODIFIED="1777066692859" TEXT="Verhalten spezifizieren">
|
<node CREATED="1777050440887" ID="ID_1006627416" MODIFIED="1777066692859" TEXT="Verhalten spezifizieren">
|
||||||
<icon BUILTIN="yes"/>
|
<icon BUILTIN="yes"/>
|
||||||
<node CREATED="1777050520227" ID="ID_796153621" MODIFIED="1777050524094" TEXT="Use-Cases">
|
<node CREATED="1777050520227" ID="ID_796153621" MODIFIED="1777050524094" TEXT="Use-Cases">
|
||||||
|
<node CREATED="1777068198295" ID="ID_1010651012" MODIFIED="1777068390012" TEXT="Allokationsbedarf ankündigen">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head/>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
zwar wird das niemals einer konkreten Allokation vorgreifen, sollte aber <i>den internen Seiten-Effekt haben daß Pool-Eingräge »beiseitegelegt« werden.</i>  Denn sonst würden die gleichen Einträge u.U. für nachfolgende Vorankündigungen nochmal verbucht werden, wodurch dann insgesamt zu wenig zusätzlicher Speicher angefordert wird. Das bedeutet, wir brauchen nicht nur eine Flag, sondern verschiedene Grade der Reservierung
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html></richcontent>
|
||||||
|
</node>
|
||||||
<node CREATED="1777051227060" ID="ID_847462254" MODIFIED="1777051382666" TEXT="Allokation in den Pool übernehmen"/>
|
<node CREATED="1777051227060" ID="ID_847462254" MODIFIED="1777051382666" TEXT="Allokation in den Pool übernehmen"/>
|
||||||
<node CREATED="1777051616687" ID="ID_142096290" MODIFIED="1777051638112" TEXT="Allokation aus dem Pool entnehmen"/>
|
<node CREATED="1777051616687" ID="ID_142096290" MODIFIED="1777051638112" TEXT="Allokation aus dem Pool entnehmen"/>
|
||||||
<node CREATED="1777051746358" ID="ID_658492297" MODIFIED="1777051798530" TEXT="Allokation in den Pool zurückgeben"/>
|
<node CREATED="1777051746358" ID="ID_658492297" MODIFIED="1777051798530" TEXT="Allokation in den Pool zurückgeben"/>
|
||||||
|
|
@ -145866,14 +145876,64 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
||||||
</node>
|
</node>
|
||||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1777050453251" ID="ID_1529547535" MODIFIED="1777066700207" TEXT="Implementieren">
|
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1777050453251" ID="ID_1529547535" MODIFIED="1777066700207" TEXT="Implementieren">
|
||||||
<icon BUILTIN="pencil"/>
|
<icon BUILTIN="pencil"/>
|
||||||
<node CREATED="1777052048904" ID="ID_1403107789" MODIFIED="1777052073352" TEXT="die Eingangs-Queue wird komplett (transparent) integriert"/>
|
<node CREATED="1777052048904" ID="ID_1403107789" MODIFIED="1777052073352" TEXT="die Eingangs-Queue wird komplett (transparent) integriert">
|
||||||
|
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1777078419796" ID="ID_1966959598" MODIFIED="1777084265167" TEXT="verwende boost::lockfree::queue"/>
|
||||||
|
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1777078428098" ID="ID_1939142827" MODIFIED="1777078435459" TEXT="ist das die richtige Wahl?">
|
||||||
|
<icon BUILTIN="help"/>
|
||||||
|
<node CREATED="1777078440070" ID="ID_885005752" MODIFIED="1777078470502" TEXT="verlangt »trivial assignment« und Destructor"/>
|
||||||
|
<node CREATED="1777078471365" ID="ID_769328039" MODIFIED="1777078487222" TEXT="heißt im Klartext: darf keine default-Initialiser haben">
|
||||||
|
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1777078531972" ID="ID_921695652" LINK="https://stackoverflow.com/a/38780211/444796" MODIFIED="1777084274162" TEXT="Konkret: kein std::tuple">
|
||||||
|
<icon BUILTIN="messagebox_warning"/>
|
||||||
|
</node>
|
||||||
|
<node COLOR="#435e98" CREATED="1777078635327" ID="ID_238173965" MODIFIED="1777084271658" TEXT="muß mir selber eine passende Struct bauen"/>
|
||||||
|
</node>
|
||||||
|
<node CREATED="1777078489787" ID="ID_1970735736" MODIFIED="1777084225822" TEXT="Vorteile">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head/>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
...da es sich um einen Prototyp handelt, halte ich diese Vorteile für sehr wichtig; im Besonderen das mit dem single producer/consumer läßt sich nicht ohne Weiteres sicherstellen (es ergibt sich hier nur indirekt, indem man die Klasse dann thread_local definiert und auf der anderen Seite einen zentralen Allokations-Manager als Singleton hat. Aber selbst dann könnte man den Allokations-Manager noch von verschiedenen Threads aus nutzen.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Dazu kommt, daß ich generell eine Aversion gegen Ringbuffer habe, speziell dann, wenn man keine Garantie geben kann zur maximalen Befüllung. Es ärgert mich immer wieder, wenn »coole« Leute mit Ringbuffern um sich werfen.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html></richcontent>
|
||||||
|
<icon BUILTIN="forward"/>
|
||||||
|
<node CREATED="1777078498513" ID="ID_1558383335" MODIFIED="1777078503445" TEXT="kann dynamisch wachsen"/>
|
||||||
|
<node CREATED="1777078504193" ID="ID_1364741326" MODIFIED="1777078513262" TEXT="kann mit mehreren Producern/Consumern umgehen"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
<node CREATED="1777052358645" ID="ID_1367907395" MODIFIED="1777052396869" TEXT="zum Aufräumen wird ein Empfänger-λ übergeben"/>
|
<node CREATED="1777052358645" ID="ID_1367907395" MODIFIED="1777052396869" TEXT="zum Aufräumen wird ein Empfänger-λ übergeben"/>
|
||||||
<node CREATED="1777052497154" ID="ID_1906132363" MODIFIED="1777052517239" TEXT="vorerst den default(-Heap)-Allokator für alles verwenden"/>
|
<node CREATED="1777052497154" ID="ID_1906132363" MODIFIED="1777052517239" TEXT="vorerst den default(-Heap)-Allokator für alles verwenden"/>
|
||||||
|
<node CREATED="1777073876105" ID="ID_1153882258" MODIFIED="1777073995987" TEXT="stelle fest: LinkedElements sind nicht gut geeignet">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head/>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
...und zwar, weil sie bisher kein Entfernen von Einträgen unterstützen (und sinnvollerweise wäre auch nur ein pop() vom Anfang der Liste); außerdem wäre schwierig, daß man beim Entfernen die Ownership übertragen müßte, um eine Re-Allokation zu verhindern.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html></richcontent>
|
||||||
|
<node COLOR="#338800" CREATED="1777074497539" ID="ID_1587444173" MODIFIED="1777084232736" TEXT="sollte eine std::list verwenden (double-linked)">
|
||||||
|
<icon BUILTIN="yes"/>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1777050457640" ID="ID_55967690" MODIFIED="1777050461566" TEXT="Dokumentieren per Test">
|
<node CREATED="1777074521660" ID="ID_1763982951" MODIFIED="1777074532534" TEXT="grundsätzlich: gehe von einer kleinen Anzahl an Einträgen aus"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1777050457640" ID="ID_55967690" MODIFIED="1777084249904" TEXT="Dokumentieren per Test">
|
||||||
|
<icon BUILTIN="pencil"/>
|
||||||
<node CREATED="1777050471715" ID="ID_694034532" MODIFIED="1777050476406" TEXT="LocalMemPool_test"/>
|
<node CREATED="1777050471715" ID="ID_694034532" MODIFIED="1777050476406" TEXT="LocalMemPool_test"/>
|
||||||
<node CREATED="1777052679889" ID="ID_1809859332" MODIFIED="1777052689966" TEXT="simpleUse()"/>
|
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1777052679889" ID="ID_1809859332" MODIFIED="1777084246555" TEXT="simpleUse()">
|
||||||
<node CREATED="1777052647931" ID="ID_1721020388" MODIFIED="1777052658570" TEXT="verify_matchAlloc"/>
|
<icon BUILTIN="pencil"/>
|
||||||
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1777052647931" ID="ID_1721020388" MODIFIED="1777084246554" TEXT="verify_matchAlloc">
|
||||||
|
<icon BUILTIN="pencil"/>
|
||||||
|
</node>
|
||||||
<node CREATED="1777052660303" ID="ID_1192169892" MODIFIED="1777052665482" TEXT="verify_selectAlloc"/>
|
<node CREATED="1777052660303" ID="ID_1192169892" MODIFIED="1777052665482" TEXT="verify_selectAlloc"/>
|
||||||
<node CREATED="1777052670304" ID="ID_924547131" MODIFIED="1777052674241" TEXT="verify_pruneAlloc"/>
|
<node CREATED="1777052670304" ID="ID_924547131" MODIFIED="1777052674241" TEXT="verify_pruneAlloc"/>
|
||||||
</node>
|
</node>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue