From 5b3e08327a4b94c6265303163759b6c80a6370ea Mon Sep 17 00:00:00 2001 From: Markus Mittendrein Date: Sun, 8 Dec 2024 17:39:45 +0100 Subject: [PATCH] Modernize C4FindObject and C4SortObject with vector and unique_ptr --- src/C4FindObject.cpp | 278 ++++++++++++++++++------------------------- src/C4FindObject.h | 104 ++++++++-------- src/C4Script.cpp | 80 +++++-------- 3 files changed, 195 insertions(+), 267 deletions(-) diff --git a/src/C4FindObject.cpp b/src/C4FindObject.cpp index 1d06527c9..32bbe7cea 100644 --- a/src/C4FindObject.cpp +++ b/src/C4FindObject.cpp @@ -26,15 +26,11 @@ #include #include #include +#include // *** C4FindObject -C4FindObject::~C4FindObject() -{ - delete pSort; -} - -C4FindObject *C4FindObject::CreateByValue(const C4Value &DataVal, C4SortObject **ppSortObj) +std::unique_ptr C4FindObject::CreateByValue(const C4Value &DataVal, std::vector>* sorts) { // Must be an array C4ValueArray *pArray = C4Value(DataVal).getArray(); @@ -46,9 +42,13 @@ C4FindObject *C4FindObject::CreateByValue(const C4Value &DataVal, C4SortObject * { // this is not a FindObject but a sort condition! // sort condition not desired here? - if (!ppSortObj) return nullptr; - // otherwise, create it! - *ppSortObj = C4SortObject::CreateByValue(iType, Data); + if (!sorts) return nullptr; + + auto sort = C4SortObject::CreateByValue(iType, Data); + if (sort) + { + sorts->emplace_back(std::move(sort)); + } // done return nullptr; } @@ -58,10 +58,10 @@ C4FindObject *C4FindObject::CreateByValue(const C4Value &DataVal, C4SortObject * case C4FO_Not: { // Create child condition - C4FindObject *pCond = C4FindObject::CreateByValue(Data[1]); - if (!pCond) return nullptr; + auto cond = C4FindObject::CreateByValue(Data[1]); + if (!cond) return nullptr; // wrap - return new C4FindObjectNot(pCond); + return std::make_unique(std::move(cond)); } case C4FO_And: case C4FO_Or: @@ -69,56 +69,59 @@ C4FindObject *C4FindObject::CreateByValue(const C4Value &DataVal, C4SortObject * // Trivial case (one condition) if (Data.GetSize() == 2) return C4FindObject::CreateByValue(Data[1]); + // Create all childs - C4FindObject **ppConds = new C4FindObject *[Data.GetSize() - 1]; + std::vector> conds; + conds.reserve(Data.GetSize() - 1); for (int32_t i = 0; i < Data.GetSize() - 1; i++) - ppConds[i] = C4FindObject::CreateByValue(Data[i + 1]); - // Count real entries, move them to start of list - int32_t iSize = 0; - for (int32_t i = 0; i < Data.GetSize() - 1; i++) - if (ppConds[i]) - if (iSize++ != i) - ppConds[iSize - 1] = ppConds[i]; + { + auto cond = C4FindObject::CreateByValue(Data[i + 1]); + if (cond) + { + conds.emplace_back(std::move(cond)); + } + } + // Create if (iType == C4FO_And) - return new C4FindObjectAnd(iSize, ppConds); + return std::make_unique(std::move(conds)); else - return new C4FindObjectOr(iSize, ppConds); + return std::make_unique(std::move(conds)); } case C4FO_Exclude: - return new C4FindObjectExclude(Data[1].getObj()); + return std::make_unique(Data[1].getObj()); case C4FO_ID: - return new C4FindObjectID(Data[1].getC4ID()); + return std::make_unique(Data[1].getC4ID()); case C4FO_InRect: - return new C4FindObjectInRect(C4Rect(Data[1].getInt(), Data[2].getInt(), Data[3].getInt(), Data[4].getInt())); + return std::make_unique(C4Rect(Data[1].getInt(), Data[2].getInt(), Data[3].getInt(), Data[4].getInt())); case C4FO_AtPoint: - return new C4FindObjectAtPoint(Data[1].getInt(), Data[2].getInt()); + return std::make_unique(Data[1].getInt(), Data[2].getInt()); case C4FO_AtRect: - return new C4FindObjectAtRect(Data[1].getInt(), Data[2].getInt(), Data[3].getInt(), Data[4].getInt()); + return std::make_unique(Data[1].getInt(), Data[2].getInt(), Data[3].getInt(), Data[4].getInt()); case C4FO_OnLine: - return new C4FindObjectOnLine(Data[1].getInt(), Data[2].getInt(), Data[3].getInt(), Data[4].getInt()); + return std::make_unique(Data[1].getInt(), Data[2].getInt(), Data[3].getInt(), Data[4].getInt()); case C4FO_Distance: - return new C4FindObjectDistance(Data[1].getInt(), Data[2].getInt(), Data[3].getInt()); + return std::make_unique(Data[1].getInt(), Data[2].getInt(), Data[3].getInt()); case C4FO_OCF: - return new C4FindObjectOCF(Data[1].getInt()); + return std::make_unique(Data[1].getInt()); case C4FO_Category: - return new C4FindObjectCategory(Data[1].getInt()); + return std::make_unique(Data[1].getInt()); case C4FO_Action: { C4String *pStr = Data[1].getStr(); if (!pStr) return nullptr; // Don't copy, it should be safe - return new C4FindObjectAction(pStr->Data.getData()); + return std::make_unique(pStr->Data.getData()); } case C4FO_Func: @@ -127,7 +130,7 @@ C4FindObject *C4FindObject::CreateByValue(const C4Value &DataVal, C4SortObject * C4String *pStr = Data[1].getStr(); if (!pStr) return nullptr; // Construct - C4FindObjectFunc *pFO = new C4FindObjectFunc(pStr->Data.getData()); + auto pFO = std::make_unique(pStr->Data.getData()); // Add parameters for (int i = 2; i < Data.GetSize(); i++) pFO->SetPar(i - 2, Data[i]); @@ -140,23 +143,23 @@ C4FindObject *C4FindObject::CreateByValue(const C4Value &DataVal, C4SortObject * int32_t index = 0; if (Data.GetSize() >= 3) index = static_cast(BoundBy(Data[2].getInt(), 0, 1)); - return new C4FindObjectActionTarget(Data[1].getObj(), index); + return std::make_unique(Data[1].getObj(), index); } case C4FO_Container: - return new C4FindObjectContainer(Data[1].getObj()); + return std::make_unique(Data[1].getObj()); case C4FO_AnyContainer: - return new C4FindObjectAnyContainer(); + return std::make_unique(); case C4FO_Owner: - return new C4FindObjectOwner(Data[1].getInt()); + return std::make_unique(Data[1].getInt()); case C4FO_Controller: - return new C4FindObjectController(Data[1].getInt()); + return std::make_unique(Data[1].getInt()); case C4FO_Layer: - return new C4FindObjectLayer(Data[1].getObj()); + return std::make_unique(Data[1].getObj()); } return nullptr; } @@ -374,49 +377,35 @@ void C4FindObject::CheckObjectStatusAfterSort(std::vector &objects) std::ranges::replace_if(objects, [](C4Object *const obj) { return !obj->Status; }, nullptr); } -void C4FindObject::SetSort(C4SortObject *pToSort) +void C4FindObject::SetSort(std::unique_ptr pToSort) { - delete pSort; - pSort = pToSort; + pSort = std::move(pToSort); } // *** C4FindObjectNot -C4FindObjectNot::~C4FindObjectNot() -{ - delete pCond; -} - -bool C4FindObjectNot::Check(C4Object *pObj) +bool C4FindObjectNot::Check(C4Object *obj) { - return !pCond->Check(pObj); + return !cond->Check(obj); } // *** C4FindObjectAnd -C4FindObjectAnd::C4FindObjectAnd(int32_t inCnt, C4FindObject **ppConds, bool fFreeArray) - : iCnt(inCnt), ppConds(ppConds), fHasBounds(false), fUseShapes(false), fFreeArray(fFreeArray) +C4FindObjectAnd::C4FindObjectAnd(std::vector>&& conds) + : conds(std::move(conds)), fHasBounds(false), fUseShapes(false) { // Filter ensured entries - for (int32_t i = 0; i < iCnt;) - if (ppConds[i]->IsEnsured()) - { - delete ppConds[i]; - iCnt--; - for (int32_t j = i; j < iCnt; j++) - ppConds[j] = ppConds[j + 1]; - } - else - i++; + std::erase_if(conds, [](const std::unique_ptr& cond) { return cond->IsEnsured(); }); + // Intersect all child bounds - for (int32_t i = 0; i < iCnt; i++) + for (const auto& cond : conds) { - C4Rect *pChildBounds = ppConds[i]->GetBounds(); + C4Rect *pChildBounds = cond->GetBounds(); if (pChildBounds) { // some objects might be in an rect and at a point not in that rect // so do not intersect an atpoint bound with an rect bound - fUseShapes = ppConds[i]->UseShapes(); + fUseShapes = cond->UseShapes(); if (fUseShapes) { Bounds = *pChildBounds; @@ -434,57 +423,41 @@ C4FindObjectAnd::C4FindObjectAnd(int32_t inCnt, C4FindObject **ppConds, bool fFr } } -C4FindObjectAnd::~C4FindObjectAnd() -{ - for (int32_t i = 0; i < iCnt; i++) - delete ppConds[i]; - if (fFreeArray) - delete[] ppConds; -} - -bool C4FindObjectAnd::Check(C4Object *pObj) +bool C4FindObjectAnd::Check(C4Object *obj) { - for (int32_t i = 0; i < iCnt; i++) - if (!ppConds[i]->Check(pObj)) - return false; - return true; + return std::ranges::all_of(conds, [obj](const std::unique_ptr& cond){ return cond->Check(obj); }); } bool C4FindObjectAnd::IsImpossible() { - for (int32_t i = 0; i < iCnt; i++) - if (ppConds[i]->IsImpossible()) - return true; - return false; + return std::ranges::any_of(conds, [](const std::unique_ptr& cond) { return cond->IsImpossible(); }); } // *** C4FindObjectOr -C4FindObjectOr::C4FindObjectOr(int32_t inCnt, C4FindObject **ppConds) - : iCnt(inCnt), ppConds(ppConds), fHasBounds(false) +C4FindObjectOr::C4FindObjectOr(std::vector>&& conds) + : conds(std::move(conds)), fHasBounds(false) { // Filter impossible entries - for (int32_t i = 0; i < iCnt;) - if (ppConds[i]->IsImpossible()) - { - delete ppConds[i]; - iCnt--; - for (int32_t j = i; j < iCnt; j++) - ppConds[j] = ppConds[j + 1]; - } - else - i++; + std::erase_if(conds, [](const std::unique_ptr& cond) { return cond->IsImpossible(); }); + // Sum up all child bounds - for (int32_t i = 0; i < iCnt; i++) + for (const auto& cond : conds) { - C4Rect *pChildBounds = ppConds[i]->GetBounds(); - if (!pChildBounds) { fHasBounds = false; break; } + C4Rect *pChildBounds = cond->GetBounds(); + if (!pChildBounds) + { + fHasBounds = false; + break; + } + // Do not optimize atpoint: It could lead to having to search multiple // sectors. An object's shape can be in multiple sectors. We do not want // to find the same object twice. - if (ppConds[i]->UseShapes()) + if (cond->UseShapes()) { - fHasBounds = false; break; + fHasBounds = false; + break; } if (fHasBounds) Bounds.Add(*pChildBounds); @@ -496,27 +469,14 @@ C4FindObjectOr::C4FindObjectOr(int32_t inCnt, C4FindObject **ppConds) } } -C4FindObjectOr::~C4FindObjectOr() -{ - for (int32_t i = 0; i < iCnt; i++) - delete ppConds[i]; - delete[] ppConds; -} - -bool C4FindObjectOr::Check(C4Object *pObj) +bool C4FindObjectOr::Check(C4Object *obj) { - for (int32_t i = 0; i < iCnt; i++) - if (ppConds[i]->Check(pObj)) - return true; - return false; + return std::ranges::any_of(conds, [obj](const std::unique_ptr& cond){ return cond->Check(obj); }); } bool C4FindObjectOr::IsEnsured() { - for (int32_t i = 0; i < iCnt; i++) - if (ppConds[i]->IsEnsured()) - return true; - return false; + return std::ranges::any_of(conds, [](const std::unique_ptr& cond) { return cond->IsEnsured(); }); } // *** C4FindObject* (primitive conditions) @@ -680,7 +640,7 @@ bool C4FindObjectLayer::IsImpossible() // *** C4SortObject -C4SortObject *C4SortObject::CreateByValue(const C4Value &DataVal) +std::unique_ptr C4SortObject::CreateByValue(const C4Value &DataVal) { // Must be an array const C4ValueArray *pArray = C4Value(DataVal).getArray(); @@ -689,17 +649,17 @@ C4SortObject *C4SortObject::CreateByValue(const C4Value &DataVal) return CreateByValue(Data[0].getInt(), Data); } -C4SortObject *C4SortObject::CreateByValue(C4ValueInt iType, const C4ValueArray &Data) +std::unique_ptr C4SortObject::CreateByValue(C4ValueInt iType, const C4ValueArray &Data) { switch (iType) { case C4SO_Reverse: { // create child sort - C4SortObject *pChildSort = C4SortObject::CreateByValue(Data[1]); - if (!pChildSort) return nullptr; + auto childSort = C4SortObject::CreateByValue(Data[1]); + if (!childSort) return nullptr; // wrap - return new C4SortObjectReverse(pChildSort); + return std::make_unique(std::move(childSort)); } case C4SO_Multiple: @@ -710,35 +670,34 @@ C4SortObject *C4SortObject::CreateByValue(C4ValueInt iType, const C4ValueArray & return C4SortObject::CreateByValue(Data[1]); } // Create all children - C4SortObject **ppSorts = new C4SortObject *[Data.GetSize() - 1]; + std::vector> sorts; + sorts.reserve(Data.GetSize() - 1); for (int32_t i = 0; i < Data.GetSize() - 1; i++) { - ppSorts[i] = C4SortObject::CreateByValue(Data[i + 1]); + auto sort = C4SortObject::CreateByValue(Data[i + 1]); + if (sort) + { + sorts.emplace_back(std::move(sort)); + } } - // Count real entries, move them to start of list - int32_t iSize = 0; - for (int32_t i = 0; i < Data.GetSize() - 1; i++) - if (ppSorts[i]) - if (iSize++ != i) - ppSorts[iSize - 1] = ppSorts[i]; // Create - return new C4SortObjectMultiple(iSize, ppSorts); + return std::make_unique(std::move(sorts)); } case C4SO_Distance: - return new C4SortObjectDistance(Data[1].getInt(), Data[2].getInt()); + return std::make_unique(Data[1].getInt(), Data[2].getInt()); case C4SO_Random: - return new C4SortObjectRandom(); + return std::make_unique(); case C4SO_Speed: - return new C4SortObjectSpeed(); + return std::make_unique(); case C4SO_Mass: - return new C4SortObjectMass(); + return std::make_unique(); case C4SO_Value: - return new C4SortObjectValue(); + return std::make_unique(); case C4SO_Func: { @@ -746,12 +705,12 @@ C4SortObject *C4SortObject::CreateByValue(C4ValueInt iType, const C4ValueArray & C4String *pStr = Data[1].getStr(); if (!pStr) return nullptr; // Construct - C4SortObjectFunc *pSO = new C4SortObjectFunc(pStr->Data.getData()); + auto sort = std::make_unique(pStr->Data.getData()); // Add parameters for (int i = 2; i < Data.GetSize(); i++) - pSO->SetPar(i - 2, Data[i]); + sort->SetPar(i - 2, Data[i]); // Done - return pSO; + return sort; } } return nullptr; @@ -848,39 +807,32 @@ int32_t C4SortObjectByValue::CompareCache(int32_t iObj1, int32_t iObj2, C4Object return values[iObj2] - values[iObj1]; } -C4SortObjectReverse::~C4SortObjectReverse() -{ - delete pSort; -} - int32_t C4SortObjectReverse::Compare(C4Object *pObj1, C4Object *pObj2) { - return pSort->Compare(pObj2, pObj1); + return sort->Compare(pObj2, pObj1); } bool C4SortObjectReverse::PrepareCache(std::vector &objects) { - return pSort->PrepareCache(objects); + return sort->PrepareCache(objects); } int32_t C4SortObjectReverse::CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) { - return pSort->CompareCache(iObj2, iObj1, pObj2, pObj1); -} - -C4SortObjectMultiple::~C4SortObjectMultiple() -{ - for (int32_t i = 0; i < iCnt; ++i) delete ppSorts[i]; - if (fFreeArray) delete[] ppSorts; + return sort->CompareCache(iObj2, iObj1, pObj2, pObj1); } int32_t C4SortObjectMultiple::Compare(C4Object *pObj1, C4Object *pObj2) { // return first comparison that's nonzero - int32_t iCmp; - for (int32_t i = 0; i < iCnt; ++i) - if (iCmp = ppSorts[i]->Compare(pObj1, pObj2)) - return iCmp; + for (const auto& sort : sorts) + { + const auto result = sort->Compare(pObj1, pObj2); + if (result != 0) + { + return result; + } + } // all comparisons equal return 0; } @@ -888,8 +840,10 @@ int32_t C4SortObjectMultiple::Compare(C4Object *pObj1, C4Object *pObj2) bool C4SortObjectMultiple::PrepareCache(std::vector &objects) { bool fCaches = false; - for (int32_t i = 0; i < iCnt; ++i) - fCaches |= ppSorts[i]->PrepareCache(objects); + for (const auto& sort : sorts) + { + fCaches |= sort->PrepareCache(objects); + } // return wether a sort citerion uses a cache return fCaches; } @@ -897,10 +851,14 @@ bool C4SortObjectMultiple::PrepareCache(std::vector &objects) int32_t C4SortObjectMultiple::CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) { // return first comparison that's nonzero - int32_t iCmp; - for (int32_t i = 0; i < iCnt; ++i) - if (iCmp = ppSorts[i]->CompareCache(iObj1, iObj2, pObj1, pObj2)) - return iCmp; + for (const auto& sort : sorts) + { + const auto result = sort->CompareCache(iObj1, iObj2, pObj1, pObj2); + if (result != 0) + { + return result; + } + } // all comparisons equal return 0; } diff --git a/src/C4FindObject.h b/src/C4FindObject.h index 5799d33cf..7aa731643 100644 --- a/src/C4FindObject.h +++ b/src/C4FindObject.h @@ -16,9 +16,10 @@ #pragma once +#include + #include "C4Id.h" #include "C4Sector.h" -#include "C4Shape.h" #include "C4Value.h" #include "C4Aul.h" @@ -62,6 +63,26 @@ enum C4SortObjectCondID C4SO_Last = 200, // no sort condition larger than this }; +// result sorting +class C4SortObject +{ +public: + virtual ~C4SortObject() = default; + +public: + // Overridables + virtual int32_t Compare(C4Object *pObj1, C4Object *pObj2) = 0; // return value <0 if obj1 is to be sorted before obj2 + + virtual bool PrepareCache([[maybe_unused]] std::vector &objects) { return false; } + virtual int32_t CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) { return Compare(pObj1, pObj2); } + +public: + static std::unique_ptr CreateByValue(const C4Value &Data); + static std::unique_ptr CreateByValue(C4ValueInt iType, const C4ValueArray &Data); + + void SortObjects(std::vector &result); +}; + // Base class class C4FindObject { @@ -69,13 +90,12 @@ class C4FindObject friend class C4FindObjectAnd; friend class C4FindObjectOr; - class C4SortObject *pSort; + std::unique_ptr pSort; public: - C4FindObject() : pSort(nullptr) {} - virtual ~C4FindObject(); + virtual ~C4FindObject() = default; - static C4FindObject *CreateByValue(const C4Value &Data, C4SortObject **ppSortObj = nullptr); // createFindObject or SortObject - if ppSortObj==nullptr, SortObject is not allowed + static std::unique_ptr CreateByValue(const C4Value &Data, std::vector> *sorts = nullptr); // createFindObject or SortObject - if sorts==nullptr, SortObject is not allowed int32_t Count(const C4ObjectList &Objs); // Counts objects for which the condition is true C4Object *Find(const C4ObjectList &Objs); // Returns first object for which the condition is true @@ -85,7 +105,7 @@ class C4FindObject C4Object *Find(const C4ObjectList &Objs, const C4LSectors &Sct); // Returns first object for which the condition is true C4ValueArray *FindMany(const C4ObjectList &Objs, const C4LSectors &Sct); // Returns all objects for which the condition is true - void SetSort(C4SortObject *pToSort); + void SetSort(std::unique_ptr pToSort); protected: // Overridables @@ -104,54 +124,50 @@ class C4FindObject class C4FindObjectNot : public C4FindObject { public: - C4FindObjectNot(C4FindObject *pCond) - : pCond(pCond) {} - virtual ~C4FindObjectNot(); + C4FindObjectNot(std::unique_ptr cond) + : cond{std::move(cond)} {} private: - C4FindObject *pCond; + std::unique_ptr cond; protected: - virtual bool Check(C4Object *pObj) override; - virtual bool IsImpossible() override { return pCond->IsEnsured(); } - virtual bool IsEnsured() override { return pCond->IsImpossible(); } + virtual bool Check(C4Object *obj) override; + virtual bool IsImpossible() override { return cond->IsEnsured(); } + virtual bool IsEnsured() override { return cond->IsImpossible(); } }; class C4FindObjectAnd : public C4FindObject { public: - C4FindObjectAnd(int32_t iCnt, C4FindObject **ppConds, bool fFreeArray = true); - virtual ~C4FindObjectAnd(); + C4FindObjectAnd(std::vector>&& conds); private: - int32_t iCnt; - C4FindObject **ppConds; bool fFreeArray; bool fUseShapes; + std::vector> conds; + bool fUseShapes; C4Rect Bounds; bool fHasBounds; protected: - virtual bool Check(C4Object *pObj) override; + virtual bool Check(C4Object *obj) override; virtual C4Rect *GetBounds() override { return fHasBounds ? &Bounds : nullptr; } virtual bool UseShapes() override { return fUseShapes; } - virtual bool IsEnsured() override { return !iCnt; } + virtual bool IsEnsured() override { return conds.empty(); } virtual bool IsImpossible() override; }; class C4FindObjectOr : public C4FindObject { public: - C4FindObjectOr(int32_t iCnt, C4FindObject **ppConds); - virtual ~C4FindObjectOr(); + C4FindObjectOr(std::vector>&& conds); private: - int32_t iCnt; - C4FindObject **ppConds; + std::vector> conds; C4Rect Bounds; bool fHasBounds; protected: - virtual bool Check(C4Object *pObj) override; + virtual bool Check(C4Object *obj) override; virtual C4Rect *GetBounds() override { return fHasBounds ? &Bounds : nullptr; } virtual bool IsEnsured() override; - virtual bool IsImpossible() override { return !iCnt; } + virtual bool IsImpossible() override { return conds.empty(); } }; // Primitive conditions @@ -394,32 +410,10 @@ class C4FindObjectController : public C4FindObject virtual bool IsImpossible() override; }; -// result sorting -class C4SortObject -{ -public: - C4SortObject() {} - virtual ~C4SortObject() {} - -public: - // Overridables - virtual int32_t Compare(C4Object *pObj1, C4Object *pObj2) = 0; // return value <0 if obj1 is to be sorted before obj2 - - virtual bool PrepareCache([[maybe_unused]] std::vector &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(std::vector &result); -}; - class C4SortObjectByValue : public C4SortObject { public: C4SortObjectByValue(); - ~C4SortObjectByValue() override = default; private: std::vector values; @@ -436,12 +430,11 @@ class C4SortObjectByValue : public C4SortObject class C4SortObjectReverse : public C4SortObject // reverse sort { public: - C4SortObjectReverse(C4SortObject *pSort) - : C4SortObject(), pSort(pSort) {} - virtual ~C4SortObjectReverse(); + C4SortObjectReverse(std::unique_ptr sort) + : sort{std::move(sort)} {} private: - C4SortObject *pSort; + std::unique_ptr sort; protected: int32_t Compare(C4Object *pObj1, C4Object *pObj2) override; @@ -453,14 +446,11 @@ class C4SortObjectReverse : public C4SortObject // reverse sort class C4SortObjectMultiple : public C4SortObject // apply next sort if previous compares to equality { public: - C4SortObjectMultiple(int32_t iCnt, C4SortObject **ppSorts, bool fFreeArray = true) - : C4SortObject(), iCnt(iCnt), ppSorts(ppSorts), fFreeArray(fFreeArray) {} - virtual ~C4SortObjectMultiple(); + C4SortObjectMultiple(std::vector>&& sorts) + : C4SortObject(), sorts(std::move(sorts)) {} private: - bool fFreeArray; - int32_t iCnt; - C4SortObject **ppSorts; + std::vector> sorts; protected: int32_t Compare(C4Object *pObj1, C4Object *pObj2) override; diff --git a/src/C4Script.cpp b/src/C4Script.cpp index 934a26807..13b75ef2d 100644 --- a/src/C4Script.cpp +++ b/src/C4Script.cpp @@ -19,6 +19,7 @@ /* Functions mapped by C4Script */ +#include "C4FindObject.h" #include #include #include @@ -40,6 +41,7 @@ #include #include +#include #include #include #include @@ -1779,87 +1781,65 @@ static C4Object *FnFindBase(C4ValueInt iOwner, C4ValueInt iIndex) return Game.FindBase(iOwner, iIndex); } -std::unique_ptr CreateCriterionsFromPars(const std::string_view forFunction, C4Object *const contextObj, const std::span pPars, C4FindObject **pFOs, C4SortObject **pSOs) +std::unique_ptr CreateCriterionsFromPars(const std::string_view forFunction, C4Object *const contextObj, const std::span pPars, bool acceptSort = false) { - int i, iCnt = 0, iSortCnt = 0; + std::vector> conds; + std::vector> sorts; + // Read all parameters - for (i = 0; i < C4AUL_MAX_Par; i++) + for (int i = 0; i < C4AUL_MAX_Par; i++) { const C4Value &Data = pPars[i].GetRefVal(); // No data given? if (!Data) break; // Construct - C4SortObject *pSO = nullptr; - C4FindObject *pFO = C4FindObject::CreateByValue(Data, pSOs ? &pSO : nullptr); - // Add FindObject - if (pFO) - { - pFOs[iCnt++] = pFO; - } - // Add SortObject - if (pSO) + auto cond = C4FindObject::CreateByValue(Data, acceptSort ? &sorts : nullptr); + if (cond) { - pSOs[iSortCnt++] = pSO; + conds.emplace_back(std::move(cond)); } } // No criterions? - if (!iCnt) + if (conds.empty()) { - for (i = 0; i < iSortCnt; ++i) delete pSOs[i]; throw C4AulExecError{contextObj, std::format("{}: No valid search criterions supplied!", forFunction)}; } + // Create search object + std::unique_ptr pFO; + if (conds.size() == 1) + pFO = std::move(conds.front()); + else + pFO = std::make_unique(std::move(conds)); + + // create sort criterion - C4SortObject *pSO = nullptr; - if (iSortCnt) + if (acceptSort && !sorts.empty()) { - if (iSortCnt == 1) - pSO = pSOs[0]; + if (sorts.size() == 1) + pFO->SetSort(std::move(sorts.front())); else - pSO = new C4SortObjectMultiple(iSortCnt, pSOs, false); + pFO->SetSort(std::make_unique(std::move(sorts))); } - // Create search object - std::unique_ptr pFO; - if (iCnt == 1) - pFO.reset(pFOs[0]); - else - pFO = std::make_unique(iCnt, pFOs, false); - if (pSO) pFO->SetSort(pSO); + return pFO; } static C4Value FnObjectCount2(C4AulContext *cthr, std::span pPars) { - // Create FindObject-structure - C4FindObject *pFOs[C4AUL_MAX_Par]; - const auto pFO = CreateCriterionsFromPars("ObjectCount", cthr->Obj, pPars, pFOs, nullptr); - // Search - int32_t iCnt = pFO->Count(Game.Objects, Game.Objects.Sectors); - // Return - return C4VInt(iCnt); + const auto pFO = CreateCriterionsFromPars("ObjectCount2", cthr->Obj, pPars); + return C4VInt(pFO->Count(Game.Objects, Game.Objects.Sectors)); } static C4Value FnFindObject2(C4AulContext *cthr, std::span pPars) { - // Create FindObject-structure - C4FindObject *pFOs[C4AUL_MAX_Par]; - C4SortObject *pSOs[C4AUL_MAX_Par]; - const auto pFO = CreateCriterionsFromPars("FindObject2", cthr->Obj, pPars, pFOs, pSOs); - // Search - C4Object *pObj = pFO->Find(Game.Objects, Game.Objects.Sectors); - // Return - return C4VObj(pObj); + const auto pFO = CreateCriterionsFromPars("FindObject2", cthr->Obj, pPars, true); + return C4VObj(pFO->Find(Game.Objects, Game.Objects.Sectors)); } static C4Value FnFindObjects(C4AulContext *cthr, std::span pPars) { - // Create FindObject-structure - C4FindObject *pFOs[C4AUL_MAX_Par]; - C4SortObject *pSOs[C4AUL_MAX_Par]; - const auto pFO = CreateCriterionsFromPars("FindObjects", cthr->Obj, pPars, pFOs, pSOs); - // Search - C4ValueArray *pResult = pFO->FindMany(Game.Objects, Game.Objects.Sectors); - // Return - return C4VArray(pResult); + const auto pFO = CreateCriterionsFromPars("FindObjects", cthr->Obj, pPars, true); + return C4VArray(pFO->FindMany(Game.Objects, Game.Objects.Sectors)); } static C4ValueInt FnObjectCount(C4AulContext *cthr, C4ID id, C4ValueInt x, C4ValueInt y, C4ValueInt wdt, C4ValueInt hgt, C4ValueInt dwOCF, C4String *szAction, C4Object *pActionTarget, C4Value vContainer, C4ValueInt iOwner)