#ifndef CREATURELIB_HISTORYHOLDER_HPP #define CREATURELIB_HISTORYHOLDER_HPP #include "../../Library/Exceptions/CreatureException.hpp" #include "HistoryElements/HistoryElement.hpp" template concept HistoryElementType = std::is_base_of::value; namespace CreatureLib::Battling { class HistoryHolder { size_t _offset; size_t _capacity; u8* _memory = nullptr; HistoryElement* _top = nullptr; static constexpr size_t initialSize = 2048; static constexpr size_t stepSize = 1024; public: HistoryHolder() : _offset(0), _capacity(2048) { auto ptr = malloc(_capacity); if (ptr == nullptr) { THROW("Out of memory."); } _memory = static_cast(ptr); } HistoryHolder(const HistoryHolder&) = delete; HistoryHolder& operator=(const HistoryHolder&) = delete; ~HistoryHolder() { if (_top != nullptr) _top->Clear(); free(_memory); } void Resize() { _capacity += stepSize; auto newPtr = realloc(_memory, _capacity); if (newPtr == nullptr) { THROW("Out of memory."); } _memory = static_cast(newPtr); } template void Register(parameters... args) { if (_offset + sizeof(T) >= _capacity) { Resize(); } u8* ptr = _memory + _offset; T* element = new (ptr) T(args...); _offset += sizeof(T); if (_top != nullptr) { element->_previousOffset = (u8*)sizeof(T); } _top = element; } ArbUt::BorrowedPtr GetTopElement() const noexcept { return _top; } std::optional> GetLastUsedAttack() const noexcept { const auto* c = _top; while (c != nullptr) { if (c->GetKind() == HistoryElementKind::AttackUse) return c; c = c->GetPrevious(); } return {}; } void CloneOnto(HistoryHolder& other) { if (other._top != nullptr) { other._top->Clear(); } free(other._memory); other._offset = _offset; other._capacity = _capacity; other._memory = static_cast(malloc(_capacity)); if (_top != nullptr) { other._top = reinterpret_cast(other._memory + ((u8*)_top - _memory)); } } }; } #endif // CREATURELIB_HISTORYHOLDER_HPP