Skip to content

Commit

Permalink
Use std::vector in C4FindObject and refactor C4ValueList to use std::…
Browse files Browse the repository at this point in the history
…vector internally
  • Loading branch information
Fulgen301 committed Nov 11, 2023
1 parent fab2cc5 commit b456647
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 176 deletions.
136 changes: 53 additions & 83 deletions src/C4FindObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <C4Random.h>

#include <algorithm>
#include <numeric>

// *** C4FindObject

Expand Down Expand Up @@ -203,26 +204,21 @@ C4ValueArray *C4FindObject::FindMany(const C4ObjectList &Objs)
if (IsImpossible())
return new C4ValueArray();
// Set up array
C4ValueArray *pArray = new C4ValueArray(32);
std::vector<C4Object *> result;

int32_t iSize = 0;
// Search
for (C4ObjectLink *pLnk = Objs.First; pLnk; pLnk = pLnk->Next)
if (pLnk->Obj->Status)
if (Check(pLnk->Obj))
{
// Grow the array, if neccessary
if (iSize >= pArray->GetSize())
pArray->SetSize(iSize * 2);
// Add object
(*pArray)[iSize++] = C4VObj(pLnk->Obj);
result.push_back(pLnk->Obj);
}
// Shrink array
pArray->SetSize(iSize);
// Recheck object status (may shrink array again)
CheckObjectStatus(pArray);
CheckObjectStatus(result);
// Apply sorting
if (pSort) pSort->SortObjects(pArray);
return pArray;
if (pSort) pSort->SortObjects(result);
return new C4ValueArray{std::span{result}};
}

int32_t C4FindObject::Count(const C4ObjectList &Objs, const C4LSectors &Sct)
Expand Down Expand Up @@ -315,8 +311,8 @@ C4ValueArray *C4FindObject::FindMany(const C4ObjectList &Objs, const C4LSectors
C4Rect *pBounds = GetBounds();
if (!pBounds)
return FindMany(Objs);
// Prepare for array that may be generated
C4ValueArray *pArray; int32_t iSize;

std::vector<C4Object *> result;
// Check shape lists?
if (UseShapes())
{
Expand All @@ -327,7 +323,6 @@ C4ValueArray *C4FindObject::FindMany(const C4ObjectList &Objs, const C4LSectors
if (!Area.Next(pSct))
return FindMany(pSct->ObjectShapes);
// Set up array
pArray = new C4ValueArray(32); iSize = 0;
// Create marker, search all areas
uint32_t iMarker = ::Game.Objects.GetNextMarker();
for (; pLst; pLst = Area.NextObjectShapes(pLst, &pSct))
Expand All @@ -338,56 +333,32 @@ C4ValueArray *C4FindObject::FindMany(const C4ObjectList &Objs, const C4LSectors
pLnk->Obj->Marker = iMarker;
if (Check(pLnk->Obj))
{
// Grow the array, if neccessary
if (iSize >= pArray->GetSize())
pArray->SetSize(iSize * 2);
// Add object
(*pArray)[iSize++] = C4VObj(pLnk->Obj);
result.push_back(pLnk->Obj);
}
}
}
else
{
// Set up array
pArray = new C4ValueArray(32); iSize = 0;
// Search
C4LArea Area(&Game.Objects.Sectors, *pBounds); C4LSector *pSct;
for (C4ObjectList *pLst = Area.FirstObjects(&pSct); pLst; pLst = Area.NextObjects(pLst, &pSct))
for (C4ObjectLink *pLnk = pLst->First; pLnk; pLnk = pLnk->Next)
if (pLnk->Obj->Status)
if (Check(pLnk->Obj))
{
// Grow the array, if neccessary
if (iSize >= pArray->GetSize())
pArray->SetSize(iSize * 2);
// Add object
(*pArray)[iSize++] = C4VObj(pLnk->Obj);
result.push_back(pLnk->Obj);
}
}
// Shrink array
pArray->SetSize(iSize);
// Recheck object status (may shrink array again)
CheckObjectStatus(pArray);
CheckObjectStatus(result);
// Apply sorting
if (pSort) pSort->SortObjects(pArray);
return pArray;
if (pSort) pSort->SortObjects(result);
return new C4ValueArray{std::span{result}};
}

void C4FindObject::CheckObjectStatus(C4ValueArray *pArray)
void C4FindObject::CheckObjectStatus(std::vector<C4Object *> &objects)
{
// Recheck object status
for (int32_t i = 0; i < pArray->GetSize(); i++)
if (!pArray->GetItem(i).getObj()->Status)
{
// This shouldn't happen really, so this is done as a separate loop.
int32_t j = i; i++;
for (; i < pArray->GetSize(); i++)
if (pArray->GetItem(i).getObj()->Status)
pArray->GetItem(j++) = pArray->GetItem(i);
// Set new size
pArray->SetSize(j);
break;
}
std::erase_if(objects, [](C4Object *const obj) { return !obj->Status; });
}

void C4FindObject::SetSort(C4SortObject *pToSort)
Expand Down Expand Up @@ -782,65 +753,68 @@ namespace

public:
C4SortObjectSTL(C4SortObject &rSorter) : rSorter(rSorter) {}
bool operator()(const C4Value &v1, const C4Value &v2) { return rSorter.Compare(v1._getObj(), v2._getObj()) > 0; }
bool operator()(C4Object *const v1, C4Object *const v2) { return rSorter.Compare(v1, v2) > 0; }
};

