deargui-vpl/ref/virtools/Includes/XArray.h

1011 lines
22 KiB
C++

/*************************************************************************/
/* File : XArray.h */
/* Author : Aymeric Bard */
/* */
/* Virtools SDK */
/* Copyright (c) Virtools 2000, All Rights Reserved. */
/*************************************************************************/
#ifndef _XARRAY_H_
#define _XARRAY_H_
#include "XUtil.h"
#include <string.h>
#ifdef __GNUC__
void* VxNewAligned(int size,int align);
void VxDeleteAligned(void*);
#endif
/************************************************
{filename:XArray}
Name: XArray
Summary: Class representation of an array.
Remarks:
The array has a notion of reserved size, which doubles each time it is
reached. The reserved size reduces only if the occupation of the array goes
below 30% of the reserved size.
You mustn't store classes of variable size into an XArray. Use XClassArray for this.
See Also : XClassArray, XSArray
************************************************/
template <class T,int Alignment = 0>
class XArray
{
public:
typedef XArray<T,Alignment> Array;
// Types
typedef T* Iterator;
typedef T Type;
typedef T& Reference;
/************************************************
Summary: Constructors.
Input Arguments:
ss: Default number of reserved elements.
a: An array to copy from.
************************************************/
XArray(int ss=0)
{
// Allocated
if (ss>0) {
m_Begin = Allocate(ss);
m_End = m_Begin;
m_AllocatedEnd = m_Begin+ss;
} else {
m_AllocatedEnd = 0;
m_Begin = m_End = 0;
}
}
// copy Ctor
//template<int A>
XArray(const Array& a)
{
// the resize
int size = a.Size();
m_Begin = Allocate(size);
m_End = m_Begin+size;
m_AllocatedEnd = m_End;
// The copy
XCopy(m_Begin,a.m_Begin,a.m_End);
}
/************************************************
Summary: Destructor.
Remarks:
Release the elements contained in the array. If
you were storing pointers, you need first to iterate
on the array and call delete on each pointer.
************************************************/
~XArray()
{
Free();
}
/************************************************
Summary: Affectation operator.
Remarks:
The content of the array is enterely overwritten
by the given array.
************************************************/
//template<int A>
Array& operator = (const Array& a)
{
if(this != &a) {
if (Allocated() >= a.Size()) { // No need to allocate
// The copy
XCopy(m_Begin,a.m_Begin,a.m_End);
m_End = m_Begin + a.Size();
} else {
Free();
// the resize
int size = a.Size();
m_Begin = Allocate(size);
m_End = m_Begin+size;
m_AllocatedEnd = m_End;
// The copy
XCopy(m_Begin,a.m_Begin,a.m_End);
}
}
return *this;
}
/************************************************
Summary: Appends the content of another array.
Remarks:
The content of the array is conserved.
************************************************/
//template<int A>
Array& operator += (const Array& a)
{
int size = a.Size();
if (size) {
int oldsize = Size();
int newsize = oldsize+size+1;
if (newsize <= Allocated()) { // The new array fits in
// we recopy the new array
XCopy(m_End,a.m_Begin,a.m_End);
m_End += size;
} else { // the new array dosn't fit in
T* temp = Allocate(newsize);
// we recopy the old array
XCopy(temp,m_Begin,m_End);
m_End = temp+oldsize;
// we copy the given array
XCopy(m_End,a.m_Begin,a.m_End);
m_End += size;
m_AllocatedEnd = m_End+1;
// we free the old memory
Free();
// we set the new pointer
m_Begin = temp;
}
}
return *this;
}
/************************************************
Summary: Removes the elements of the given array
from the array.
Remarks:
The content of the array is conserved.
************************************************/
//template<int A>
Array& operator -= (const Array& a)
{
int size = a.Size();
if (size) {
int oldsize = Size();
if (oldsize) {
T* newarray = Allocate(oldsize+1);
T* temp = newarray;
for(T* t = m_Begin; t != m_End; ++t) {
// we search for the element in the other array
if(a.Find(*t) == a.m_End) {
// the element is not in the other array, we copy it to the newone
*temp = *t;
++temp;
}
}
Free();
// we set the new pointers
m_Begin = newarray;
m_End = temp;
m_AllocatedEnd = m_Begin+oldsize+1;
}
}
return *this;
}
/************************************************
Summary: Removes all the elements from an array.
Remarks:
There is no more space reserved after this call.
************************************************/
void Clear()
{
Free();
m_Begin = 0;
m_End = 0;
m_AllocatedEnd = 0;
}
/************************************************
Summary: Ensures than the reserved size equals the real size..
************************************************/
void Compact()
{
if (m_AllocatedEnd > m_End) {
int size = Size();
if (!size) return;
T* newdata = Allocate(size);
// copy before insertion point
XCopy(newdata,m_Begin,m_End);
Free();
m_Begin = newdata;
m_AllocatedEnd = m_End = newdata+size;
}
}
/************************************************
Summary: Reserves n elements for an array.
Remarks:
The elements beyond the reserved limit are
discarded.
************************************************/
void Reserve(int size)
{
// allocation of new size
T* newdata = Allocate(size);
// Recopy of old elements
T* last = XMin(m_Begin+size,m_End);
XCopy(newdata,m_Begin,last);
// new Pointers
Free();
m_End = newdata+(last-m_Begin);
m_Begin = newdata;
m_AllocatedEnd = newdata+size;
}
/************************************************
Summary: Resizes the array.
Input Arguments:
size: New size of the array.
Remarks:
After Resize(n) (n>0), you can address elements from [0]
to [n-1].
No constructors are called (use an XClassArray if it is
desired).
If the size is greater than the reserved size,
the array is reallocated at the exact needed size.
If not, there is no reallocation at all. Resize(0)
is faster than Clear() if you know you will probably
push some more elements after.
See Also:Reserve
************************************************/
void Resize(int size)
{
XASSERT(size>=0);
// we check if the array has enough capacity
int oldsize = (m_AllocatedEnd-m_Begin);
// If not, we allocate extra data
if (size > oldsize) Reserve(size);
// if (size+1 > oldsize) Reserve(size+1); // +1 for research
// We set the end cursor
m_End = m_Begin+size;
}
/************************************************
Summary: Expands an array of e elements.
Input Arguments:
e: size to expand.
************************************************/
void Expand(int e = 1)
{
// we check if the array has enough capacity
// If not, we allocate extra data
while (Size()+e > Allocated()) {
Reserve(Allocated()?Allocated()*2:2);
}
// We set the end cursor
m_End += e;
}
/************************************************
Summary: Compress an array of e elements.
Input Arguments:
e: size to compress.
************************************************/
void Compress(int e = 1)
{
if (m_Begin + e <= m_End) {
// We set the end cursor
m_End -= e;
} else {
m_End = m_Begin;
}
}
/************************************************
Summary: Inserts an element at the end of an array.
Input Arguments:
o: object to insert.
************************************************/
void PushBack(const T& o)
{
if (m_End == m_AllocatedEnd) {
Reserve(Size()?Size()*2:2);
}
*(m_End++) = o;
}
/************************************************
Summary: Inserts an element at the start of an array.
Input Arguments:
o: object to insert.
Remarks:
This function can be slow if your array is
well filled.
************************************************/
void PushFront(const T& o)
{
XInsert(m_Begin,o);
}
/************************************************
Summary: Inserts an element before another one.
Input Arguments:
i: iterator on the element to insert before.
pos: position to insert the object
o: object to insert.
Remarks:
The element to insert before is given as
an iterator on it, i.e. a pointer on it in
this case.
************************************************/
void Insert(T* i, const T& o)
{
if(i<m_Begin || i>m_End) return;
// The Call
XInsert(i,o);
}
void Insert(int pos, const T& o)
{
Insert(m_Begin+pos,o);
}
// dicchotomic sorted insertion (use the < operator)
void InsertSorted(const T& o)
{
T* begin = m_Begin;
T* end = m_End;
while (begin < end) {
T* pivot = begin + ((end-begin)>>1);
if (o < *pivot)
end = pivot;
else
begin = pivot+1;
}
// The Call
XInsert(begin,o);
}
/************************************************
Summary: Moves the element n before the element i.
Input Arguments:
n: iterator on the element to move.
i: iterator on the element to insert before.
Remarks:
The elements are given by iterators on them,
i.e. pointer on them in this case.
************************************************/
void Move(T* i, T* n)
{
if(i<m_Begin || i>m_End) return;
if(n<m_Begin || n>m_End) return;
// The Call
int insertpos = i - m_Begin;
if (n < i) --insertpos;
T tn = *n;
XRemove(n);
Insert(insertpos,tn);
}
/************************************************
Summary: Removes the last element of an array.
Remarks:
You must be sure that the array isn't empty.
Return Value: object removed.
************************************************/
T PopBack()
{
// If there is no last element, it will crash
T t = *(m_End-1);
XRemove(m_End-1);
return t;
}
/************************************************
Summary: Removes the first element of an array.
************************************************/
void PopFront()
{
// we remove the first element only if it exists
if(m_Begin != m_End) XRemove(m_Begin);
}
/************************************************
Summary: Removes an element at a given position.
Input Arguments:
pos: position of the object to remove.
old: value of the element removed.
Return Value: an iterator on the next
element after the element removed (to go on with
an iteration).
************************************************/
XBOOL RemoveAt(unsigned int pos,T& old)
{
T* t = m_Begin+pos;
// we ensure i is in boundary...
if(t >= m_End) return 0;
old = *t; // we keep the old value
// the removal
XRemove(t);
return TRUE; // really removed
}
BOOL EraseAt(int pos)
{
return (BOOL)Remove(m_Begin+pos);
}
T* RemoveAt(int pos)
{
return Remove(m_Begin+pos);
}
/************************************************
Summary: Removes an element.
Input Arguments:
i: iterator on the element to remove.
o: object to remove.
Return Value: An iterator on the next
element after the element removed (to go on with
an iteration).
Remarks:
The elements are given by iterators on them,
i.e. pointer on them in this case.
************************************************/
T* Remove(T* i)
{
// we ensure i is in boundary...
if(i<m_Begin || i>=m_End) return 0;
// the Call
return XRemove(i);
}
T* Remove(const T& o)
{
T* t = Find(o);
// we ensure i is in boundary...
if(t<m_Begin || t>=m_End) return 0;
// the Call
return XRemove(t);
}
BOOL Erase(const T& o)
{
T* t = Find(o);
// we ensure i is in boundary...
if(t<m_Begin || t>=m_End)
return FALSE;
// the Call
return (BOOL)XRemove(t);
}
void FastRemove(const T& o)
{
FastRemove(Find(o));
}
void FastRemove(const Iterator& iT)
{
// we ensure i is in boundary...
if(iT<m_Begin || iT>=m_End)
return;
m_End--;
if (iT < m_End)
*iT = *m_End;
}
void FastRemoveAt(int pos)
{
FastRemove(Begin() + pos);
}
/************************************************
Summary: Fills an array with a value.
Input Arguments:
o: value to fill.
************************************************/
void Fill(const T& o)
{
for(T* t = m_Begin; t != m_End; ++t)
*t=o;
}
/************************************************
Summary: Fills an array with a BYTE value.
Input Arguments:
val: byte value to fill.
************************************************/
void Memset(XBYTE val)
{
memset(m_Begin,val,(m_End-m_Begin)*sizeof(T));
}
/************************************************
Summary: Access to an array element.
Input Arguments:
i: index of the element to access.
Return Value: a reference on the object accessed.
Remarks:
No test are provided on i.
************************************************/
const T& operator [](int i) const
{
XASSERT(i>=0 && i<Size());
return *(m_Begin+i);
}
T& operator [](int i)
{
XASSERT(i>=0 && i<Size());
return *(m_Begin+i);
}
/************************************************
Summary: Access to an array element.
Input Arguments:
i: index of the element to access.
Return Value: a pointer on the object accessed.
Remarks:
End() is returned if i is outside the array
limits.
************************************************/
T* At(unsigned int i)
{
T* t = m_Begin+i;
if ((t >= m_Begin) && (t < m_End)) return t;
else return m_End;
}
const T* At(unsigned int i) const
{
T* t = m_Begin+i;
if ((t >= m_Begin) && (t < m_End)) return t;
else return m_End;
}
/************************************************
Summary: Finds an element.
Input Arguments:
o: element to find.
Return Value: a pointer on the first object found
or End() if the object is not found.
************************************************/
T* Find(const T& o) const
{
// FRom roro : To Check !!!!!!
// If the array is empty
// if(!(m_End - m_Begin)) return m_End;
// *m_End = o;
// T* t = m_Begin;
// while(*t != o) ++t;
T* t = m_Begin;
while(t < m_End && *t != o)
++t;
// Some times faster : To Disassemble
// T* t = m_Begin-1;
// do ++t; while(*t != o);
return t;
}
/************************************************
Summary: Dichotomic search : finds an element in an array that is sorted in
increasing order.
Input Arguments:
o: element to find.
Return Value: a pointer on the first object found
or End() if the object is not found.
************************************************/
T* BinaryFind(const T& o) const
{
int low = 0;
int high = Size() - 1;
while (low <= high)
{
int mid = (low + high) >> 1;
if (m_Begin[mid] > o)
{
high = mid - 1;
}
else if (m_Begin[mid] < o)
{
low = mid + 1;
}
else
{
return m_Begin + mid;
}
}
return NULL;
}
/************************************************
Summary: Tests for an element presence.
Input Arguments:
o: element to test.
Return Value: TRUE if the element is present.
************************************************/
XBOOL IsHere(const T& o) const
{
T* t = m_Begin;
while(t < m_End && *t != o) ++t;
return (t != m_End);
}
/************************************************
Summary: Returns the position of an element.
Input Arguments:
o: element to find.
Return Value: position or -1 if not found.
************************************************/
int GetPosition(const T& o) const
{
T* t = Find(o);
// If the element is not found
if(t == m_End) return -1;
// else return the position
return t-m_Begin;
}
/************************************************
Summary: Swaps two items in array.
Input Arguments:
pos1: position of first item to swap
pos2: position of second item to swap.
************************************************/
void Swap(int pos1,int pos2)
{
char buffer[sizeof(T)];
memcpy(buffer,m_Begin+pos1,sizeof(T));
memcpy(m_Begin+pos1,m_Begin+pos2,sizeof(T));
memcpy(m_Begin+pos2,buffer,sizeof(T));
}
/************************************************
Summary: Swaps two arrays.
Input Arguments:
o: second array to swap.
************************************************/
void Swap(Array& a)
{
XSwap(m_Begin,a.m_Begin);
XSwap(m_End,a.m_End);
XSwap(m_AllocatedEnd,a.m_AllocatedEnd);
}
void Attach(T* iArray,int iCount)
{
Clear();
m_Begin=iArray;
m_End=m_Begin+iCount;
}
void Detach()
{
m_Begin=0;
m_End=0;
m_AllocatedEnd=0;
}
/************************************************
Summary: Returns the first element of an array.
Remarks:
No test are provided to see if there is an
element.
************************************************/
T& Front() {return *Begin();}
const T& Front() const {return *Begin();}
/************************************************
Summary: Returns the last element of an array.
Remarks:
No test are provided to see if there is an
element.
************************************************/
T& Back() {return *(End()-1);}
const T& Back() const {return *(End()-1);}
/************************************************
Summary: Returns an iterator on the first element.
Example:
Typically, an algorithm iterating on an array
looks like:
for(T* t = a.Begin(); t != a.End(); ++t) {
// do something with *t
}
************************************************/
T* Begin() const {return m_Begin;}
/************************************************
Summary: Returns an iterator on the last element.
************************************************/
T* RBegin() const {return m_End-1;}
/************************************************
Summary: Returns an iterator after the last element.
************************************************/
T* End() const {return m_End;}
/************************************************
Summary: Returns an iterator before the first element.
************************************************/
T* REnd() const {return m_Begin-1;}
/************************************************
Summary: Returns the elements number.
************************************************/
int Size() const {return m_End-m_Begin;}
/************************************************
Summary: Returns whether the array is empty (it is faster to use
IsEmpty than Size when testing for array size...)
************************************************/
bool IsEmpty() const {return m_End == m_Begin;}
/************************************************
Summary: Returns the occupied size in memory in bytes
Parameters:
addstatic: TRUE if you want to add the size occupied
by the class itself.
************************************************/
int GetMemoryOccupation(XBOOL addstatic=FALSE) const {return Allocated()*sizeof(T)+(addstatic?sizeof(*this):0);}
/************************************************
Summary: Returns the elements allocated.
************************************************/
int Allocated() const {return m_AllocatedEnd-m_Begin;}
static int XCompare(const void *elem1, const void *elem2 )
{
return *(T*)elem1 - *(T*)elem2;
}
/************************************************
Summary: Sorts an array with a quick sort.
Input Arguments:
compare: The function comparing two elements.
Remarks:
Two sorts algorithm are available : BubbleSort
and (quick)Sort.
************************************************/
void Sort(VxSortFunc compare = XCompare)
{
if (Size() > 1) qsort(m_Begin,Size(),sizeof(T),compare);
}
/************************************************
Summary: Sorts an array with a bubble sort.
Input Arguments:
compare: The function comparing two elements.
Remarks:
Two sorts algorithm are available : BubbleSort
and (quick)sort.
************************************************/
void BubbleSort(T* rangestart, T* rangeend,VxSortFunc compare = XCompare)
{
if (!compare) return;
if ((rangeend-rangestart)<=1) return;
XBOOL Noswap=TRUE;
for (T* it1=rangestart+1;it1<rangeend;it1++) {
for (T* it2=rangeend-1;it2>=it1;it2--) {
T* t2= it2-1;
if (compare(it2,t2) < 0) {
XSwap(*it2,*t2);
Noswap=FALSE;
}
}
if (Noswap) break;
Noswap=TRUE;
}
}
/************************************************
Summary: Sorts an array with a bubble sort.
Input Arguments:
compare: The function comparing two elements.
Remarks:
Two sorts algorithm are available : BubbleSort
and (quick)sort.
************************************************/
void BubbleSort(VxSortFunc compare = XCompare)
{
if (!compare) return;
if ((m_End-m_Begin)<=1) return;
XBOOL Noswap=TRUE;
for (T* it1=m_Begin+1;it1<m_End;it1++) {
for (T* it2=m_End-1;it2>=it1;it2--) {
T* t2= it2-1;
if (compare(it2,t2) < 0) {
XSwap(*it2,*t2);
Noswap=FALSE;
}
}
if (Noswap) break;
Noswap=TRUE;
}
}
protected:
///
// Methods
// Copy {secret}
void XCopy(T* dest, T* start, T* end)
{
int size = ((XBYTE*)end - (XBYTE*)start);
if(size)
memcpy(dest,start,size);
}
// Move {secret}
void XMove(T* dest, T* start, T* end)
{
int size = ((XBYTE*)end - (XBYTE*)start);
if(size)
memmove(dest,start,size);
}
// Insert {secret}
void XInsert(T* i, const T& o)
{
XASSERT(i >= m_Begin);
XASSERT(i <= m_End);
// Test For Reallocation
if (m_End == m_AllocatedEnd) {
int newsize = (m_AllocatedEnd-m_Begin)*2;//+m_AllocationSize;
if(!newsize) newsize = 2;
T* newdata = Allocate(newsize);
// copy before insertion point
XCopy(newdata,m_Begin,i);
// copy the new element
T* insertionpoint = newdata+(i-m_Begin);
*(insertionpoint) = o;
// copy after insertion point
XCopy(insertionpoint+1,i,m_End);
// New Pointers
m_End = newdata+(m_End-m_Begin);
Free();
m_Begin = newdata;
m_AllocatedEnd = newdata+newsize;
} else {
// copy after insertion point
XMove(i+1,i,m_End);
// copy the new element
*i = o;
}
m_End++;
}
// Remove {secret}
T* XRemove(T* i)
{
// copy after insertion point
XMove(i,i+1,m_End);
m_End--;
return i;
}
///
// Allocation and deallocation methods : to be override for alignement purposes
// Allocation {secret}
T* Allocate(int size)
{
if(size) {
if (Alignment != 0)
return (T*)VxNewAligned(sizeof(T)*size,Alignment);
else
return (T*)new T[size];
}
else return 0;
}
// Free {secret}
void Free()
{
if (Alignment != 0)
VxDeleteAligned(m_Begin);
else
delete [] m_Begin;
}
///
// Members
// elements start {secret}
T* m_Begin;
// elements end {secret}
T* m_End;
// reserved end {secret}
T* m_AllocatedEnd;
};
#endif