Last active
November 16, 2016 10:39
-
-
Save ragecryx/a65d0893e3716f7506d800fce9b1fcb5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// build!g++ -std=c++11 -g -Wall -o bin_serialization bin_serialization.cpp | |
// run!./bin_serialization | |
#include <cstdio> | |
#include <cstdlib> | |
#include <cassert> | |
#include <string> | |
#include <type_traits> | |
#include <sys/stat.h> | |
#include <iostream> | |
using namespace std; | |
/////////////////////////// Serializer Code /////////////////////////// | |
class Serializer; | |
class Serializable { | |
public: | |
virtual void SaveTo(Serializer *s) const = 0; | |
virtual void LoadFrom(Serializer *s) = 0; | |
}; | |
// SFINAE | |
template<class T> | |
using IsScalar = typename std::enable_if< std::is_scalar<T>::value >::type*; | |
template<class T> | |
using IsSerializable = typename std::enable_if< std::is_base_of<Serializable, T>::value, Serializable >::type*; | |
template<class T> | |
using IsString = typename std::enable_if< std::is_base_of<std::string, T>::value, std::string >::type*; | |
class Serializer { | |
public: | |
Serializer() : mIsWriting(false), mpFile(nullptr) { } | |
~Serializer() { | |
if (mpFile != nullptr) { | |
fclose(mpFile); | |
mpFile = nullptr; | |
} | |
} | |
// * Writing methods... | |
template<class T, IsScalar<T> = nullptr> | |
void Write (const T& value) { | |
if (!mIsWriting) SwitchMode(); | |
fwrite(&value, sizeof(T), 1, mpFile); | |
} | |
template<class T, IsSerializable<T> = nullptr> | |
void Write (const T& value) { | |
if (!mIsWriting) SwitchMode(); | |
value.SaveTo(this); | |
} | |
template<class T, IsString<T> = nullptr> | |
void Write (const T& value) { | |
if (!mIsWriting) SwitchMode(); | |
int size = value.size(); | |
fwrite(&size, sizeof(int), 1, mpFile); | |
fwrite(value.c_str(), size, 1, mpFile); | |
} | |
// * Reading methods... | |
template<class T, IsScalar<T> = nullptr> | |
void Read (T &value) { | |
if (mIsWriting) SwitchMode(); | |
fread(&value, sizeof(T), 1, mpFile); | |
} | |
template<class T, IsSerializable<T> = nullptr> | |
void Read (T &value) { | |
if (mIsWriting) SwitchMode(); | |
value.LoadFrom(this); | |
} | |
template<class T, IsString<T> = nullptr> | |
void Read (T &value) { | |
if (mIsWriting) SwitchMode(); | |
int size; | |
fread(&size, sizeof(int), 1, mpFile); | |
char* tmp = new char[size+1]; | |
tmp[size] = '\0'; | |
fread(tmp, size, 1, mpFile); | |
value.assign(tmp); | |
delete[] tmp; | |
} | |
// * File methods | |
void SetFile (const std::string filename) { | |
mFilename = filename; | |
if (mIsWriting) | |
BeginWriteMode(); | |
else | |
BeginReadMode(); | |
} | |
void Close () { | |
fclose(mpFile); | |
mpFile = nullptr; | |
} | |
private: | |
void BeginWriteMode () { | |
mIsWriting = true; | |
if ( mpFile != nullptr) | |
Close(); | |
mpFile = fopen(mFilename.c_str(), "wb"); | |
if (mpFile == nullptr) | |
std::cerr << "[Serializer] Cannot open " << mFilename << " for writing!" << std::endl; | |
} | |
void BeginReadMode () { | |
mIsWriting = false; | |
if ( mpFile != nullptr) | |
Close(); | |
mpFile = fopen(mFilename.c_str(), "rb"); | |
if (mpFile == nullptr) | |
std::cerr << "[Serializer] Cannot open " << mFilename << " for reading!" << std::endl; | |
} | |
void SwitchMode () { | |
if (mFilename.size() > 0) { | |
if (mIsWriting) { | |
BeginReadMode(); | |
} else { | |
BeginWriteMode(); | |
} | |
} | |
} | |
private: | |
std::string mFilename; | |
bool mIsWriting; | |
FILE* mpFile; | |
}; | |
// EXAMPLE ////////////////////////////////////////////////// | |
class CharacterPlayer : public Serializable { | |
public: | |
CharacterPlayer() : kills(0), xp(0), name() {} | |
~CharacterPlayer() {} | |
public: | |
void SaveTo(Serializer *s) const { | |
s->Write(xp); | |
s->Write(name); | |
} | |
void LoadFrom(Serializer *s) { | |
s->Read(xp); | |
s->Read(name); | |
} | |
public: | |
int kills; | |
float xp; | |
std::string name; | |
}; | |
typedef struct _character_combat_stats { | |
unsigned int armorClass = 1; | |
unsigned int attackBase = 1; | |
float attackSpeed = 1; | |
} CharacterCombatStats; | |
class Character : public Serializable { | |
public: | |
Character() : health(10), speed(1.0f), player() {}; | |
~Character() {}; | |
public: | |
void SaveTo(Serializer *s) const { | |
s->Write(speed); | |
s->Write(combatStats.armorClass); | |
s->Write(combatStats.attackBase); | |
s->Write(combatStats.attackSpeed); | |
s->Write(player); | |
} | |
void LoadFrom(Serializer *s) { | |
s->Read(speed); | |
s->Read(combatStats.armorClass); | |
s->Read(combatStats.attackBase); | |
s->Read(combatStats.attackSpeed); | |
s->Read(player); | |
} | |
public: | |
int health; | |
float speed; | |
CharacterCombatStats combatStats; | |
CharacterPlayer player; | |
}; | |
std::ostream &operator<<(std::ostream &os, Character const &a) { | |
os << "Character:\n" << " * Player: " << a.player.name << " (" << a.player.xp << "xp/" << a.player.kills << "k)" << endl; | |
os << " * Health: " << a.health << "\n * Speed: " << a.speed << endl; | |
os << " * Combat Stats ===\n" << " * AC ~ " << a.combatStats.armorClass << endl; | |
os << " * AtkBase ~ " << a.combatStats.attackBase << endl; | |
os << " * AtkSpeed ~ " << a.combatStats.attackSpeed << endl; | |
return os; | |
} | |
int main (int argc, char const *argv[]) { | |
cout << "* Creating Character..." << endl; | |
Character a; | |
a.health = 20; | |
a.speed = 12.3f; | |
a.combatStats.armorClass = 12; | |
a.combatStats.attackBase = 4; | |
a.combatStats.attackSpeed = 1.337f; | |
a.player.name = "RageCX"; | |
a.player.xp = 125; | |
a.player.kills = 2; | |
cout << a; | |
cout << "* Creating Serializer..." << endl; | |
Serializer s; | |
s.SetFile("./char.crl"); | |
cout << "* Writing Character..." << endl; | |
a.SaveTo(&s); | |
s.Close(); | |
struct stat fstat; | |
stat("./char.crl", &fstat); | |
cout << "Size of file is " << fstat.st_size << endl; | |
cout << "* Reading back in new object..." << endl; | |
Serializer s2; | |
s2.SetFile("./char.crl"); | |
Character b; | |
b.LoadFrom(&s2); | |
cout << b; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TODO