class C4SortObjectSTLCache
{
private:
C4SortObject &rSorter;
C4Value *pVals;
std::vector<C4Object *> &values;

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; }
C4SortObjectSTLCache(C4SortObject &rSorter, std::vector<C4Object *> &values) : rSorter(rSorter), values{values} {}
bool operator()(int32_t n1, int32_t n2) { return rSorter.CompareCache(n1, n2, values[n1], values[n2]) > 0; }
};
}

void C4SortObject::SortObjects(C4ValueArray *pArray)
void C4SortObject::SortObjects(std::vector<C4Object *> &result)
{
if (PrepareCache(pArray))
if (PrepareCache(result))
{
const std::int32_t size{pArray->GetSize()};
auto positions = std::make_unique_for_overwrite<std::intptr_t[]>(result.size());
std::span positionsSpan{positions.get(), result.size()};

// Initialize position array
intptr_t i, *pPos = new intptr_t[size];
for (i = 0; i < size; i++) pPos[i] = i;
std::ranges::iota(positionsSpan, 0);
// Sort
std::stable_sort(pPos, pPos + size, C4SortObjectSTLCache(*this, pArray->pData));
std::ranges::stable_sort(positionsSpan, C4SortObjectSTLCache{*this, result});
// Save actual object pointers in array (hacky).
for (i = 0; i < size; i++)
pPos[i] = reinterpret_cast<intptr_t>(pArray->pData[pPos[i]]._getObj());
for (std::size_t i{0}; i < result.size(); ++i)
{
positions[i] = reinterpret_cast<std::intptr_t>(result[positions[i]]);
}
// Set the values
for (i = 0; i < size; i++)
pArray->pData[i].SetObject(reinterpret_cast<C4Object *>(pPos[i]));
delete[] pPos;
for (std::size_t i{0}; i < result.size(); ++i)
{
result[i] = reinterpret_cast<C4Object *>(positions[i]);
}
}
else
{
// Be sure to use stable sort, as otherweise the algorithm isn't garantueed
// to produce identical results on all platforms!
std::stable_sort(pArray->pData, pArray->pData + pArray->GetSize(), C4SortObjectSTL(*this));
std::ranges::stable_sort(result, C4SortObjectSTL{*this});
}
}

// *** C4SortObjectByValue

C4SortObjectByValue::C4SortObjectByValue()
: C4SortObject(), pVals(nullptr), iSize(0) {}
: C4SortObject() {}

C4SortObjectByValue::~C4SortObjectByValue()
{
delete[] pVals; pVals = nullptr;
}

bool C4SortObjectByValue::PrepareCache(const C4ValueList *pObjs)
bool C4SortObjectByValue::PrepareCache(std::vector<C4Object *> &objects)
{
// Clear old cache
delete[] pVals; pVals = nullptr; iSize = 0;
// Create new cache
iSize = pObjs->GetSize(); pVals = new int32_t[iSize];
for (int32_t i = 0; i < iSize; i++)
pVals[i] = CompareGetValue(pObjs->GetItem(i)._getObj());
// Okay

values.clear();
values.reserve(objects.size());

std::ranges::copy(objects | std::views::transform([this](C4Object *const obj)
{
return CompareGetValue(obj);
}), std::back_inserter(values));

return true;
}

