//------------------------------------------------------------------------------
// emOwnPtrArray.h
//
// Copyright (C) 2024 Oliver Hamann.
//
// Homepage: http://eaglemode.sourceforge.net/
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License version 3 as published by the
// Free Software Foundation.
//
// 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 version 3 for
// more details.
//
// You should have received a copy of the GNU General Public License version 3
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------
#ifndef emOwnPtrArray_h
#define emOwnPtrArray_h
#ifndef emArray_h
#include <emCore/emArray.h>
#endif
//==============================================================================
//=============================== emOwnPtrArray ================================
//==============================================================================
template <class OBJ> class emOwnPtrArray {
public:
// Template class for a dynamic array of smart pointers which own the
// referenced objects. The objects are deleted by calling the normal
// delete operator. NULL pointers are allowed.
emOwnPtrArray();
~emOwnPtrArray();
int GetCount() const;
// Get number of elements.
void SetCount(int count, bool compact=false);
// Set the number of elements in this array. Additional elements
// are set to NULL.
// Arguments:
// count - The new number of elements in the array.
// compact - Whether to make the capacity equal to the count.
void Compact();
// Make the capacity equal to the count.
const OBJ * const * Get() const;
OBJ * * Get();
// Get a pointer to the pointer to the first element in this
// array, that is, get the array as a normal C array.
const OBJ * Get(int index) const;
OBJ * Get(int index);
const OBJ * operator [] (int index) const;
OBJ * operator [] (int index);
// Get a pointer to an element. The index must be within the
// range of 0 to GetCount()-1.
void Set(int index, OBJ * obj);
// Assign an object pointer at the given index and take
// ownership of the pointed object. Assigning NULL is allowed.
// The previously owned object is deleted.
void Reset(int index);
// Same as Set(index,NULL).
OBJ * Release(int index);
// Release ownership of the object at the given index, set NULL
// there, and return the object pointer.
void Add(OBJ * obj, bool compact=false);
emOwnPtrArray & operator += (OBJ * obj);
void Insert(int index, OBJ * obj, bool compact=false);
// Take ownership of the given object and add it to the end of
// the array, or insert it at the given index. NULL is allowed.
void Remove(int index, int remCount=1, bool compact=false);
// Remove objects at a particular position.
void Clear(bool compact=false);
// Remove all objects.
// Arguments:
// compact - Whether to minimize the internal array capacity.
bool IsEmpty() const;
// Ask whether the number of objects is zero.
bool Sort(
int(*compare)(const OBJ * obj1, const OBJ * obj2, void * context),
void * context=NULL
);
// Sort this array. The order of equal elements is preserved.
// Arguments:
// compare - Function for comparing two elements.
// If you want the elements to be compared via the
// operators '<' and '>', say:
// emStdComparer<OBJ>::Compare
// with OBJ replaced by the real type of the
// elements. The context argument is ignored then.
// Arguments:
// obj1 - Pointer to first element.
// obj2 - Pointer to second element.
// context - See below.
// Returns: Zero if the elements are equal, a value
// greater than zero if the first element is
// greater than the second one, and a value less
// than zero if the first element is less than the
// second one.
// context - Any pointer to be forwarded to the compare
// function.
// Returns: Whether there was a change.
int BinarySearchByKey(
void * key,
int(*compareObjKey)(const OBJ * obj, void * key, void * context),
void * context=NULL
) const;
// Binary search for an element that matches the given key. The
// array must already be sorted accordingly.
// Arguments:
// key - The key to search for.
// compareObjKey - Function for comparing an object with the
// key.
// context - Any pointer to be forwarded to the compare
// function.
// Returns:
// If a matching element could be found, the index of that
// element is returned. Otherwise a value less than zero is
// returned: the binary inversion of the index for insertion.
void BinaryInsert(
OBJ * obj,
int(*compare)(const OBJ * obj1, const OBJ * obj2,
void * context),
void * context=NULL,
bool compact=false
);
// Insert an element by sorting it into the array, even if there
// is already an element which equals the given object. The
// array must already be sorted by the same compare function.
// Arguments:
// obj - An object to be copied for the insertion.
// compare - Please see the Sort method.
// context - Please see the Sort method.
// compact - Whether to minimize the capacity.
bool BinaryRemoveByKey(
void * key,
int(*compareObjKey)(const OBJ * obj, void * key, void * context),
void * context=NULL,
bool compact=false
);
// Like BinarySearchByKey, but remove the found element, or
// return false if no such element can been found.
private:
struct WrappedCmpContext {
int(*compare)(const OBJ * obj1, const OBJ * obj2, void * context);
void * context;
};
struct WrappedCmpObjKeyContext {
int(*compareObjKey)(const OBJ * obj, void * key, void * context);
void * context;
};
void AdaptCapacity(int newCount, bool compact=false);
emOwnPtrArray(const emOwnPtrArray&);
emOwnPtrArray & operator = (const emOwnPtrArray &);
// Copying is not allowed.
static int WrappedCompare(
const OBJ * const * obj1, const OBJ * const * obj2, void * context
);
static int WrappedCompareObjKey(
const OBJ * const * obj, void * key, void * context
);
int Count, Capacity;
OBJ * * Array;
};
//==============================================================================
//============================== Implementations ===============================
//==============================================================================
template <class OBJ>
inline emOwnPtrArray<OBJ>::emOwnPtrArray()
: Count(0),
Capacity(0),
Array(NULL)
{
}
template <class OBJ>
inline emOwnPtrArray<OBJ>::~emOwnPtrArray()
{
SetCount(0,true);
}
template <class OBJ>
inline int emOwnPtrArray<OBJ>::GetCount() const
{
return Count;
}
template <class OBJ>
void emOwnPtrArray<OBJ>::SetCount(int count, bool compact)
{
if (Count<count) {
AdaptCapacity(count, compact);
memset(Array+Count,0,sizeof(OBJ*)*(count-Count));
Count=count;
}
else {
if (count<0) count=0;
while (Count>count) {
Count--;
if (Array[Count]) delete Array[Count];
}
AdaptCapacity(Count, compact);
}
}
template <class OBJ>
inline void emOwnPtrArray<OBJ>::Compact()
{
AdaptCapacity(Count,true);
}
template <class OBJ>
inline const OBJ * const * emOwnPtrArray<OBJ>::Get() const
{
return Array;
}
template <class OBJ>
inline OBJ * * emOwnPtrArray<OBJ>::Get()
{
return Array;
}
template <class OBJ>
inline const OBJ * emOwnPtrArray<OBJ>::Get(int index) const
{
return Array[index];
}
template <class OBJ>
inline OBJ * emOwnPtrArray<OBJ>::Get(int index)
{
return Array[index];
}
template <class OBJ>
inline const OBJ * emOwnPtrArray<OBJ>::operator [](int index) const
{
return Array[index];
}
template <class OBJ>
inline OBJ * emOwnPtrArray<OBJ>::operator [](int index)
{
return Array[index];
}
template <class OBJ>
inline void emOwnPtrArray<OBJ>::Set(int index, OBJ * obj)
{
if (Array[index]) delete Array[index];
Array[index] = obj;
}
template <class OBJ>
inline void emOwnPtrArray<OBJ>::Reset(int index)
{
Set(index,NULL);
}
template <class OBJ>
inline OBJ * emOwnPtrArray<OBJ>::Release(int index)
{
OBJ * e;
e=Array[index];
Array[index]=NULL;
return e;
}
template <class OBJ>
inline void emOwnPtrArray<OBJ>::Add(OBJ * obj, bool compact)
{
Insert(Count,obj,compact);
}
template <class OBJ>
inline emOwnPtrArray<OBJ> & emOwnPtrArray<OBJ>::operator += (OBJ * obj)
{
Add(obj);
return *this;
}
template <class OBJ>
void emOwnPtrArray<OBJ>::Insert(int index, OBJ * obj, bool compact)
{
int n;
if (index<0) index=0;
if (index>Count) index=Count;
Count++;
AdaptCapacity(Count,compact);
n=Count-index-1;
if (n>0) memmove(Array+index+1,Array+index,sizeof(OBJ*)*n);
Array[index]=obj;
}
template <class OBJ>
void emOwnPtrArray<OBJ>::Remove(int index, int remCount, bool compact)
{
int i,n;
if (index<0) { remCount+=index; index=0; }
if (remCount>Count-index) remCount=Count-index;
if (remCount<=0) return;
for (i=index; i<index+remCount; i++) {
if (Array[i]) delete Array[i];
}
n=Count-index-remCount;
if (n>0) memmove(Array+index,Array+index+remCount,sizeof(OBJ*)*n);
Count-=remCount;
AdaptCapacity(Count,compact);
}
template <class OBJ>
inline void emOwnPtrArray<OBJ>::Clear(bool compact)
{
SetCount(0,compact);
}
template <class OBJ>
inline bool emOwnPtrArray<OBJ>::IsEmpty() const
{
return Count==0;
}
template <class OBJ>
bool emOwnPtrArray<OBJ>::Sort(
int(*compare)(const OBJ * obj1, const OBJ * obj2, void * context),
void * context
)
{
WrappedCmpContext wrapped;
wrapped.compare=compare;
wrapped.context=context;
return emSortArray((const OBJ**)Array,Count,WrappedCompare,&wrapped);
}
template <class OBJ>
int emOwnPtrArray<OBJ>::BinarySearchByKey(
void * key,
int(*compareObjKey)(const OBJ * obj, void * key, void * context),
void * context
) const
{
WrappedCmpObjKeyContext wrapped;
wrapped.compareObjKey=compareObjKey;
wrapped.context=context;
return emBinarySearch((const OBJ**)Array,Count,key,WrappedCompareObjKey,&wrapped);
}
template <class OBJ> void emOwnPtrArray<OBJ>::BinaryInsert(
OBJ * obj,
int(*compare)(const OBJ * obj1, const OBJ * obj2, void * context),
void * context, bool compact
)
{
WrappedCmpContext wrapped;
int i;
wrapped.compare=compare;
wrapped.context=context;
i=emBinarySearch(
(const OBJ * *)Array,Count,
(const OBJ * const *)&obj,
WrappedCompare,&wrapped
);
if (i<0) i=~i;
Insert(i,obj,compact);
}
template <class OBJ>
bool emOwnPtrArray<OBJ>::BinaryRemoveByKey(
void * key,
int(*compareObjKey)(const OBJ * obj, void * key, void * context),
void * context, bool compact
)
{
int i;
i=BinarySearchByKey(key,compareObjKey,context);
if (i>=0) {
Remove(i,1,compact);
return true;
}
else {
if (compact) Compact();
return false;
}
}
template <class OBJ>
void emOwnPtrArray<OBJ>::AdaptCapacity(int newCount, bool compact)
{
int capacity;
if (compact) capacity=newCount;
else if (Capacity<newCount || Capacity>=newCount*3) capacity=newCount*2;
else return;
if (Capacity==capacity) return;
if (capacity==0) {
free(Array);
Array=NULL;
}
else {
Array=(OBJ**)realloc((void*)Array,sizeof(OBJ*)*capacity);
}
Capacity=capacity;
}
template <class OBJ>
inline emOwnPtrArray<OBJ>::emOwnPtrArray(const emOwnPtrArray&)
{
}
template <class OBJ>
inline emOwnPtrArray<OBJ> & emOwnPtrArray<OBJ>::operator =
(const emOwnPtrArray&)
{
return *this;
}
template <class OBJ>
int emOwnPtrArray<OBJ>::WrappedCompare(
const OBJ * const * obj1, const OBJ * const * obj2, void * context
)
{
const WrappedCmpContext * wrapped;
wrapped=(WrappedCmpContext*)context;
return wrapped->compare(*obj1,*obj2,wrapped->context);
}
template <class OBJ>
int emOwnPtrArray<OBJ>::WrappedCompareObjKey(
const OBJ * const * obj, void * key, void * context
)
{
const WrappedCmpObjKeyContext * wrapped;
wrapped=(WrappedCmpObjKeyContext*)context;
return wrapped->compareObjKey(*obj,key,wrapped->context);
}
#endif