1
0
mirror of https://github.com/OpenTTD/OpenTTD synced 2026-01-18 18:02:37 +01:00

Fix: [Script] Retarget iterators on list swap (#14805)

Fix script list sorter to correctly retarget iterator when swapping lists.
Each sorter implementation now updates its internal iterator to remain valid after attaching to a new list, avoiding undefined behaviour.
This commit is contained in:
SamuXarick
2026-01-08 22:06:57 +00:00
committed by GitHub
parent 80f19546d2
commit bee3bc0ce5

View File

@@ -34,6 +34,11 @@ protected:
*/
virtual void FindNext() = 0;
/**
* Retarget sorter internal iterator after retargeting the list.
*/
virtual void RetargetIterator() = 0;
public:
/**
* Virtual dtor, needed to mute warnings.
@@ -87,14 +92,15 @@ public:
}
/**
* Attach the sorter to a new list. This assumes the content of the old list has been moved to
* the new list, too, so that we don't have to invalidate any iterators. Note that std::swap
* doesn't invalidate iterators on lists and maps, so that should be safe.
* @param new_list New list to attach to.
* Attach the sorter to a new list and update internal iterator so it remains valid
* in the context of the new list. This assumes the content of the old list has been
* moved to the new list.
* @param new_list New list to attach to and update internal iterator.
*/
void Retarget(const ScriptList *new_list)
{
this->list = new_list;
this->RetargetIterator();
}
};
@@ -138,6 +144,16 @@ public:
++this->value_iter;
if (this->value_iter != this->list->values.end()) this->item_next = this->value_iter->second;
}
void RetargetIterator() override
{
if (this->item_next.has_value()) {
auto item_iter = this->list->items.find(this->item_next.value());
this->value_iter = this->list->values.find({item_iter->second, this->item_next.value()});
} else {
this->value_iter = this->list->values.end();
}
}
};
/**
@@ -189,6 +205,16 @@ public:
}
if (this->value_iter != this->list->values.end()) this->item_next = this->value_iter->second;
}
void RetargetIterator() override
{
if (this->item_next.has_value()) {
auto item_iter = this->list->items.find(this->item_next.value());
this->value_iter = this->list->values.find({item_iter->second, this->item_next.value()});
} else {
this->value_iter = this->list->values.end();
}
}
};
/**
@@ -231,6 +257,15 @@ public:
++this->item_iter;
if (this->item_iter != this->list->items.end()) this->item_next = this->item_iter->first;
}
void RetargetIterator() override
{
if (this->item_next.has_value()) {
this->item_iter = this->list->items.find(this->item_next.value());
} else {
this->item_iter = this->list->items.end();
}
}
};
/**
@@ -282,6 +317,15 @@ public:
}
if (this->item_iter != this->list->items.end()) this->item_next = this->item_iter->first;
}
void RetargetIterator() override
{
if (this->item_next.has_value()) {
this->item_iter = this->list->items.find(this->item_next.value());
} else {
this->item_iter = this->list->items.end();
}
}
};