Ported RewindManager to use LinkedObjectPool class.

This commit is contained in:
Stephen Anthony 2017-10-09 18:11:15 -02:30
parent 741e148da5
commit 63ad275b9d
3 changed files with 71 additions and 43 deletions

View File

@ -25,8 +25,8 @@
* A fixed-size object-pool based doubly-linked list that makes use of * A fixed-size object-pool based doubly-linked list that makes use of
* multiple STL lists, to reduce frequent (de)allocations. * multiple STL lists, to reduce frequent (de)allocations.
* *
* This structure acts like a queue (adds to end, removes from beginning), * This structure can be used as either a stack or queue, but also allows
* but also allows for removal at any location in the queue. * for removal at any location in the list.
* *
* There are two internal lists; one stores active nodes, and the other * There are two internal lists; one stores active nodes, and the other
* stores pool nodes that have been 'deleted' from the active list (note * 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 * Return a reference to the element at the first node in the active list.
* that node. The reference may then be modified; ie, you're able to change */
* the data located at that node. 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() { T& addLast() {
myList.splice(myList.end(), myPool, myPool.begin()); myList.splice(myList.end(), myPool, myPool.begin());
@ -71,13 +91,22 @@ class LinkedObjectPool
} }
/** /**
* Return a reference to the element at the first node. * Remove the first node of the active list.
* The reference may not be modified.
*/ */
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) { void remove(const_iter i, Int32 offset = 0) {
myPool.splice(myPool.end(), myList, myPool.splice(myPool.end(), myList,
@ -85,37 +114,38 @@ class LinkedObjectPool
} }
/** /**
* Remove a single element by index, offset from the beginning of the list. * Convenience method to remove a single element from the active list by
* (ie, '0' means first element, '1' is second, and so on). * index, offset from the beginning of the list. (ie, '0' means first
* element, '1' is second, and so on).
*/ */
void remove(uInt32 index) { void remove(uInt32 index) {
myPool.splice(myPool.end(), myList, std::next(myList.begin(), 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 * 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) { void removeLast(uInt32 index) {
myPool.splice(myPool.end(), myList, std::next(myList.begin(), index), myList.end()); 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 */ /** Access the list with iterators, just as you would a normal C++ STL list */
iter begin() { return myList.begin(); } iter begin() { return myList.begin(); }
iter end() { return myList.end(); } iter end() { return myList.end(); }
const_iter begin() const { return myList.cbegin(); } const_iter begin() const { return myList.cbegin(); }
const_iter end() const { return myList.cend(); } const_iter end() const { return myList.cend(); }
uInt32 size() const { return myList.size(); } uInt32 size() const { return myList.size(); }
bool empty() const { return size() == 0; } bool empty() const { return myList.size() == 0; }
bool full() const { return size() >= CAPACITY; } bool full() const { return myList.size() >= CAPACITY; }
private: private:
std::list<T> myList, myPool; std::list<T> myList, myPool;

View File

@ -32,16 +32,16 @@ RewindManager::RewindManager(OSystem& system, StateManager& statemgr)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RewindManager::addState(const string& message) bool RewindManager::addState(const string& message)
{ {
RewindPtr state = make_unique<RewindState>(); // TODO: get this from object pool if(myStateList.full())
Serializer& s = state->data; myStateList.removeLast(); // remove the oldest state file
RewindState& state = myStateList.addFirst();
Serializer& s = state.data;
s.reset(); // rewind Serializer internal buffers s.reset(); // rewind Serializer internal buffers
if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s)) if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s))
{ {
state->message = "Rewind " + message; state.message = "Rewind " + message;
// Add to the list TODO: should check against current size
myStateList.emplace_front(std::move(state));
return true; return true;
} }
return false; return false;
@ -50,18 +50,18 @@ bool RewindManager::addState(const string& message)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RewindManager::rewindState() bool RewindManager::rewindState()
{ {
if(myStateList.size() > 0) if(!myStateList.empty())
{ {
RewindPtr state = std::move(myStateList.front()); RewindState& state = myStateList.first();
myStateList.pop_front(); // TODO: add 'state' to object pool Serializer& s = state.data;
Serializer& s = state->data;
s.reset(); // rewind Serializer internal buffers s.reset(); // rewind Serializer internal buffers
myStateManager.loadState(s); myStateManager.loadState(s);
myOSystem.console().tia().loadDisplay(s); myOSystem.console().tia().loadDisplay(s);
// Show message indicating the rewind state // Show message indicating the rewind state
myOSystem.frameBuffer().showMessage(state->message); myOSystem.frameBuffer().showMessage(state.message);
myStateList.removeFirst();
return true; return true;
} }

View File

@ -21,17 +21,12 @@
class OSystem; class OSystem;
class StateManager; class StateManager;
#include <list> #include "LinkedObjectPool.hxx"
#include "bspf.hxx" #include "bspf.hxx"
/** /**
This class is used to save (and later 'rewind') system save states. 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 @author Stephen Anthony
*/ */
class RewindManager class RewindManager
@ -54,12 +49,12 @@ class RewindManager
*/ */
bool rewindState(); bool rewindState();
bool empty() const { return myStateList.size() == 0; } bool empty() const { return myStateList.empty(); }
void clear() { myStateList.clear(); } void clear() { myStateList.clear(); }
private: private:
// Maximum number of states to save // Maximum number of states to save
static constexpr uInt32 MAX_SIZE = 100; // FIXME: use this static constexpr uInt32 MAX_SIZE = 100;
OSystem& myOSystem; OSystem& myOSystem;
StateManager& myStateManager; StateManager& myStateManager;
@ -67,10 +62,13 @@ class RewindManager
struct RewindState { struct RewindState {
Serializer data; Serializer data;
string message; string message;
// We do nothing on object instantiation or copy
RewindState() { }
RewindState(const RewindState&) { }
}; };
using RewindPtr = unique_ptr<RewindState>; Common::LinkedObjectPool<RewindState, MAX_SIZE> myStateList;
std::list<RewindPtr> myStateList;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported