Skip to content

Commit

Permalink
Switch droid groups to using std::list
Browse files Browse the repository at this point in the history
Remove `psGrpNext` from `DROID` class, add
`DroidList` field to the `DROID_GROUP` class instead.

Introduce a utility function `mutating_list_iterate`
in `objmem.h` which is a for-each-style algorithm
to work with `std::list`, which can cope with
invalidation of the current iterator (this can come
handy in cases where we traverse the group list and
remove/add from/to the same group list along the way).

"mutating" word here clearly denotes that this loop may
modify the list, which will be traversed.

Signed-off-by: Pavel Solodovnikov <[email protected]>
  • Loading branch information
ManManson authored and KJeff01 committed Jan 6, 2024
1 parent 57d397b commit 22b0518
Show file tree
Hide file tree
Showing 16 changed files with 180 additions and 168 deletions.
4 changes: 2 additions & 2 deletions src/ai.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ static SDWORD targetAttackWeight(BASE_OBJECT *psTarget, BASE_OBJECT *psAttacker,
{
SDWORD targetTypeBonus = 0, damageRatio = 0, attackWeight = 0, noTarget = -1;
UDWORD weaponSlot;
DROID *targetDroid = nullptr, *psAttackerDroid = nullptr, *psGroupDroid, *psDroid;
DROID *targetDroid = nullptr, *psAttackerDroid = nullptr, *psDroid;
STRUCTURE *targetStructure = nullptr;
WEAPON_EFFECT weaponEffect;
WEAPON_STATS *attackerWeapon;
Expand Down Expand Up @@ -521,7 +521,7 @@ static SDWORD targetAttackWeight(BASE_OBJECT *psTarget, BASE_OBJECT *psAttacker,
}

//fire support - go through all droids assigned to the commander
for (psGroupDroid = psAttackerDroid->psGroup->psList; psGroupDroid; psGroupDroid = psGroupDroid->psGrpNext)
for (const DROID* psGroupDroid : psAttackerDroid->psGroup->psList)
{
for (weaponSlot = 0; weaponSlot < psGroupDroid->numWeaps; weaponSlot++)
{
Expand Down
28 changes: 16 additions & 12 deletions src/droid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ static void droidBodyUpgrade(DROID *psDroid)
psDroid->baseSpeed = calcDroidBaseSpeed(&sTemplate, psDroid->weight, psDroid->player);
if (isTransporter(psDroid))
{
for (DROID *psCurr = psDroid->psGroup->psList; psCurr != nullptr; psCurr = psCurr->psGrpNext)
for (DROID *psCurr : psDroid->psGroup->psList)
{
if (psCurr != psDroid)
{
Expand Down Expand Up @@ -387,7 +387,6 @@ DROID::DROID(uint32_t id, unsigned player)
: BASE_OBJECT(OBJ_DROID, id, player)
, droidType(DROID_ANY)
, psGroup(nullptr)
, psGrpNext(nullptr)
, secondaryOrder(DSS_ARANGE_LONG | DSS_REPLEV_NEVER | DSS_ALEV_ALWAYS | DSS_HALT_GUARD)
, secondaryOrderPending(DSS_ARANGE_LONG | DSS_REPLEV_NEVER | DSS_ALEV_ALWAYS | DSS_HALT_GUARD)
, secondaryOrderPendingCount(0)
Expand Down Expand Up @@ -438,16 +437,18 @@ DROID::~DROID()
audio_RemoveObj(this);

DROID *psDroid = this;
DROID *psCurr, *pNextGroupDroid = nullptr;

if (isTransporter(psDroid))
{
if (psDroid->psGroup)
{
//free all droids associated with this Transporter
for (psCurr = psDroid->psGroup->psList; psCurr != nullptr && psCurr != psDroid; psCurr = pNextGroupDroid)
for (DROID* psCurr : psDroid->psGroup->psList)
{
pNextGroupDroid = psCurr->psGrpNext;
if (psCurr == psDroid)
{
break;
}
delete psCurr;
}
}
Expand Down Expand Up @@ -530,15 +531,18 @@ bool removeDroidBase(DROID *psDel)
if (psDel->psGroup)
{
//free all droids associated with this Transporter
DROID *psNext;
for (auto psCurr = psDel->psGroup->psList; psCurr != nullptr && psCurr != psDel; psCurr = psNext)
mutating_list_iterate(psDel->psGroup->psList, [psDel](DROID* psCurr)
{
psNext = psCurr->psGrpNext;

if (psCurr == psDel)
{
return IterationResult::BREAK_ITERATION;
}
/* add droid to droid list then vanish it - hope this works! - GJ */
addDroid(psCurr, apsDroidLists);
vanishDroid(psCurr);
}

return IterationResult::CONTINUE_ITERATION;
});
}
}

Expand Down Expand Up @@ -2292,7 +2296,7 @@ UDWORD getNumDroidsForLevel(uint32_t player, UDWORD level)
}
if (isTransporter(psDroid))
{
for (DROID *psCurr = psDroid->psGroup->psList; psCurr != nullptr; psCurr = psCurr->psGrpNext)
for (const DROID *psCurr : psDroid->psGroup->psList)
{
if (psCurr != psDroid && getDroidLevel(psCurr) == level)
{
Expand Down Expand Up @@ -2708,7 +2712,7 @@ bool electronicDroid(const DROID *psDroid)
if (psDroid->droidType == DROID_COMMAND && psDroid->psGroup && psDroid->psGroup->psCommander == psDroid)
{
// if a commander has EW units attached it is electronic
for (const DROID *psCurr = psDroid->psGroup->psList; psCurr; psCurr = psCurr->psGrpNext)
for (const DROID *psCurr : psDroid->psGroup->psList)
{
if (psDroid != psCurr && electronicDroid(psCurr))
{
Expand Down
1 change: 0 additions & 1 deletion src/droiddef.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ struct DROID : public BASE_OBJECT
SWORD resistance; ///< used in Electronic Warfare
// The group the droid belongs to
DROID_GROUP *psGroup;
DROID *psGrpNext;
STRUCTURE *psBaseStruct; ///< a structure that this droid might be associated with. For VTOLs this is the rearming pad
// queued orders
SDWORD listSize; ///< Gives the number of synchronised orders. Orders from listSize to the real end of the list may not affect game state.
Expand Down
8 changes: 4 additions & 4 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5341,7 +5341,7 @@ static bool loadSaveDroidPointers(const WzString &pFileName, PerPlayerDroidLists
}
if (isTransporter(psDroid) && psDroid->psGroup != nullptr) // Check for droids in the transporter.
{
for (DROID *psTrDroid = psDroid->psGroup->psList; psTrDroid != nullptr; psTrDroid = psTrDroid->psGrpNext)
for (DROID *psTrDroid : psDroid->psGroup->psList)
{
if (psTrDroid->id == id)
{
Expand Down Expand Up @@ -5485,7 +5485,7 @@ static void writeSaveObject(WzConfig &ini, const BASE_OBJECT *psObj)
}
}

static void writeSaveObjectJSON(nlohmann::json &jsonObj, BASE_OBJECT *psObj)
static void writeSaveObjectJSON(nlohmann::json &jsonObj, const BASE_OBJECT *psObj)
{
jsonObj["id"] = psObj->id;
setPlayerJSON(jsonObj, psObj->player);
Expand Down Expand Up @@ -5787,7 +5787,7 @@ static bool loadSaveDroid(const char *pFileName, PerPlayerDroidLists& ppsCurrent
/*
Writes the linked list of droids for each player to a file
*/
static nlohmann::json writeDroid(DROID *psCurr, bool onMission, int &counter)
static nlohmann::json writeDroid(const DROID *psCurr, bool onMission, int &counter)
{
nlohmann::json droidObj = nlohmann::json::object();
droidObj["name"] = psCurr->aName;
Expand Down Expand Up @@ -5918,7 +5918,7 @@ static bool writeDroidFile(const char *pFileName, const PerPlayerDroidLists& pps
{
if (psCurr->psGroup)
{
for (DROID *psTrans = psCurr->psGroup->psList; psTrans != nullptr; psTrans = psTrans->psGrpNext)
for (const DROID *psTrans : psCurr->psGroup->psList)
{
if (psTrans != psCurr)
{
Expand Down
68 changes: 13 additions & 55 deletions src/group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ DROID_GROUP::DROID_GROUP()
{
type = GT_NORMAL;
refCount = 0;
psList = nullptr;
psCommander = nullptr;
}

Expand Down Expand Up @@ -114,7 +113,7 @@ void DROID_GROUP::add(DROID *psDroid)
// if psDroid == NULL just increase the refcount don't add anything to the list
if (psDroid != nullptr)
{
if (psList && psDroid->player != psList->player)
if (!psList.empty() && psDroid->player != psList.front()->player)
{
ASSERT(false, "grpJoin: Cannot have more than one players droids in a group");
return;
Expand All @@ -129,10 +128,9 @@ void DROID_GROUP::add(DROID *psDroid)
if (isTransporter(psDroid))
{
ASSERT_OR_RETURN(, (type == GT_NORMAL), "grpJoin: Cannot have two transporters in a group");
ASSERT_OR_RETURN(, psList == nullptr, "Adding transporter to non-empty list.");
ASSERT_OR_RETURN(, psList.empty(), "Adding transporter to non-empty list.");
type = GT_TRANSPORTER;
psDroid->psGrpNext = psList;
psList = psDroid;
psList.push_front(psDroid);
}
else if ((psDroid->droidType == DROID_COMMAND) && (type != GT_TRANSPORTER))
{
Expand All @@ -142,8 +140,7 @@ void DROID_GROUP::add(DROID *psDroid)
}
else
{
psDroid->psGrpNext = psList;
psList = psDroid;
psList.push_front(psDroid);
}

if (type == GT_COMMAND)
Expand All @@ -158,8 +155,6 @@ void DROID_GROUP::add(DROID *psDroid)
// remove a droid from a group
void DROID_GROUP::remove(DROID *psDroid)
{
DROID *psPrev, *psCurr;

ASSERT_OR_RETURN(, grpInitialized, "Group code not initialized yet");

if (psDroid != nullptr && psDroid->psGroup != this)
Expand All @@ -178,34 +173,15 @@ void DROID_GROUP::remove(DROID *psDroid)
// if psDroid == NULL just decrease the refcount don't remove anything from the list
if (psDroid != nullptr)
{
// update group list of droids and droids' psGrpNext
// update group list of droids
if (psDroid->droidType != DROID_COMMAND || type != GT_COMMAND)
{
psPrev = nullptr;
for (psCurr = psList; psCurr; psCurr = psCurr->psGrpNext)
{
if (psCurr == psDroid)
{
break;
}
psPrev = psCurr;
}
ASSERT(psCurr != nullptr, "grpLeave: droid not found");
if (psCurr != nullptr)
{
if (psPrev)
{
psPrev->psGrpNext = psCurr->psGrpNext;
}
else
{
psList = psList->psGrpNext;
}
}
auto it = std::find(psList.begin(), psList.end(), psDroid);
ASSERT(it != psList.end(), "grpLeave: droid not found");
psList.erase(it);
}

psDroid->psGroup = nullptr;
psDroid->psGrpNext = nullptr;

// update group's type
if ((psDroid->droidType == DROID_COMMAND) && (type == GT_COMMAND))
Expand All @@ -232,28 +208,16 @@ void DROID_GROUP::remove(DROID *psDroid)
// count the members of a group
unsigned int DROID_GROUP::getNumMembers()
{
const DROID *psCurr;
unsigned int num;

ASSERT(grpInitialized, "Group code not initialized yet");

num = 0;
for (psCurr = psList; psCurr; psCurr = psCurr->psGrpNext)
{
num += 1;
}

return num;
return psList.size();
}

// Give a group of droids an order
void DROID_GROUP::orderGroup(DROID_ORDER order)
{
DROID *psCurr;

ASSERT(grpInitialized, "Group code not initialized yet");

for (psCurr = psList; psCurr; psCurr = psCurr->psGrpNext)
for (DROID* psCurr : psList)
{
orderDroid(psCurr, order, ModeQueue);
}
Expand All @@ -262,12 +226,10 @@ void DROID_GROUP::orderGroup(DROID_ORDER order)
// Give a group of droids an order (using a Location)
void DROID_GROUP::orderGroup(DROID_ORDER order, UDWORD x, UDWORD y)
{
DROID *psCurr;

ASSERT(grpInitialized, "Group code not initialized yet");
ASSERT_OR_RETURN(, validOrderForLoc(order), "orderGroup: Bad order");

for (psCurr = psList; psCurr != nullptr; psCurr = psCurr->psGrpNext)
for (DROID* psCurr : psList)
{
orderDroidLoc(psCurr, order, x, y, bMultiMessages ? ModeQueue : ModeImmediate);
}
Expand All @@ -276,11 +238,9 @@ void DROID_GROUP::orderGroup(DROID_ORDER order, UDWORD x, UDWORD y)
// Give a group of droids an order (using an Object)
void DROID_GROUP::orderGroup(DROID_ORDER order, BASE_OBJECT *psObj)
{
DROID *psCurr;

ASSERT_OR_RETURN(, validOrderForObj(order), "orderGroup: Bad order");

for (psCurr = psList; psCurr != nullptr; psCurr = psCurr->psGrpNext)
for (DROID* psCurr : psList)
{
orderDroidObj(psCurr, order, (BASE_OBJECT *)psObj, bMultiMessages ? ModeQueue : ModeImmediate);
}
Expand All @@ -289,11 +249,9 @@ void DROID_GROUP::orderGroup(DROID_ORDER order, BASE_OBJECT *psObj)
// Set the secondary state for a group of droids
void DROID_GROUP::setSecondary(SECONDARY_ORDER sec, SECONDARY_STATE state)
{
DROID *psCurr;

ASSERT(grpInitialized, "Group code not initialized yet");

for (psCurr = psList; psCurr; psCurr = psCurr->psGrpNext)
for (DROID* psCurr : psList)
{
secondarySetState(psCurr, sec, state);
}
Expand Down
11 changes: 6 additions & 5 deletions src/group.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#define __INCLUDED_SRC_GROUP_H__

#include "orderdef.h"
#include "objmem.h"

struct BASE_OBJECT;
struct DROID;
Expand All @@ -51,11 +52,11 @@ class DROID_GROUP

void setSecondary(SECONDARY_ORDER sec, SECONDARY_STATE state); // set the secondary state for a group of droids

GROUP_TYPE type; // Type from the enum GROUP_TYPE above
SWORD refCount; // Number of objects in the group. Group is deleted if refCount<=0. Count number of droids+NULL pointers.
DROID *psList; // List of droids in the group
DROID *psCommander; // The command droid of a command group
int id; // unique group id
GROUP_TYPE type; // Type from the enum GROUP_TYPE above
SWORD refCount; // Number of objects in the group. Group is deleted if refCount<=0. Count number of droids+NULL pointers.
DroidList psList; // List of droids in the group
DROID *psCommander; // The command droid of a command group
int id; // unique group id
};

// initialise the group system
Expand Down
8 changes: 5 additions & 3 deletions src/loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -897,8 +897,6 @@ void adjustDroidCount(DROID *droid, int delta) {
// Increase counts of droids in a transporter
void droidCountsInTransporter(DROID *droid, int player)
{
DROID *psDroid = nullptr;

if (!isTransporter(droid) || droid->psGroup == nullptr)
{
return;
Expand All @@ -907,8 +905,12 @@ void droidCountsInTransporter(DROID *droid, int player)
numTransporterDroids[player] += droid->psGroup->refCount - 1;

// and count the units inside it...
for (psDroid = droid->psGroup->psList; psDroid != nullptr && psDroid != droid; psDroid = psDroid->psGrpNext)
for (DROID* psDroid : droid->psGroup->psList)
{
if (psDroid == droid)
{
break;
}
if (psDroid->droidType == DROID_CYBORG_CONSTRUCT || psDroid->droidType == DROID_CONSTRUCT)
{
numConstructorDroids[player] += 1;
Expand Down
Loading

0 comments on commit 22b0518

Please sign in to comment.