mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-04 22:19:42 +08:00
Co-authored-by: Andrew Le Bihan <andy@mcneel.com> Co-authored-by: Dale Fugier <dale@mcneel.com> Co-authored-by: Dale Lear <dalelear@mcneel.com> Co-authored-by: Greg Arden <greg@mcneel.com> Co-authored-by: Jussi <jussi@mcneel.com> Co-authored-by: Lowell <lowell@mcneel.com> Co-authored-by: Rajaa Issa <rajaa@mcneel.com> Co-authored-by: Steve Baer <steve@mcneel.com> Co-authored-by: alain <alain@mcneel.com> Co-authored-by: chuck <chuck@mcneel.com> Co-authored-by: piac <giulio@mcneel.com>
921 lines
30 KiB
C++
921 lines
30 KiB
C++
/* $NoKeywords: $ */
|
|
/*
|
|
//
|
|
// Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
|
|
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
|
|
// McNeel & Associates.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
|
|
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
|
|
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
|
|
//
|
|
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
*/
|
|
#if !defined(OPENNURBS_FSP_INC_)
|
|
#define OPENNURBS_FSP_INC_
|
|
|
|
class ON_CLASS ON_FixedSizePoolElement
|
|
{
|
|
private:
|
|
// ON_FixedSizePoolElement is never instantiated
|
|
ON_FixedSizePoolElement() = delete;
|
|
~ON_FixedSizePoolElement() = delete;
|
|
ON_FixedSizePoolElement(const ON_FixedSizePoolElement&) = delete;
|
|
ON_FixedSizePoolElement operator=(const ON_FixedSizePoolElement&) = delete;
|
|
|
|
public:
|
|
// next element - intentionally not initialized because instantiation is not permitted.
|
|
ON_FixedSizePoolElement* m_next;
|
|
};
|
|
|
|
class ON_CLASS ON_FixedSizePool
|
|
{
|
|
public:
|
|
ON_FixedSizePool();
|
|
~ON_FixedSizePool();
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
ON_FixedSizePool(ON_FixedSizePool&&);
|
|
ON_FixedSizePool& operator=(ON_FixedSizePool&&);
|
|
#endif
|
|
|
|
|
|
/*
|
|
Description:
|
|
Create a fixed size memory pool.
|
|
Parameters:
|
|
sizeof_element - [in]
|
|
number of bytes in each element. This parameter must be greater than zero.
|
|
In general, use sizeof(element type). If you pass a "raw" number as
|
|
sizeof_element, then be certain that it is the right size to insure the
|
|
fields in your elements will be properly aligned.
|
|
Remarks:
|
|
You must call Create() on an unused ON_FixedSizePool or call Destroy()
|
|
before calling create.
|
|
Returns:
|
|
True if successful and the pool can be used.
|
|
See Also
|
|
CreateForExperts().
|
|
*/
|
|
bool Create(
|
|
size_t sizeof_element
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Create a fixed size memory pool.
|
|
If you have a decent estimate of how many elements you need,
|
|
CreateForExperts() is a typically a better choice.
|
|
Otherwise, Create(sizeof_element) is typically the best option.
|
|
|
|
Parameters:
|
|
sizeof_element - [in]
|
|
number of bytes in each element. This parameter must be greater than zero.
|
|
In general, use sizeof(element type). If you pass a "raw" number as
|
|
sizeof_element, then be certain that it is the right size to insure the
|
|
fields in your elements will be properly aligned.
|
|
element_count_estimate - [in] (0 = good default)
|
|
If you know how many elements you will need, pass that number here.
|
|
It is better to slightly overestimate than to slightly underestimate.
|
|
If you do not have a good estimate, then use zero.
|
|
block_element_capacity - [in] (0 = good default)
|
|
If block_element_capacity is zero, Create() will calculate a block
|
|
size that is efficent for most applications. If you are an expert
|
|
user and want to specify the number of elements per block,
|
|
then pass the number of elements per block here. When
|
|
block_element_capacity > 0 and element_count_estimate > 0, the first
|
|
block will have a capacity of at least element_count_estimate; in this
|
|
case do not ask for extraordinarly large amounts of contiguous heap.
|
|
|
|
Remarks:
|
|
You must call Create() on an unused ON_FixedSizePool or call Destroy()
|
|
before calling create.
|
|
Returns:
|
|
True if successful and the pool can be used.
|
|
*/
|
|
bool Create(
|
|
size_t sizeof_element,
|
|
size_t element_count_estimate,
|
|
size_t block_element_capacity
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Create a fixed size memory pool.
|
|
Parameters:
|
|
sizeof_element - [in]
|
|
number of bytes in each element. This parameter must be greater than zero.
|
|
In general, use sizeof(element type). If you pass a "raw" number as
|
|
sizeof_element, then be certain that it is the right size to insure the
|
|
fields in your elements will be properly aligned.
|
|
|
|
maximum_element_count_estimate - [in] (0 = good default)
|
|
If you have a tight upper bound on the number of elements you need
|
|
from this fixed size pool, call Create(sizeof_element) instead.
|
|
|
|
If the description of this parameter is confusing to you,
|
|
call Create(sizeof_element) instead.
|
|
|
|
If you have a tight upper bound on how many elements you will need,
|
|
pass that number here. When maximum_element_count_estimate > 0, the
|
|
initial memory blocks in the fixed size pool will be sized to efficiently
|
|
deliver maximum_element_count_estimate elements.
|
|
The fixed block pool can become inefficient when maximum_element_count_estimate
|
|
is a gross overestimate or a slight underestimate of the actual number of
|
|
elements that get allocated.
|
|
|
|
minimum_block2_element_capacity - [in] (0 = good default)
|
|
If the description below is confusing, pass 0.
|
|
If maximum_element_count_estimate = 0, this parameter is ignored.
|
|
If maximum_element_count_estimate > 0 and you have an excellent choice
|
|
for a lower bound on the number of elements per block for unexpected allocations
|
|
of more than maximum_element_count_estimate elements, then pass that value for
|
|
minimum_block2_element_capacity.
|
|
|
|
Remarks:
|
|
You must call Create() or CreateEx() on an unused ON_FixedSizePool or call Destroy()
|
|
before calling create.
|
|
Returns:
|
|
True if successful and the pool can be used.
|
|
*/
|
|
bool CreateForExperts(
|
|
size_t sizeof_element,
|
|
size_t maximum_element_count_estimate,
|
|
size_t minimum_block2_element_capacity
|
|
);
|
|
|
|
static size_t DefaultElementCapacityFromSizeOfElement(size_t sizeof_element);
|
|
|
|
/*
|
|
Description:
|
|
Tool for debugging pool use when tuning block size and block capacity.
|
|
Returns:
|
|
Total operating system heap memory (in bytes) used by this ON_FixedSizePool.
|
|
Remarks:
|
|
SizeOfPool() = SizeOfAllocatedElements() + SizeOfUnusedElements().
|
|
*/
|
|
size_t SizeOfPool() const;
|
|
|
|
/*
|
|
Description:
|
|
Tool for debugging pool use when tuning block size and block capacity.
|
|
Returns:
|
|
Operating system heap memory (in bytes) that are used by active pool elements.
|
|
Remarks:
|
|
SizeOfPool() = SizeOfActiveElements() + SizeOfUnusedElements().
|
|
*/
|
|
size_t SizeOfActiveElements() const;
|
|
|
|
/*
|
|
Description:
|
|
Tool for debugging pool use when tuning block size and block capacity.
|
|
Returns:
|
|
Operating system heap memory (in bytes) that has been reserved but is not
|
|
currently used by active elements.
|
|
Remarks:
|
|
SizeOfPool() = SizeOfActiveElements() + SizeOfUnusedElements().
|
|
*/
|
|
size_t SizeOfUnusedElements() const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
Size of the elements in this pool.
|
|
*/
|
|
size_t SizeofElement() const;
|
|
|
|
/*
|
|
Returns:
|
|
A pointer to sizeof_element bytes. The memory is zeroed.
|
|
Remarks:
|
|
If multiple threads are using this pool, then use ThreadSafeAllocateElement().
|
|
*/
|
|
void* AllocateElement();
|
|
|
|
/*
|
|
Returns:
|
|
A pointer to sizeof_element bytes. The values in the returned block are undefined.
|
|
Remarks:
|
|
If multiple threads are using this pool, then use ThreadSafeAllocateDirtyElement().
|
|
*/
|
|
void* AllocateDirtyElement();
|
|
|
|
/*
|
|
Description:
|
|
Return an element to the pool.
|
|
Parameters:
|
|
p - [in]
|
|
A pointer returned by AllocateElement().
|
|
It is critical that p be from this pool and that
|
|
you return a pointer no more than one time.
|
|
Remarks:
|
|
If multiple threads are using this pool, then use ThreadSafeReturnElement().
|
|
|
|
If you find the following remarks confusing, but you really want to use
|
|
ReturnElement(), then here are some simple guidelines.
|
|
1) SizeofElement() must be >= 16
|
|
2) SizeofElement() must be a multiple of 8.
|
|
3) Do not use FirstElement() and NextElement() to iterate through
|
|
the pool.
|
|
|
|
If 1 to 3 don't work for you, then you need to understand the following
|
|
information before using ReturnElement().
|
|
|
|
ON_FixedMemoryPool uses the first sizeof(void*) bytes of the
|
|
returned element for bookkeeping purposes. Therefore, if you
|
|
are going to use ReturnElement(), then SizeofElement() must be
|
|
at least sizeof(void*). If you are using a platform that requires
|
|
pointers to be aligned on sizeof(void*) boundaries, then
|
|
SizeofElement() must be a multiple of sizeof(void*).
|
|
If you are going to use ReturnElement() and then use FirstElement()
|
|
and NextElement() to iterate through the list of elements, then you
|
|
need to set a value in the returned element to indicate that it
|
|
needs to be skipped during the iteration. This value cannot be
|
|
located in the fist sizeof(void*) bytes of the element. If the
|
|
element is a class with a vtable, you cannot call a virtual
|
|
function on a returned element because the vtable pointer is
|
|
trashed when ReturnElement() modifies the fist sizeof(void*) bytes.
|
|
*/
|
|
void ReturnElement(void* p);
|
|
|
|
/*
|
|
Description:
|
|
Thread safe version of AllocateElement().
|
|
Returns:
|
|
A pointer to sizeof_element bytes. The memory is zeroed.
|
|
*/
|
|
void* ThreadSafeAllocateElement();
|
|
|
|
/*
|
|
Description:
|
|
Thread safe version of AllocateDirtyElement().
|
|
Returns:
|
|
A pointer to sizeof_element bytes. The values in the returned block are undefined.
|
|
*/
|
|
void* ThreadSafeAllocateDirtyElement();
|
|
|
|
/*
|
|
Description:
|
|
Thread safe version of ReturnElement().
|
|
*/
|
|
void ThreadSafeReturnElement(void* p);
|
|
|
|
/*
|
|
Description:
|
|
Return all allocated elements to the pool. No heap is freed and
|
|
the pool remains initialized and ready for AllocateElement()
|
|
to be called.
|
|
*/
|
|
void ReturnAll();
|
|
|
|
/*
|
|
Description:
|
|
Destroy the pool and free all the heap. The pool cannot be used again
|
|
until Create() is called.
|
|
*/
|
|
void Destroy();
|
|
|
|
/*
|
|
Returns:
|
|
Number of active elements. (Elements that have been returned are not active.)
|
|
*/
|
|
size_t ActiveElementCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Total number of elements = number of active elements + number of returned elements.
|
|
*/
|
|
size_t TotalElementCount() const;
|
|
|
|
/*
|
|
Description:
|
|
Get the i-th elment in the fixed size pool.
|
|
Parameters:
|
|
element_index - [in]
|
|
Returns:
|
|
A pointer to the element with the specified index.
|
|
The first element has element_index = 0 and is the element
|
|
returned by the first call to AllocateElement().
|
|
The last element has element_index = ElementCount()-1.
|
|
If element_index is out of range, nullptr is returned.
|
|
Remarks:
|
|
It is faster to use ON_FixedSizePoolIterator.FirstElement() and
|
|
ON_FixedSizePoolIterator.NextElement() to iterate through the
|
|
entire list of elements. This function is relatively
|
|
efficient when there are a few large blocks in the pool
|
|
or element_index is small compared to the number of elements
|
|
in the first few blocks.
|
|
|
|
If ReturnElement() is not used or no AllocateElement() calls
|
|
are made after any use of ReturnElement(), then the i-th
|
|
element is the one returned by the (i+1)-th call to
|
|
AllocateElement()
|
|
*/
|
|
void* Element(
|
|
size_t element_index
|
|
) const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Get the fixed size pool index of an element.
|
|
Parameters:
|
|
element_pointer - [in]
|
|
Returns:
|
|
An index >= 0 and < ON_MAX_SIZE_T if the element_pointer
|
|
points to an element managed by the this fixed size pool.
|
|
ON_MAX_SIZE_T otherwise.
|
|
Remarks:
|
|
It is faster to use ON_FixedSizePoolIterator.FirstElement() and
|
|
ON_FixedSizePoolIterator.NextElement() to iterate through the
|
|
entire list of elements. This function is relatively
|
|
efficient when there are a few large blocks in the pool
|
|
or element_pointer is an element in the first few blocks.
|
|
|
|
If ReturnElement() is not used or no AllocateElement() calls
|
|
are made after any use of ReturnElement(), then the i-th
|
|
element is the one returned by the (i+1)-th call to
|
|
AllocateElement().
|
|
*/
|
|
size_t ElementIndex(
|
|
const void* element_pointer
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
p - [in]
|
|
pointer to test
|
|
Returns:
|
|
True if p points to memory in this pool.
|
|
*/
|
|
bool InPool(
|
|
const void* pointer
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
If you are certain that all elements in the pool (active and returned)
|
|
have an unsigned 32-bit id that is unique and increasing, then you may use
|
|
this function to find them.
|
|
Parameters:
|
|
id_offset - [in]
|
|
offset into the element where the id is stored.
|
|
id - [in]
|
|
id to search for
|
|
*/
|
|
void* ElementFromId(
|
|
size_t id_offset,
|
|
unsigned int id
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
If you are certain that all elements in the pool (active and returned)
|
|
have an unsigned 32-bit id that is unique and increasing, then you may use
|
|
this function to find the maximum assigned id.
|
|
Parameters:
|
|
id_offset - [in]
|
|
offset into the element where the id is stored.
|
|
Returns:
|
|
maximum id in all elements (active and returned).
|
|
*/
|
|
unsigned int MaximumElementId(
|
|
size_t id_offset
|
|
) const;
|
|
|
|
bool ElementIdIsIncreasing(
|
|
size_t id_offset
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
If successful, (1 + maximum assigned id value) is returned.
|
|
Otherwise 0 is returned.
|
|
*/
|
|
unsigned int ResetElementId(
|
|
size_t id_offset,
|
|
unsigned int initial_id
|
|
);
|
|
|
|
public:
|
|
// Primarily used for debugging
|
|
bool IsValid() const;
|
|
|
|
private:
|
|
friend class ON_FixedSizePoolIterator;
|
|
|
|
void* m_first_block = nullptr;
|
|
|
|
// ReturnElement() adds to the m_al_element stack.
|
|
// AllocateElement() will use the stack before using m_al_element_array[]
|
|
void* m_al_element_stack = nullptr;
|
|
|
|
void* m_al_block = nullptr; // current element allocation block.
|
|
// m_al_element_array[] is in m_al_block and has length m_al_count.
|
|
void* m_al_element_array = nullptr;
|
|
size_t m_al_count = 0;
|
|
size_t m_sizeof_element = 0;
|
|
size_t m_block_element_count = 0; // block element count
|
|
|
|
//size_t m_active_element_count = 0; // number of active elements
|
|
//size_t m_total_element_count = 0; // total number of elements (active + returned)
|
|
|
|
unsigned int m_active_element_count = 0; // number of active elements
|
|
unsigned int m_total_element_count = 0; // total number of elements (active + returned)
|
|
|
|
private:
|
|
// Used by The ThreadSafe...() functions and for expert users
|
|
// to use when managing memory controlled by this pool. Best
|
|
// to ingnore this unless you have a very clear idea of what
|
|
// you are doing, why you are doing it, and when you are doing it.
|
|
// Otherwise, you'll find yourself waiting forever on a nested
|
|
// access request.
|
|
friend class ON_SleepLockGuard;
|
|
ON_SleepLock m_sleep_lock;
|
|
|
|
private:
|
|
unsigned int m_reserved0 = 0;
|
|
|
|
|
|
private:
|
|
// returns capacity of elements in existing block
|
|
size_t BlockElementCapacity( const void* block ) const;
|
|
|
|
// returns number of allocated of elements in existing block
|
|
size_t BlockElementCount( const void* block ) const;
|
|
|
|
private:
|
|
// prohibit copy construction and operator=.
|
|
ON_FixedSizePool(const ON_FixedSizePool&) = delete;
|
|
ON_FixedSizePool& operator=(const ON_FixedSizePool&) = delete;
|
|
};
|
|
|
|
class ON_CLASS ON_FixedSizePoolIterator
|
|
{
|
|
public:
|
|
ON_FixedSizePoolIterator();
|
|
ON_FixedSizePoolIterator( const class ON_FixedSizePool& fsp );
|
|
|
|
const class ON_FixedSizePool* FixedSizePool();
|
|
|
|
void Create(const ON_FixedSizePool* fsp);
|
|
|
|
/*
|
|
Description:
|
|
Get the first element when iterating through the list of elements.
|
|
Parameters:
|
|
element_index - [in]
|
|
If you use the version of FirstElement() that has an
|
|
element_index parameter, then the iteration begins at
|
|
that element.
|
|
Example:
|
|
The loop will iteratate through all the elements returned from
|
|
AllocateElement(), including any that have be returned to the pool
|
|
using ReturnElement().
|
|
|
|
// iterate through all elements in the pool
|
|
// This iteration will go through TotalElements() items.
|
|
for ( void* p = FirstElement(); 0 != p; p = NextElement() )
|
|
{
|
|
// If you are not using ReturnElement(), then you may process
|
|
// "p" immediately. If you have used ReturnElement(), then you
|
|
// must check some value in p located after the first sizeof(void*)
|
|
// bytes to see if p is active.
|
|
if ( p is not active )
|
|
continue;
|
|
|
|
... process p
|
|
}
|
|
|
|
Returns:
|
|
The first element when iterating through the list of elements.
|
|
Remarks:
|
|
FirstElement() and NextElement() will return elements that have
|
|
been returned to the pool using ReturnElement(). If you use
|
|
ReturnElement(), then be sure to mark the element so it can be
|
|
identified and skipped.
|
|
|
|
Do not make any calls to FirstBlock() or NextBlock() when using
|
|
FirstElement() and NextElement() to iteratate through elements.
|
|
*/
|
|
void* FirstElement();
|
|
void* FirstElement( size_t element_index );
|
|
|
|
/*
|
|
Description:
|
|
Get the next element when iterating through the list of elements.
|
|
If FirstElement() is not called, then the first call to
|
|
NextElement() returns the first element.
|
|
Example:
|
|
See the FirstElement() documentation.
|
|
Returns:
|
|
The next element when iterating through the list of elements.
|
|
Remarks:
|
|
FirstElement() and NextElement() will return elements that have
|
|
been returned to the pool using ReturnElement(). If you use
|
|
ReturnElement(), then be sure to mark the element so it can be
|
|
identified and skipped.
|
|
|
|
Do not make any calls to FirstBlock() or NextBlock() when using
|
|
FirstElement() and NextElement() to iteratate through elements.
|
|
*/
|
|
void* NextElement();
|
|
|
|
/*
|
|
Returns:
|
|
The most recently returned value from a call to FirstElement()
|
|
or NextElement().
|
|
Remarks:
|
|
Do not make any calls to FirstBlock() or NextBlock() when using
|
|
FirstElement() and NextElement() to iteratate through elements.
|
|
*/
|
|
void* CurrentElement() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets the state of the iterator to the initial state that
|
|
exists after construction. This is useful if the iterator
|
|
has been used the get one or more elements and then
|
|
the referenced fixed size pool is modified or code wants
|
|
to begin iteration again a used a call to NextElement()
|
|
to return the first element.
|
|
*/
|
|
void Reset();
|
|
|
|
|
|
/*
|
|
Description:
|
|
Get a pointer to the first element in the first block.
|
|
Parameters:
|
|
block_element_count - [out] (can be null)
|
|
If not null, the number of elements allocated from the
|
|
first block is returned in block_element_count.
|
|
Note that if you have used ReturnElement(), some
|
|
of these elemements may have been returned.
|
|
Example:
|
|
The loop will iteratate through all the blocks.
|
|
|
|
// iterate through all blocks in the pool
|
|
size_t block_element_count = 0;
|
|
for ( void* p = FirstBlock(&block_element_count);
|
|
0 != p;
|
|
p = NextBlock(&block_element_count)
|
|
)
|
|
{
|
|
ElementType* e = (ElementType*)p;
|
|
for ( size_t i = 0;
|
|
i < block_element_count;
|
|
i++, e = ((const char*)e) + SizeofElement()
|
|
)
|
|
{
|
|
...
|
|
}
|
|
}
|
|
|
|
Returns:
|
|
The first block when iterating the list of blocks.
|
|
Remarks:
|
|
The heap for a fixed size memory pool is simply a linked
|
|
list of blocks. FirstBlock() and NextBlock() can be used
|
|
to iterate through the list of blocks.
|
|
|
|
Do not make any calls to FirstElement() or NextElement() when using
|
|
FirstBlock() and NextBlock() to iteratate through blocks.
|
|
*/
|
|
void* FirstBlock( size_t* block_element_count );
|
|
|
|
/*
|
|
Description:
|
|
Get the next block when iterating through the blocks.
|
|
Parameters:
|
|
block_element_count - [out] (can be null)
|
|
If not null, the number of elements allocated from the
|
|
block is returned in block_element_count. Note that if
|
|
you have used ReturnElement(), some of these elemements
|
|
may have been returned.
|
|
Example:
|
|
See the FirstBlock() documentation.
|
|
Returns:
|
|
The next block when iterating through the blocks.
|
|
Remarks:
|
|
Do not make any calls to FirstElement() or NextElement() when using
|
|
FirstBlock() and NextBlock() to iteratate through blocks.
|
|
*/
|
|
void* NextBlock( size_t* block_element_count );
|
|
|
|
private:
|
|
const class ON_FixedSizePool* m_fsp;
|
|
void* m_it_block;
|
|
void* m_it_element;
|
|
};
|
|
|
|
|
|
template <class T> class ON_SimpleFixedSizePool : private ON_FixedSizePool
|
|
{
|
|
public:
|
|
// construction ////////////////////////////////////////////////////////
|
|
|
|
ON_SimpleFixedSizePool();
|
|
~ON_SimpleFixedSizePool();
|
|
|
|
/*
|
|
Description:
|
|
Create a fixed size memory pool.
|
|
Parameters:
|
|
element_count_estimate - [in] (0 = good default)
|
|
If you know how many elements you will need, pass that number here.
|
|
It is better to slightly overestimate than to slightly underestimate.
|
|
If you do not have a good estimate, then use zero.
|
|
block_element_count - [in] (0 = good default)
|
|
If block_element_count is zero, Create() will calculate a block
|
|
size that is efficent for most applications. If you are an expert
|
|
user and want to specify the number of blocks, then pass the number
|
|
of elements per block here. When block_element_count > 0 and
|
|
element_count_estimate > 0, the first block will be large enough
|
|
element_count_estimate*sizeof(T) bytes; in this case do not
|
|
ask for extraordinarly large amounts of contiguous heap.
|
|
Remarks:
|
|
You must call Create() on an unused ON_FixedSizePool or call Destroy()
|
|
before calling create.
|
|
Returns:
|
|
True if successful and the pool can be used.
|
|
*/
|
|
bool Create(
|
|
size_t element_count_estimate,
|
|
size_t block_element_count
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
Size of the elements in this pool.
|
|
*/
|
|
size_t SizeofElement() const;
|
|
|
|
/*
|
|
Returns:
|
|
A pointer to sizeof_element bytes. The memory is zeroed.
|
|
*/
|
|
T* AllocateElement();
|
|
|
|
/*
|
|
Description:
|
|
Return an element to the pool.
|
|
Parameters:
|
|
p - [in]
|
|
A pointer returned by AllocateElement().
|
|
It is critical that p be from this pool and that
|
|
you return a pointer no more than one time.
|
|
Remarks:
|
|
If you find the following remarks confusing, but you really want to use
|
|
ReturnElement(), then here are some simple guidelines.
|
|
1) SizeofElement() must be >= 16
|
|
2) SizeofElement() must be a multiple of 8.
|
|
3) Do not use FirstElement() and NextElement() to iterate through
|
|
the pool.
|
|
|
|
If 1 to 3 don't work for you, then you need to understand the following
|
|
information before using ReturnElement().
|
|
|
|
ON_FixedMemoryPool uses the first sizeof(void*) bytes of the
|
|
returned element for bookkeeping purposes. Therefore, if you
|
|
are going to use ReturnElement(), then SizeofElement() must be
|
|
at least sizeof(void*). If you are using a platform that requires
|
|
pointers to be aligned on sizeof(void*) boundaries, then
|
|
SizeofElement() must be a multiple of sizeof(void*).
|
|
If you are going to use ReturnElement() and then use FirstElement()
|
|
and NextElement() to iterate through the list of elements, then you
|
|
need to set a value in the returned element to indicate that it
|
|
needs to be skipped during the iteration. This value cannot be
|
|
located in the fist sizeof(void*) bytes of the element. If the
|
|
element is a class with a vtable, you cannot call a virtual
|
|
function on a returned element because the vtable pointer is
|
|
trashed when ReturnElement() modifies the fist sizeof(void*) bytes.
|
|
*/
|
|
void ReturnElement(T* p);
|
|
|
|
/*
|
|
Description:
|
|
Return all allocated elements to the pool. No heap is freed and
|
|
the pool remains initialized and ready for AllocateElement()
|
|
to be called.
|
|
*/
|
|
void ReturnAll();
|
|
|
|
/*
|
|
Description:
|
|
Destroy the pool and free all the heap. The pool cannot be used again
|
|
until Create() is called.
|
|
*/
|
|
void Destroy();
|
|
|
|
/*
|
|
Returns:
|
|
Number of active elements. (Elements that have been returned are not active.)
|
|
*/
|
|
size_t ActiveElementCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Total number of elements = number of active elements + number of returned elements.
|
|
*/
|
|
size_t TotalElementCount() const;
|
|
|
|
/*
|
|
Description:
|
|
Get the i-th elment in the pool.
|
|
Parameters:
|
|
element_index - [in]
|
|
Returns:
|
|
A pointer to the i-th element. The first element has index = 0
|
|
and is the element returned by the first call to AllocateElement().
|
|
The last element has index = ElementCount()-1.
|
|
If i is out of range, null is returned.
|
|
Remarks:
|
|
It is faster to use FirstElement() and NextElement() to iterate
|
|
through the entire list of elements. This function is relatively
|
|
efficient when there are a few large blocks in the pool
|
|
or element_index is small compared to the number of elements
|
|
in the first few blocks.
|
|
|
|
If ReturnElement() is not used or AllocateElement() calls to
|
|
are made after any use of ReturnElement(), then the i-th
|
|
element is the one returned by the (i+1)-th call to
|
|
AllocateElement().
|
|
*/
|
|
T* Element(size_t element_index) const;
|
|
|
|
size_t ElementIndex(
|
|
T*
|
|
) const;
|
|
|
|
private:
|
|
// prohibit copy construction and operator=.
|
|
ON_SimpleFixedSizePool(const ON_SimpleFixedSizePool<T>&);
|
|
ON_SimpleFixedSizePool<T>& operator=(const ON_SimpleFixedSizePool<T>&);
|
|
};
|
|
|
|
template <class T> class ON_SimpleFixedSizePoolIterator : private ON_FixedSizePoolIterator
|
|
{
|
|
public:
|
|
ON_SimpleFixedSizePoolIterator( const class ON_SimpleFixedSizePool<T>& fsp );
|
|
ON_SimpleFixedSizePoolIterator(const class ON_SimpleFixedSizePoolIterator<T>&);
|
|
|
|
/*
|
|
Description:
|
|
Get the first element when iterating through the list of elements.
|
|
Parameters:
|
|
element_index - [in]
|
|
If you use the version of FirstElement() that has an
|
|
element_index parameter, then the iteration begins at
|
|
that element.
|
|
Example:
|
|
The loop will iteratate through all the elements returned from
|
|
AllocateElement(), including any that have be returned to the pool
|
|
using ReturnElement().
|
|
|
|
// iterate through all elements in the pool
|
|
// This iteration will go through TotalElements() items.
|
|
for ( void* p = FirstElement(); 0 != p; p = NextElement() )
|
|
{
|
|
// If you are not using ReturnElement(), then you may process
|
|
// "p" immediately. If you have used ReturnElement(), then you
|
|
// must check some value in p located after the first sizeof(void*)
|
|
// bytes to see if p is active.
|
|
if ( p is not active )
|
|
continue;
|
|
|
|
... process p
|
|
}
|
|
|
|
Returns:
|
|
The first element when iterating through the list of elements.
|
|
Remarks:
|
|
FirstElement() and NextElement() will return elements that have
|
|
been returned to the pool using ReturnElement(). If you use
|
|
ReturnElement(), then be sure to mark the element so it can be
|
|
identified and skipped.
|
|
|
|
Do not make any calls to FirstBlock() or NextBlock() when using
|
|
FirstElement() and NextElement() to iteratate through elements.
|
|
*/
|
|
T* FirstElement();
|
|
T* FirstElement( size_t element_index );
|
|
|
|
/*
|
|
Description:
|
|
Get the next element when iterating through the list of elements.
|
|
If FirstElement() is not called, then the first call to
|
|
NextElement() returns the first element.
|
|
Example:
|
|
See the FirstElement() documentation.
|
|
Returns:
|
|
The next element when iterating through the list of elements.
|
|
Remarks:
|
|
FirstElement() and NextElement() will return elements that have
|
|
been returned to the pool using ReturnElement(). If you use
|
|
ReturnElement(), then be sure to mark the element so it can be
|
|
identified and skipped.
|
|
|
|
Do not make any calls to FirstBlock() or NextBlock() when using
|
|
FirstElement() and NextElement() to iteratate through elements.
|
|
*/
|
|
T* NextElement();
|
|
|
|
/*
|
|
Returns:
|
|
The most recently returned value from a call to FirstElement()
|
|
or NextElement().
|
|
Remarks:
|
|
Do not make any calls to FirstBlock() or NextBlock() when using
|
|
FirstElement() and NextElement() to iteratate through elements.
|
|
*/
|
|
T* CurrentElement();
|
|
|
|
/*
|
|
Description:
|
|
Sets the state of the iterator to the initail state that
|
|
exists after construction. This is useful if the iterator
|
|
has been used the get one or more elements and then
|
|
the referenced fixed size pool is modified or code wants
|
|
to begin iteration again a used a call to NextElement()
|
|
to return the first element.
|
|
*/
|
|
void Reset();
|
|
|
|
|
|
/*
|
|
Description:
|
|
Get a pointer to the first element in the first block.
|
|
Parameters:
|
|
block_element_count - [out] (can be null)
|
|
If not null, the number of elements allocated from the
|
|
first block is returned in block_element_count.
|
|
Note that if you have used ReturnElement(), some
|
|
of these elemements may have been returned.
|
|
Example:
|
|
The loop will iteratate through all the blocks.
|
|
|
|
// iterate through all blocks in the pool
|
|
size_t block_element_count = 0;
|
|
for ( void* p = FirstBlock(&block_element_count);
|
|
0 != p;
|
|
p = NextBlock(&block_element_count)
|
|
)
|
|
{
|
|
ElementType* e = (ElementType*)p;
|
|
for ( size_t i = 0;
|
|
i < block_element_count;
|
|
i++, e = ((const char*)e) + SizeofElement()
|
|
)
|
|
{
|
|
...
|
|
}
|
|
}
|
|
|
|
Returns:
|
|
The first block when iterating the list of blocks.
|
|
Remarks:
|
|
The heap for a fixed size memory pool is simply a linked
|
|
list of blocks. FirstBlock() and NextBlock() can be used
|
|
to iterate through the list of blocks.
|
|
|
|
Do not make any calls to FirstElement() or NextElement() when using
|
|
FirstBlock() and NextBlock() to iteratate through blocks.
|
|
*/
|
|
T* FirstBlock( size_t* block_element_count );
|
|
|
|
/*
|
|
Description:
|
|
Get the next block when iterating through the blocks.
|
|
Parameters:
|
|
block_element_count - [out] (can be null)
|
|
If not null, the number of elements allocated from the
|
|
block is returned in block_element_count. Note that if
|
|
you have used ReturnElement(), some of these elemements
|
|
may have been returned.
|
|
Example:
|
|
See the FirstBlock() documentation.
|
|
Returns:
|
|
The next block when iterating through the blocks.
|
|
Remarks:
|
|
Do not make any calls to FirstElement() or NextElement() when using
|
|
FirstBlock() and NextBlock() to iteratate through blocks.
|
|
*/
|
|
T* NextBlock( size_t* block_element_count );
|
|
|
|
private:
|
|
// no implementation (you can use a copy construtor)
|
|
class ON_SimpleFixedSizePoolIterator<T>& operator=(const class ON_SimpleFixedSizePoolIterator<T>&);
|
|
};
|
|
|
|
// definitions of the template functions are in a different file
|
|
// so that Microsoft's developer studio's autocomplete utility
|
|
// will work on the template functions.
|
|
#include "opennurbs_fsp_defs.h"
|
|
|
|
#endif
|
|
|