bsnes/higan/nall/serializer.hpp

147 lines
3.5 KiB
C++
Raw Normal View History

#ifndef NALL_SERIALIZER_HPP
#define NALL_SERIALIZER_HPP
#include <type_traits>
#include <utility>
#include <nall/stdint.hpp>
#include <nall/utility.hpp>
namespace nall {
//serializer: a class designed to save and restore the state of classes.
//
//benefits:
//- data() will be portable in size (it is not necessary to specify type sizes.)
//- data() will be portable in endianness (always stored internally as little-endian.)
//- one serialize function can both save and restore class states.
//
//caveats:
//- only plain-old-data can be stored. complex classes must provide serialize(serializer&);
//- floating-point usage is not portable across platforms
class serializer {
public:
enum mode_t { Load, Save, Size };
mode_t mode() const {
return imode;
}
const uint8_t* data() const {
return idata;
}
unsigned size() const {
return isize;
}
unsigned capacity() const {
return icapacity;
}
template<typename T> void floatingpoint(T &value) {
enum { size = sizeof(T) };
//this is rather dangerous, and not cross-platform safe;
//but there is no standardized way to export FP-values
uint8_t *p = (uint8_t*)&value;
if(imode == Save) {
for(unsigned n = 0; n < size; n++) idata[isize++] = p[n];
} else if(imode == Load) {
for(unsigned n = 0; n < size; n++) p[n] = idata[isize++];
} else {
isize += size;
}
}
template<typename T> void integer(T &value) {
enum { size = std::is_same<bool, T>::value ? 1 : sizeof(T) };
if(imode == Save) {
for(unsigned n = 0; n < size; n++) idata[isize++] = (uintmax_t)value >> (n << 3);
} else if(imode == Load) {
value = 0;
for(unsigned n = 0; n < size; n++) value |= (uintmax_t)idata[isize++] << (n << 3);
} else if(imode == Size) {
isize += size;
}
}
template<typename T> void array(T &array) {
enum { size = sizeof(T) / sizeof(typename std::remove_extent<T>::type) };
for(unsigned n = 0; n < size; n++) integer(array[n]);
}
template<typename T> void array(T array, unsigned size) {
for(unsigned n = 0; n < size; n++) integer(array[n]);
}
//copy
serializer& operator=(const serializer &s) {
if(idata) delete[] idata;
imode = s.imode;
idata = new uint8_t[s.icapacity];
isize = s.isize;
icapacity = s.icapacity;
memcpy(idata, s.idata, s.icapacity);
return *this;
}
serializer(const serializer &s) : idata(0) {
operator=(s);
}
//move
serializer& operator=(serializer &&s) {
if(idata) delete[] idata;
imode = s.imode;
idata = s.idata;
isize = s.isize;
icapacity = s.icapacity;
s.idata = 0;
return *this;
}
serializer(serializer &&s) {
operator=(std::move(s));
}
//construction
serializer() {
imode = Size;
idata = 0;
isize = 0;
Update to v070r04 release. byuu says: - fixed new config file input driver name (you'll have to delete your old config, or change to a different driver and back and restart) - fixed slot loader windows' OK button placement - fixed nall/directory.hpp when list size was zero - rewrote nall/function.hpp, no longer requires <functional> or union tricks - added state manager The state manager is a little bit different this time. It's functionally identical to bsnes/Qt, 100% of the way. But when you save slots, it stores them in RAM. It only writes the BSA archive upon ROM unload / program exit. Yes, this means that technically if the emulator crashes, you'll lose your states. But a) that very rarely happens, and b) the old way was thrashing the disk like crazy, every letter you typed dumped up to 8MB to disk. With this new method, I can simply store a boolean valid flag before each slot, and pack the file better. Before, a save on only slot 3 would be 3*state size (~1.2mb), it will now be 3bytes+state size (~400kb.) I have also added a proper signature because of this, so it will detect when you load an archive for a previous serializer version and ignore it. When you go to save (unload the game), if there are no valid slots, the BSA archive gets unlinked (deleted.) I am also planning a feature around the now-hidden "slot 0". My idea is for it to be a fallback slot. How many times have you loaded a state when you meant to save and said, "shit, now I lost some of my progress"? The idea is that whenever you load a state, right before loading, it will save to slot 0. When you unload the game, or exit the emulator, it will also save to slot 0. You will be able to load from slot 0 from the menu, but not save to it. It will appear at the bottom of the load list. And lastly, I'll add an advanced option to auto-load slot 0 if it exists, which will enable "close the emulator and restart where you left off." functionality.
2010-09-30 10:29:49 +00:00
icapacity = 0;
}
serializer(unsigned capacity) {
imode = Save;
idata = new uint8_t[capacity]();
isize = 0;
icapacity = capacity;
}
serializer(const uint8_t *data, unsigned capacity) {
imode = Load;
idata = new uint8_t[capacity];
isize = 0;
icapacity = capacity;
memcpy(idata, data, capacity);
}
~serializer() {
if(idata) delete[] idata;
}
private:
mode_t imode;
uint8_t *idata;
unsigned isize;
unsigned icapacity;
};
};
#endif