openclonk/engine/src/C4ValueList.cpp

299 lines
7.4 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2001-2007 Peter Wortmann
* Copyright (c) 2005-2007 Sven Eberhardt
* Copyright (c) 2006-2007 Günther Brammer
* Copyright (c) 2008 Armin Burgmeier
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* See isc_license.txt for full license and disclaimer.
*
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
#include <C4Include.h>
#include <C4ValueList.h>
#include <algorithm>
#ifndef BIG_C4INCLUDE
#include <C4Aul.h>
#include <C4FindObject.h>
#endif
C4ValueList::C4ValueList()
: iSize(0), pData(NULL)
{
}
C4ValueList::C4ValueList(int32_t inSize)
: iSize(0), pData(NULL)
{
SetSize(inSize);
}
C4ValueList::C4ValueList(const C4ValueList &ValueList2)
: iSize(0), pData(NULL)
{
SetSize(ValueList2.GetSize());
for(int32_t i = 0; i < iSize; i++)
pData[i].Set(ValueList2.GetItem(i));
}
C4ValueList::~C4ValueList()
{
delete[] pData; pData = NULL;
iSize = 0;
}
C4ValueList &C4ValueList::operator =(const C4ValueList& ValueList2)
{
this->SetSize(ValueList2.GetSize());
for(int32_t i = 0; i < iSize; i++)
pData[i].Set(ValueList2.GetItem(i));
return *this;
}
class C4SortObjectSTL
{
private:
C4SortObject &rSorter;
public:
C4SortObjectSTL(C4SortObject &rSorter) : rSorter(rSorter) {}
bool operator ()(const C4Value &v1, const C4Value &v2) { return rSorter.Compare(v1._getObj(), v2._getObj()) > 0; }
};
class C4SortObjectSTLCache
{
private:
C4SortObject &rSorter;
C4Value *pVals;
public:
C4SortObjectSTLCache(C4SortObject &rSorter, C4Value *pVals) : rSorter(rSorter), pVals(pVals) {}
bool operator ()(int32_t n1, int32_t n2) { return rSorter.CompareCache(n1, n2, pVals[n1]._getObj(), pVals[n2]._getObj()) > 0; }
};
void C4ValueList::Sort(class C4SortObject &rSort)
{
if(rSort.PrepareCache(this))
{
// Initialize position array
intptr_t i, *pPos = new intptr_t[iSize];
for(i = 0; i < iSize; i++) pPos[i] = i;
// Sort
std::stable_sort(pPos, pPos+iSize, C4SortObjectSTLCache(rSort, pData));
// Save actual object pointers in array (hacky).
for(i = 0; i < iSize; i++)
pPos[i] = reinterpret_cast<intptr_t>(pData[pPos[i]]._getObj());
// Set the values
for(i = 0; i < iSize; i++)
pData[i].SetObject(reinterpret_cast<C4Object *>(pPos[i]));
delete [] pPos;
}
else
// Be sure to use stable sort, as otherweise the algorithm isn't garantueed
// to produce identical results on all platforms!
std::stable_sort(pData, pData+iSize, C4SortObjectSTL(rSort));
}
C4Value &C4ValueList::GetItem(int32_t iElem)
{
if(iElem < -iSize)
throw new C4AulExecError(NULL,"invalid subscript");
else if(iElem < 0)
iElem = iSize + iElem;
else if(iElem >= iSize && iElem < MaxSize) this->SetSize(iElem + 1);
// out-of-memory? This might not be catched, but it's better than a segfault
if(iElem >= iSize)
throw new C4AulExecError(NULL,"out of memory");
// return
return pData[iElem];
}
void C4ValueList::SetItem(int32_t iElemNr, C4Value iValue)
{
// enlarge
if(iElemNr < 0) iElemNr = 0;
if(iElemNr >= iSize && iElemNr < MaxSize) this->SetSize(iElemNr + 1);
// out-of-memory? This might not be catched, but it's better than a segfault
if(iElemNr >= iSize)
throw new C4AulExecError(NULL,"out of memory");
// set
pData[iElemNr]=iValue;
}
void C4ValueList::SetSize(int32_t inSize)
{
// array made smaller? Well, just ignore the additional allocated mem then
if(inSize<=iSize)
{
// free values in undefined area
for(int i=inSize;i<iSize;i++) pData[i].Set0();
iSize=inSize;
return;
}
// bounds check
if (inSize > MaxSize) return;
// create new array (initialises)
C4Value* pnData = new C4Value [inSize];
if (!pnData) return;
// move existing values
int32_t i;
for(i=0;i<iSize;i++)
pData[i].Move(&pnData[i]);
// replace
delete[] pData;
pData = pnData;
iSize = inSize;
}
bool C4ValueList::operator==(const C4ValueList& IntList2) const
{
for(int32_t i=0;i<Max(iSize, IntList2.GetSize());i++)
if(GetItem(i) != IntList2.GetItem(i))
return false;
return true;
}
void C4ValueList::Reset()
{
delete[] pData; pData = NULL;
iSize = 0;
}
void C4ValueList::DenumeratePointers()
{
for(int32_t i = 0; i < iSize; i++)
pData[i].DenumeratePointer();
}
void C4ValueList::CompileFunc(class StdCompiler *pComp)
{
int32_t inSize = iSize;
// Size. Reset if not found.
try
{ pComp->Value(inSize); }
catch(StdCompiler::NotFoundException *pExc)
{ Reset(); delete pExc; return; }
// Seperator
if(!pComp->Seperator(StdCompiler::SEP_SEP2))
{
assert(pComp->isCompiler());
// No ';'-seperator? So it's a really old value list format, or empty
pComp->Seperator(StdCompiler::SEP_SEP);
this->SetSize(C4MaxVariable);
// First variable was misinterpreted as size
pData[0].SetInt(inSize);
// Read remaining data
pComp->Value(mkArrayAdapt(pData + 1, C4MaxVariable - 1, C4Value()));
}
else
{
// Allocate
if(pComp->isCompiler()) this->SetSize(inSize);
// Values
pComp->Value(mkArrayAdapt(pData, iSize, C4Value()));
}
}
C4ValueArray::C4ValueArray()
: C4ValueList(), iRefCnt(0), iElementReferences(0)
{
}
C4ValueArray::C4ValueArray(int32_t inSize)
: C4ValueList(inSize), iRefCnt(0), iElementReferences(0)
{
}
C4ValueArray::C4ValueArray(const C4ValueArray &Array2)
: C4ValueList(Array2), iRefCnt(1), iElementReferences(0)
{
}
C4ValueArray::~C4ValueArray()
{
}
enum { C4VALUEARRAY_DEBUG = 0 };
C4ValueArray * C4ValueArray::IncElementRef()
{
if (iRefCnt > 1)
{
C4ValueArray * pNew = new C4ValueArray(*this);
pNew->iElementReferences = 1;
if (C4VALUEARRAY_DEBUG) printf("%p IncElementRef at %d, %d - Copying %p\n", this, iRefCnt, iElementReferences, pNew);
--iRefCnt;
return pNew;
}
else
{
if (C4VALUEARRAY_DEBUG) printf("%p IncElementRef at %d, %d\n", this, iRefCnt, iElementReferences);
++iElementReferences;
return this;
}
}
void C4ValueArray::DecElementRef()
{
if (C4VALUEARRAY_DEBUG) printf("%p DecElementRef at %d, %d\n", this, iRefCnt, iElementReferences);
assert(iElementReferences > 0);
--iElementReferences;
}
C4ValueArray * C4ValueArray::IncRef()
{
if (iRefCnt >= 1 && iElementReferences)
{
C4ValueArray * pNew = new C4ValueArray(*this);
if (C4VALUEARRAY_DEBUG) printf("%p IncRef from %d, %d - Copying %p\n", this, iRefCnt, iElementReferences, pNew);
return pNew;
}
if (C4VALUEARRAY_DEBUG) printf("%p IncRef from %d, %d\n", this, iRefCnt, iElementReferences);
iRefCnt++;
return this;
}
C4ValueArray * C4ValueArray::SetLength(int32_t size)
{
if (iRefCnt > 1)
{
C4ValueArray * pNew = (new C4ValueArray(size))->IncRef();
for(int32_t i = 0; i < size; i++)
pNew->pData[i].Set(pData[i]);
if (C4VALUEARRAY_DEBUG) printf("%p SetLength at %d, %d - Copying %p\n", this, iRefCnt, iElementReferences, pNew);
--iRefCnt;
return pNew;
}
else
{
if (C4VALUEARRAY_DEBUG) printf("%p SetLength at %d, %d\n", this, iRefCnt, iElementReferences);
SetSize(size);
return this;
}
}
void C4ValueArray::DecRef()
{
if (C4VALUEARRAY_DEBUG) printf("%p DecRef from %d, %d%s\n", this, iRefCnt, iElementReferences, iRefCnt == 1 ? " - Deleting" : "");
assert(iRefCnt);
if(!--iRefCnt)
{
delete this;
}
}