Expand All @@ -858,7 +832,7 @@ int32_t C4SortObjectByValue::CompareCache(int32_t iObj1, int32_t iObj2, C4Object
{
assert(pVals); assert(iObj1 >= 0 && iObj1 < iSize); assert(iObj2 >= 0 && iObj2 < iSize);
// Might overflow for large values...!
return pVals[iObj2] - pVals[iObj1];
return values[iObj2] - values[iObj1];
}

C4SortObjectReverse::~C4SortObjectReverse()
Expand All @@ -871,9 +845,9 @@ int32_t C4SortObjectReverse::Compare(C4Object *pObj1, C4Object *pObj2)
return pSort->Compare(pObj2, pObj1);
}

bool C4SortObjectReverse::PrepareCache(const C4ValueList *pObjs)
bool C4SortObjectReverse::PrepareCache(std::vector<C4Object *> &objects)
{
return pSort->PrepareCache(pObjs);
return pSort->PrepareCache(objects);
}

int32_t C4SortObjectReverse::CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2)
Expand All @@ -898,13 +872,9 @@ int32_t C4SortObjectMultiple::Compare(C4Object *pObj1, C4Object *pObj2)
return 0;
}

bool C4SortObjectMultiple::PrepareCache(const C4ValueList *pObjs)
bool C4SortObjectMultiple::PrepareCache(std::vector<C4Object *> &objects)
{
bool fCaches = false;
for (int32_t i = 0; i < iCnt; ++i)
fCaches |= ppSorts[i]->PrepareCache(pObjs);
// return wether a sort citerion uses a cache
return fCaches;
return std::any_of(ppSorts, ppSorts + iCnt, [&objects](C4SortObject *const sort) { return sort->PrepareCache(objects); });
}

int32_t C4SortObjectMultiple::CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2)
Expand Down
17 changes: 8 additions & 9 deletions src/C4FindObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class C4FindObject
virtual bool IsEnsured() { return false; }

private:
void CheckObjectStatus(C4ValueArray *pArray);
void CheckObjectStatus(std::vector<C4Object *> &objects);
};

// Combinators
Expand Down Expand Up @@ -404,32 +404,31 @@ class C4SortObject
// Overridables
virtual int32_t Compare(C4Object *pObj1, C4Object *pObj2) = 0; // return value <0 if obj1 is to be sorted before obj2

virtual bool PrepareCache(const C4ValueList *pObjs) { return false; }
virtual bool PrepareCache([[maybe_unused]] std::vector<C4Object *> &objects) { return false; }
virtual int32_t CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) { return Compare(pObj1, pObj2); }

public:
static C4SortObject *CreateByValue(const C4Value &Data);
static C4SortObject *CreateByValue(C4ValueInt iType, const C4ValueArray &Data);

void SortObjects(C4ValueArray *pArray);
void SortObjects(std::vector<C4Object *> &result);
};

class C4SortObjectByValue : public C4SortObject
{
public:
C4SortObjectByValue();
virtual ~C4SortObjectByValue();
~C4SortObjectByValue() override = default;

private:
int32_t *pVals;
int32_t iSize;
std::vector<std::int32_t> values;

public:
// Overridables
virtual int32_t Compare(C4Object *pObj1, C4Object *pObj2) override;
virtual int32_t CompareGetValue(C4Object *pOf) = 0;

virtual bool PrepareCache(const C4ValueList *pObjs) override;
virtual bool PrepareCache(std::vector<C4Object *> &objects) override;
virtual int32_t CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) override;
};

Expand All @@ -446,7 +445,7 @@ class C4SortObjectReverse : public C4SortObject // reverse sort
protected:
int32_t Compare(C4Object *pObj1, C4Object *pObj2) override;

virtual bool PrepareCache(const C4ValueList *pObjs) override;
virtual bool PrepareCache(std::vector<C4Object *> &objects) override;
virtual int32_t CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) override;
};

Expand All @@ -465,7 +464,7 @@ class C4SortObjectMultiple : public C4SortObject // apply next sort if previous
protected:
int32_t Compare(C4Object *pObj1, C4Object *pObj2) override;

virtual bool PrepareCache(const C4ValueList *pObjs) override;
virtual bool PrepareCache(std::vector<C4Object *> &objects) override;
virtual int32_t CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) override;
};

Expand Down
Loading

0 comments on commit b456647

Please sign in to comment.