stella/src/common/RewindManager.hxx

196 lines
5.5 KiB
C++

//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef REWIND_MANAGER_HXX
#define REWIND_MANAGER_HXX
class OSystem;
class StateManager;
#include "LinkedObjectPool.hxx"
#include "bspf.hxx"
/**
This class is used to save (and later 'replay') system save states.
In this implementation, we assume states are added at the end of the list.
Rewinding involves moving the internal iterator backwards in time (towards
the beginning of the list).
Unwinding involves moving the internal iterator forwards in time (towards
the end of the list).
Any time a new state is added, all states from the current iterator position
to the end of the list (aka, all future states) are removed, and the internal
iterator moves to the insertion point of the data (the end of the list).
@author Stephen Anthony
*/
class RewindManager
{
public:
RewindManager(OSystem& system, StateManager& statemgr);
public:
static constexpr int NUM_INTERVALS = 7;
// cycle values for the intervals
const uInt32 INTERVAL_CYCLES[NUM_INTERVALS] = {
76 * 262,
76 * 262 * 3,
76 * 262 * 10,
76 * 262 * 30,
76 * 262 * 60,
76 * 262 * 60 * 3,
76 * 262 * 60 * 10
};
// settings values for the intervals
const string INT_SETTINGS[NUM_INTERVALS] = {
"1f",
"3f",
"10f",
"30f",
"1s",
"3s",
"10s"
};
static constexpr int NUM_HORIZONS = 8;
// cycle values for the horzions
const uInt64 HORIZON_CYCLES[NUM_HORIZONS] = {
76 * 262 * 60 * 3,
76 * 262 * 60 * 10,
76 * 262 * 60 * 30,
76 * 262 * 60 * 60,
76 * 262 * 60 * 60 * 3,
76 * 262 * 60 * 60 * 10,
uInt64(76) * 262 * 60 * 60 * 30,
uInt64(76) * 262 * 60 * 60 * 60
};
// settings values for the horzions
const string HOR_SETTINGS[NUM_HORIZONS] = {
"3s",
"10s",
"30s",
"1m",
"3m",
"10m",
"30m",
"60m"
};
/**
Initializes state list and calculates compression factor.
*/
void setup();
/**
Add a new state file with the given message; this message will be
displayed when the state is replayed.
@param message Message to display when replaying this state
*/
bool addState(const string& message, bool timeMachine = false);
/**
Rewind one level of the state list, and display the message associated
with that state.
@param numStates Number of states to rewind
@return Number of states to rewinded
*/
uInt32 rewindState(uInt32 numStates = 1);
/**
Unwind one level of the state list, and display the message associated
with that state.
@param numStates Number of states to unwind
@return Number of states to unwinded
*/
uInt32 unwindState(uInt32 numStates = 1);
bool atFirst() const { return myStateList.atFirst(); }
bool atLast() const { return myStateList.atLast(); }
void resize(uInt32 size) { myStateList.resize(size); }
void clear() { myStateList.clear(); }
/**
Convert the cycles into a unit string.
*/
string getUnitString(Int64 cycles);
uInt32 getCurrentIdx() { return myStateList.currentIdx(); }
uInt32 getLastIdx() { return myStateList.size(); }
uInt32 getFirstCycles();
uInt32 getCurrentCycles();
uInt32 getLastCycles();
private:
OSystem& myOSystem;
StateManager& myStateManager;
uInt32 mySize;
uInt32 myUncompressed;
uInt32 myInterval;
uInt64 myHorizon;
double myFactor;
bool myLastTimeMachineAdd;
struct RewindState {
Serializer data; // actual save state
string message; // describes save state origin
uInt64 cycles; // cycles since emulation started
// We do nothing on object instantiation or copy
// The goal of LinkedObjectPool is to not do any allocations at all
RewindState() { }
RewindState(const RewindState&) { }
// Output object info; used for debugging only
friend ostream& operator<<(ostream& os, const RewindState& s) {
return os << "msg: " << s.message << " cycle: " << s.cycles;
}
};
// The linked-list to store states (internally it takes care of reducing
// frequent (de)-allocations)
Common::LinkedObjectPool<RewindState> myStateList;
/**
Remove a save state from the list
*/
void compressStates();
/**
Load the current state and get the message string for the rewind/unwind
@return The message
*/
string loadState(Int64 startCycles, uInt32 numStates);
private:
// Following constructors and assignment operators not supported
RewindManager() = delete;
RewindManager(const RewindManager&) = delete;
RewindManager(RewindManager&&) = delete;
RewindManager& operator=(const RewindManager&) = delete;
RewindManager& operator=(RewindManager&&) = delete;
};
#endif