diff --git a/src/common/LinkedObjectPool.hxx b/src/common/LinkedObjectPool.hxx index 03e8bfa22..ea6f9c8d8 100644 --- a/src/common/LinkedObjectPool.hxx +++ b/src/common/LinkedObjectPool.hxx @@ -25,8 +25,8 @@ * A fixed-size object-pool based doubly-linked list that makes use of * multiple STL lists, to reduce frequent (de)allocations. * - * This structure acts like a queue (adds to end, removes from beginning), - * but also allows for removal at any location in the queue. + * This structure can be used as either a stack or queue, but also allows + * for removal at any location in the list. * * There are two internal lists; one stores active nodes, and the other * stores pool nodes that have been 'deleted' from the active list (note @@ -61,9 +61,29 @@ class LinkedObjectPool } /** - * Add a new node at the end of the active list, and return a reference to - * that node. The reference may then be modified; ie, you're able to change - * the data located at that node. + * Return a reference to the element at the first node in the active list. + */ + T& first() { return myList.front(); } + + /** + * Return a reference to the element at the last node in the active list. + */ + T& last() { return myList.back(); } + + /** + * Add a new node at beginning of the active list, and return a reference + * to that nodes' data. The reference may then be modified; ie, you're + * able to change the data located at that node. + */ + T& addFirst() { + myList.splice(myList.begin(), myPool, myPool.begin()); + return myList.front(); + } + + /** + * Add a new node at the end of the active list, and return a reference + * to that nodes' data. The reference may then be modified; ie, you're + * able to change the data located at that node. */ T& addLast() { myList.splice(myList.end(), myPool, myPool.begin()); @@ -71,13 +91,22 @@ class LinkedObjectPool } /** - * Return a reference to the element at the first node. - * The reference may not be modified. + * Remove the first node of the active list. */ - const T& first() const { return myList.front(); } + void removeFirst() { + myPool.splice(myPool.end(), myList, myList.begin()); + } /** - * Remove a single element at position of the iterator +- the offset. + * Remove the last node of the active list. + */ + void removeLast() { + myPool.splice(myPool.end(), myList, std::prev(myList.end(), 1)); + } + + /** + * Convenience method to remove a single element from the active list at + * position of the iterator +- the offset. */ void remove(const_iter i, Int32 offset = 0) { myPool.splice(myPool.end(), myList, @@ -85,37 +114,38 @@ class LinkedObjectPool } /** - * Remove a single element by index, offset from the beginning of the list. - * (ie, '0' means first element, '1' is second, and so on). + * Convenience method to remove a single element from the active list by + * index, offset from the beginning of the list. (ie, '0' means first + * element, '1' is second, and so on). */ void remove(uInt32 index) { myPool.splice(myPool.end(), myList, std::next(myList.begin(), index)); } - /** - * Convenience method to remove the first element in the list. - */ - void removeFirst() { - myPool.splice(myPool.end(), myList, myList.begin()); - } - /** * Convenience method to remove a range of elements from 'index' to the - * end of the list. + * end of the active list. */ void removeLast(uInt32 index) { myPool.splice(myPool.end(), myList, std::next(myList.begin(), index), myList.end()); } + /** + * Erase entire contents of active list. + */ + void clear() { + myPool.splice(myPool.end(), myList, myList.begin(), myList.end()); + } + /** Access the list with iterators, just as you would a normal C++ STL list */ iter begin() { return myList.begin(); } iter end() { return myList.end(); } const_iter begin() const { return myList.cbegin(); } const_iter end() const { return myList.cend(); } - uInt32 size() const { return myList.size(); } - bool empty() const { return size() == 0; } - bool full() const { return size() >= CAPACITY; } + uInt32 size() const { return myList.size(); } + bool empty() const { return myList.size() == 0; } + bool full() const { return myList.size() >= CAPACITY; } private: std::list myList, myPool; diff --git a/src/common/RewindManager.cxx b/src/common/RewindManager.cxx index 21a7d2281..0a0a265e1 100644 --- a/src/common/RewindManager.cxx +++ b/src/common/RewindManager.cxx @@ -32,16 +32,16 @@ RewindManager::RewindManager(OSystem& system, StateManager& statemgr) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RewindManager::addState(const string& message) { - RewindPtr state = make_unique(); // TODO: get this from object pool - Serializer& s = state->data; + if(myStateList.full()) + myStateList.removeLast(); // remove the oldest state file + + RewindState& state = myStateList.addFirst(); + Serializer& s = state.data; s.reset(); // rewind Serializer internal buffers if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s)) { - state->message = "Rewind " + message; - - // Add to the list TODO: should check against current size - myStateList.emplace_front(std::move(state)); + state.message = "Rewind " + message; return true; } return false; @@ -50,18 +50,18 @@ bool RewindManager::addState(const string& message) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RewindManager::rewindState() { - if(myStateList.size() > 0) + if(!myStateList.empty()) { - RewindPtr state = std::move(myStateList.front()); - myStateList.pop_front(); // TODO: add 'state' to object pool - Serializer& s = state->data; + RewindState& state = myStateList.first(); + Serializer& s = state.data; s.reset(); // rewind Serializer internal buffers myStateManager.loadState(s); myOSystem.console().tia().loadDisplay(s); // Show message indicating the rewind state - myOSystem.frameBuffer().showMessage(state->message); + myOSystem.frameBuffer().showMessage(state.message); + myStateList.removeFirst(); return true; } diff --git a/src/common/RewindManager.hxx b/src/common/RewindManager.hxx index 504cea079..d8c238edf 100644 --- a/src/common/RewindManager.hxx +++ b/src/common/RewindManager.hxx @@ -21,17 +21,12 @@ class OSystem; class StateManager; -#include +#include "LinkedObjectPool.hxx" #include "bspf.hxx" /** This class is used to save (and later 'rewind') system save states. - TODO: This will eventually be converted to use object pools - Currently, it uses a C++ doubly-linked list as a stack, with - add/remove happening at the front of the list - Also, the additions are currently unbounded - @author Stephen Anthony */ class RewindManager @@ -54,12 +49,12 @@ class RewindManager */ bool rewindState(); - bool empty() const { return myStateList.size() == 0; } + bool empty() const { return myStateList.empty(); } void clear() { myStateList.clear(); } private: // Maximum number of states to save - static constexpr uInt32 MAX_SIZE = 100; // FIXME: use this + static constexpr uInt32 MAX_SIZE = 100; OSystem& myOSystem; StateManager& myStateManager; @@ -67,10 +62,13 @@ class RewindManager struct RewindState { Serializer data; string message; + + // We do nothing on object instantiation or copy + RewindState() { } + RewindState(const RewindState&) { } }; - using RewindPtr = unique_ptr; - std::list myStateList; + Common::LinkedObjectPool myStateList; private: // Following constructors and assignment operators not supported