From 4f3de9dd6e3163409fbd181e81c25846cd736796 Mon Sep 17 00:00:00 2001 From: Pavel Solodovnikov Date: Sat, 9 Mar 2024 12:25:35 +0300 Subject: [PATCH] PagedEntityContainer: add `ReuseSlots` boolean template parameter This allows to disable slot reuse in `PagedEntityContainer`. The feature is temporary and will be used only until we are confident that we don't have any issues in the WZ code base regarding object pointers not updated properly, e.g. when transitioning between the base and offworld missions. So, it's to prevent cases where one object would be overwritten by another and the game code haven't noticed that. It's better to crash/assert rather than silently use one object instead of another, which could lead to unobvious and weird bugs. Signed-off-by: Pavel Solodovnikov --- lib/framework/paged_entity_container.h | 44 ++++++++++++++++++++------ 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/lib/framework/paged_entity_container.h b/lib/framework/paged_entity_container.h index 9687fe10618..f0f65c9ee87 100644 --- a/lib/framework/paged_entity_container.h +++ b/lib/framework/paged_entity_container.h @@ -99,7 +99,8 @@ /// /// Entity type. Should be a complete type. /// The fixed number of elements each page may hold. -template +/// If `false`, slots are one-shot and set to expire after single use. +template class PagedEntityContainer { using SlotIndexType = size_t; @@ -150,6 +151,11 @@ class PagedEntityContainer return _isAlive; } + void invalidate() + { + _generation = INVALID_GENERATION; + } + void set_dead() { _isAlive = false; @@ -399,8 +405,11 @@ class PagedEntityContainer { return; } - // Advance slot generation number. - slotMetadata.advance_generation(); + + // Either advance slot generation number or invalidate the slot right away, + // the behavior depends on whether we reuse the slots or not. + advance_slot_generation(slotMetadata); + // Ensure that the element pointed-to by this slot is dead. slotMetadata.set_dead(); @@ -580,7 +589,7 @@ class PagedEntityContainer const_iterator begin() const { - return const_iterator(const_cast*>(this)->begin()); + return const_iterator(const_cast(this)->begin()); } iterator begin() @@ -657,7 +666,7 @@ class PagedEntityContainer const_iterator find(const T& x) const { - return const_iterator(const_cast*>(this)->find(const_cast(x))); + return const_iterator(const_cast(this)->find(const_cast(x))); } void erase(const_iterator it) @@ -787,6 +796,21 @@ class PagedEntityContainer return (reinterpret_cast(addr) % alignof(T)) == 0; } + template + void advance_slot_generation(SlotMetadata& meta) + { + // Advance slot generation number, when `ReuseSlots=true`. + meta.advance_generation(); + } + + // Specialization for the case when `ReuseSlots=false`. + template <> + void advance_slot_generation(SlotMetadata& meta) + { + // Invalidate slot right away so that it cannot be reused anymore. + meta.invalidate(); + } + std::vector _pages; SlotIndexType _maxIndex = INVALID_SLOT_IDX; size_t _size = 0; @@ -794,10 +818,10 @@ class PagedEntityContainer size_t _expiredSlotsCount = 0; }; -template -constexpr typename PagedEntityContainer::SlotIndexType - PagedEntityContainer::INVALID_SLOT_IDX; +template +constexpr typename PagedEntityContainer::SlotIndexType + PagedEntityContainer::INVALID_SLOT_IDX; -template -constexpr size_t PagedEntityContainer::INVALID_PAGE_IDX; +template +constexpr size_t PagedEntityContainer::INVALID_PAGE_IDX;