sim: Move paramIn/Out definition to header file

This patch is moving the definitions of paramIn/Out templates to
the header file. In this way we gain:

1) We don't have to do explicit instantiation anymore for user defined
types. This spares us from including data type header files into
serialize.cc

2) We can overload show/parseParam for BitUnions or any other type
that requires special handling when serializing. Just by overloading
the two templates we get all the containers' (list, vector, array..)
serialization for free

2) gtest: With the idea of adding unit tests for Serializable objects,
we can avoid importing serialize.cc and just redefine Serializable
methods in the test source, implementing a Serializable stub

Change-Id: I45a9bb87d5ef886a3668fd477005cd105f612e36
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/13635
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
This commit is contained in:
Giacomo Travaglini
2018-10-17 17:17:48 +01:00
parent f3016e6846
commit 16bf103ad8
2 changed files with 481 additions and 592 deletions

View File

@@ -57,12 +57,8 @@
#include <string>
#include <vector>
#include "arch/generic/vec_reg.hh"
#include "base/framebuffer.hh"
#include "base/inifile.hh"
#include "base/logging.hh"
#include "base/output.hh"
#include "base/str.hh"
#include "base/trace.hh"
#include "debug/Checkpoint.hh"
#include "sim/eventq.hh"
@@ -75,412 +71,11 @@
using namespace std;
//
// The base implementations use to_number for parsing and '<<' for
// displaying, suitable for integer types.
//
template <class T>
bool
parseParam(const string &s, T &value)
{
return to_number(s, value);
}
template <class T>
void
showParam(CheckpointOut &os, const T &value)
{
os << value;
}
//
// Template specializations:
// - char (8-bit integer)
// - floating-point types
// - bool
// - string
//
// Treat 8-bit ints (chars) as ints on output, not as chars
template <>
void
showParam(CheckpointOut &os, const char &value)
{
os << (int)value;
}
template <>
void
showParam(CheckpointOut &os, const signed char &value)
{
os << (int)value;
}
template <>
void
showParam(CheckpointOut &os, const unsigned char &value)
{
os << (unsigned int)value;
}
template <>
bool
parseParam(const string &s, float &value)
{
return to_number(s, value);
}
template <>
bool
parseParam(const string &s, double &value)
{
return to_number(s, value);
}
template <>
bool
parseParam(const string &s, bool &value)
{
return to_bool(s, value);
}
// Display bools as strings
template <>
void
showParam(CheckpointOut &os, const bool &value)
{
os << (value ? "true" : "false");
}
// String requires no processing to speak of
template <>
bool
parseParam(const string &s, string &value)
{
value = s;
return true;
}
int Serializable::ckptMaxCount = 0;
int Serializable::ckptCount = 0;
int Serializable::ckptPrevCount = -1;
std::stack<std::string> Serializable::path;
template <class T>
void
paramOut(CheckpointOut &os, const string &name, const T &param)
{
os << name << "=";
showParam(os, param);
os << "\n";
}
template <class T>
void
arrayParamOut(CheckpointOut &os, const string &name, const vector<T> &param)
{
typename vector<T>::size_type size = param.size();
os << name << "=";
if (size > 0)
showParam(os, param[0]);
for (typename vector<T>::size_type i = 1; i < size; ++i) {
os << " ";
showParam(os, param[i]);
}
os << "\n";
}
template <class T>
void
arrayParamOut(CheckpointOut &os, const string &name, const list<T> &param)
{
typename list<T>::const_iterator it = param.begin();
os << name << "=";
if (param.size() > 0)
showParam(os, *it);
it++;
while (it != param.end()) {
os << " ";
showParam(os, *it);
it++;
}
os << "\n";
}
template <class T>
void
arrayParamOut(CheckpointOut &os, const string &name, const set<T> &param)
{
typename set<T>::const_iterator it = param.begin();
os << name << "=";
if (param.size() > 0)
showParam(os, *it);
it++;
while (it != param.end()) {
os << " ";
showParam(os, *it);
it++;
}
os << "\n";
}
template <class T>
void
paramIn(CheckpointIn &cp, const string &name, T &param)
{
const string &section(Serializable::currentSection());
string str;
if (!cp.find(section, name, str) || !parseParam(str, param)) {
fatal("Can't unserialize '%s:%s'\n", section, name);
}
}
template <class T>
bool
optParamIn(CheckpointIn &cp, const string &name, T &param, bool warn)
{
const string &section(Serializable::currentSection());
string str;
if (!cp.find(section, name, str) || !parseParam(str, param)) {
if (warn)
warn("optional parameter %s:%s not present\n", section, name);
return false;
} else {
return true;
}
}
template <class T>
void
arrayParamOut(CheckpointOut &os, const string &name,
const T *param, unsigned size)
{
os << name << "=";
if (size > 0)
showParam(os, param[0]);
for (unsigned i = 1; i < size; ++i) {
os << " ";
showParam(os, param[i]);
}
os << "\n";
}
template <class T>
void
arrayParamIn(CheckpointIn &cp, const string &name, T *param, unsigned size)
{
const string &section(Serializable::currentSection());
string str;
if (!cp.find(section, name, str)) {
fatal("Can't unserialize '%s:%s'\n", section, name);
}
// code below stolen from VectorParam<T>::parse().
// it would be nice to unify these somehow...
vector<string> tokens;
tokenize(tokens, str, ' ');
// Need this if we were doing a vector
// value.resize(tokens.size());
if (tokens.size() != size) {
fatal("Array size mismatch on %s:%s'\n", section, name);
}
for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
// need to parse into local variable to handle vector<bool>,
// for which operator[] returns a special reference class
// that's not the same as 'bool&', (since it's a packed
// vector)
T scalar_value;
if (!parseParam(tokens[i], scalar_value)) {
string err("could not parse \"");
err += str;
err += "\"";
fatal(err);
}
// assign parsed value to vector
param[i] = scalar_value;
}
}
template <class T>
void
arrayParamIn(CheckpointIn &cp, const string &name, vector<T> &param)
{
const string &section(Serializable::currentSection());
string str;
if (!cp.find(section, name, str)) {
fatal("Can't unserialize '%s:%s'\n", section, name);
}
// code below stolen from VectorParam<T>::parse().
// it would be nice to unify these somehow...
vector<string> tokens;
tokenize(tokens, str, ' ');
// Need this if we were doing a vector
// value.resize(tokens.size());
param.resize(tokens.size());
for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
// need to parse into local variable to handle vector<bool>,
// for which operator[] returns a special reference class
// that's not the same as 'bool&', (since it's a packed
// vector)
T scalar_value;
if (!parseParam(tokens[i], scalar_value)) {
string err("could not parse \"");
err += str;
err += "\"";
fatal(err);
}
// assign parsed value to vector
param[i] = scalar_value;
}
}
template <class T>
void
arrayParamIn(CheckpointIn &cp, const string &name, list<T> &param)
{
const string &section(Serializable::currentSection());
string str;
if (!cp.find(section, name, str)) {
fatal("Can't unserialize '%s:%s'\n", section, name);
}
param.clear();
vector<string> tokens;
tokenize(tokens, str, ' ');
for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
T scalar_value;
if (!parseParam(tokens[i], scalar_value)) {
string err("could not parse \"");
err += str;
err += "\"";
fatal(err);
}
// assign parsed value to vector
param.push_back(scalar_value);
}
}
template <class T>
void
arrayParamIn(CheckpointIn &cp, const string &name, set<T> &param)
{
const string &section(Serializable::currentSection());
string str;
if (!cp.find(section, name, str)) {
fatal("Can't unserialize '%s:%s'\n", section, name);
}
param.clear();
vector<string> tokens;
tokenize(tokens, str, ' ');
for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
T scalar_value;
if (!parseParam(tokens[i], scalar_value)) {
string err("could not parse \"");
err += str;
err += "\"";
fatal(err);
}
// assign parsed value to vector
param.insert(scalar_value);
}
}
void
objParamIn(CheckpointIn &cp, const string &name, SimObject * &param)
{
const string &section(Serializable::currentSection());
if (!cp.findObj(section, name, param)) {
fatal("Can't unserialize '%s:%s'\n", section, name);
}
}
#define INSTANTIATE_PARAM_TEMPLATES(type) \
template void \
paramOut(CheckpointOut &os, const string &name, type const &param); \
template void \
paramIn(CheckpointIn &cp, const string &name, type & param); \
template bool \
optParamIn(CheckpointIn &cp, const string &name, type & param, \
bool warn); \
template void \
arrayParamOut(CheckpointOut &os, const string &name, \
type const *param, unsigned size); \
template void \
arrayParamIn(CheckpointIn &cp, const string &name, \
type *param, unsigned size); \
template void \
arrayParamOut(CheckpointOut &os, const string &name, \
const vector<type> &param); \
template void \
arrayParamIn(CheckpointIn &cp, const string &name, \
vector<type> &param); \
template void \
arrayParamOut(CheckpointOut &os, const string &name, \
const list<type> &param); \
template void \
arrayParamIn(CheckpointIn &cp, const string &name, \
list<type> &param);
INSTANTIATE_PARAM_TEMPLATES(char)
INSTANTIATE_PARAM_TEMPLATES(signed char)
INSTANTIATE_PARAM_TEMPLATES(unsigned char)
INSTANTIATE_PARAM_TEMPLATES(signed short)
INSTANTIATE_PARAM_TEMPLATES(unsigned short)
INSTANTIATE_PARAM_TEMPLATES(signed int)
INSTANTIATE_PARAM_TEMPLATES(unsigned int)
INSTANTIATE_PARAM_TEMPLATES(signed long)
INSTANTIATE_PARAM_TEMPLATES(unsigned long)
INSTANTIATE_PARAM_TEMPLATES(signed long long)
INSTANTIATE_PARAM_TEMPLATES(unsigned long long)
INSTANTIATE_PARAM_TEMPLATES(bool)
INSTANTIATE_PARAM_TEMPLATES(float)
INSTANTIATE_PARAM_TEMPLATES(double)
INSTANTIATE_PARAM_TEMPLATES(string)
INSTANTIATE_PARAM_TEMPLATES(Pixel)
INSTANTIATE_PARAM_TEMPLATES(VecRegContainer<8>)
INSTANTIATE_PARAM_TEMPLATES(VecRegContainer<16>)
// set is only used with strings and furthermore doesn't agree with Pixel
template void
arrayParamOut(CheckpointOut &, const string &, const set<string> &);
template void
arrayParamIn(CheckpointIn &, const string &, set<string> &);
/////////////////////////////
/// Container for serializing global variables (not associated with
@@ -645,12 +240,6 @@ Serializable::ScopedCheckpointSection::nameOut(CheckpointOut &cp)
cp << "\n[" << Serializable::currentSection() << "]\n";
}
void
debug_serialize(const string &cpt_dir)
{
Serializable::serializeAll(cpt_dir);
}
const std::string &
Serializable::currentSection()
{
@@ -681,7 +270,6 @@ CheckpointIn::dir()
return currentDirectory;
}
CheckpointIn::CheckpointIn(const string &cpt_dir, SimObjectResolver &resolver)
: db(new IniFile), objNameResolver(resolver), cptDir(setDir(cpt_dir))
{
@@ -708,7 +296,6 @@ CheckpointIn::find(const string &section, const string &entry, string &value)
return db->find(section, entry, value);
}
bool
CheckpointIn::findObj(const string &section, const string &entry,
SimObject *&value)
@@ -722,9 +309,23 @@ CheckpointIn::findObj(const string &section, const string &entry,
return true;
}
bool
CheckpointIn::sectionExists(const string &section)
{
return db->sectionExists(section);
}
void
objParamIn(CheckpointIn &cp, const string &name, SimObject * &param)
{
const string &section(Serializable::currentSection());
if (!cp.findObj(section, name, param)) {
fatal("Can't unserialize '%s:%s'\n", section, name);
}
}
void
debug_serialize(const string &cpt_dir)
{
Serializable::serializeAll(cpt_dir);
}

View File

@@ -60,166 +60,65 @@
#include <vector>
#include "base/bitunion.hh"
#include "base/logging.hh"
#include "base/str.hh"
class CheckpointIn;
class IniFile;
class Serializable;
class SimObject;
class SimObjectResolver;
typedef std::ostream CheckpointOut;
template <class T>
void paramOut(CheckpointOut &cp, const std::string &name, const T &param);
template <typename T>
void
paramOut(CheckpointOut &cp, const std::string &name, const BitUnionType<T> &p)
class CheckpointIn
{
paramOut(cp, name, static_cast<BitUnionBaseType<T> >(p));
}
private:
template <class T>
void paramIn(CheckpointIn &cp, const std::string &name, T &param);
IniFile *db;
template <typename T>
void
paramIn(CheckpointIn &cp, const std::string &name, BitUnionType<T> &p)
{
BitUnionBaseType<T> b;
paramIn(cp, name, b);
p = b;
}
SimObjectResolver &objNameResolver;
template <class T>
bool optParamIn(CheckpointIn &cp, const std::string &name, T &param,
bool warn = true);
public:
CheckpointIn(const std::string &cpt_dir, SimObjectResolver &resolver);
~CheckpointIn();
template <typename T>
bool
optParamIn(CheckpointIn &cp, const std::string &name,
BitUnionType<T> &p, bool warn = true)
{
BitUnionBaseType<T> b;
if (optParamIn(cp, name, b, warn)) {
p = b;
return true;
} else {
return false;
}
}
const std::string cptDir;
template <class T>
void arrayParamOut(CheckpointOut &cp, const std::string &name,
const T *param, unsigned size);
bool find(const std::string &section, const std::string &entry,
std::string &value);
template <class T>
void arrayParamOut(CheckpointOut &cp, const std::string &name,
const std::vector<T> &param);
bool findObj(const std::string &section, const std::string &entry,
SimObject *&value);
template <class T>
void arrayParamOut(CheckpointOut &cp, const std::string &name,
const std::list<T> &param);
template <class T>
void arrayParamOut(CheckpointOut &cp, const std::string &name,
const std::set<T> &param);
bool entryExists(const std::string &section, const std::string &entry);
bool sectionExists(const std::string &section);
template <class T>
void arrayParamIn(CheckpointIn &cp, const std::string &name,
T *param, unsigned size);
// The following static functions have to do with checkpoint
// creation rather than restoration. This class makes a handy
// namespace for them though. Currently no Checkpoint object is
// created on serialization (only unserialization) so we track the
// directory name as a global. It would be nice to change this
// someday
template <class T>
void arrayParamIn(CheckpointIn &cp, const std::string &name,
std::vector<T> &param);
private:
// current directory we're serializing into.
static std::string currentDirectory;
template <class T>
void arrayParamIn(CheckpointIn &cp, const std::string &name,
std::list<T> &param);
public:
// Set the current directory. This function takes care of
// inserting curTick() if there's a '%d' in the argument, and
// appends a '/' if necessary. The final name is returned.
static std::string setDir(const std::string &base_name);
template <class T>
void arrayParamIn(CheckpointIn &cp, const std::string &name,
std::set<T> &param);
// Export current checkpoint directory name so other objects can
// derive filenames from it (e.g., memory). The return value is
// guaranteed to end in '/' so filenames can be directly appended.
// This function is only valid while a checkpoint is being created.
static std::string dir();
void
objParamIn(CheckpointIn &cp, const std::string &name, SimObject * &param);
template <class T>
static void
arrayParamOut(CheckpointOut &cp, const std::string &name,
const BitUnionType<T> *param, unsigned size)
{
// We copy the array into a vector. This is needed since we cannot
// directly typecast a pointer to BitUnionType<T> into a pointer
// of BitUnionBaseType<T> but we can typecast BitUnionType<T>
// to BitUnionBaseType<T> since we overloaded the typecast operator
std::vector<BitUnionBaseType<T>> bitunion_vec(param, param + size);
arrayParamOut(cp, name, bitunion_vec);
}
template <class T>
static void
arrayParamIn(CheckpointIn &cp, const std::string &name,
BitUnionType<T> *param, unsigned size)
{
std::vector<BitUnionBaseType<T>> bitunion_vec(size);
arrayParamIn(cp, name, bitunion_vec);
std::copy(bitunion_vec.begin(), bitunion_vec.end(), param);
}
//
// These macros are streamlined to use in serialize/unserialize
// functions. It's assumed that serialize() has a parameter 'os' for
// the ostream, and unserialize() has parameters 'cp' and 'section'.
#define SERIALIZE_SCALAR(scalar) paramOut(cp, #scalar, scalar)
#define UNSERIALIZE_SCALAR(scalar) paramIn(cp, #scalar, scalar)
#define UNSERIALIZE_OPT_SCALAR(scalar) optParamIn(cp, #scalar, scalar)
// ENUMs are like SCALARs, but we cast them to ints on the way out
#define SERIALIZE_ENUM(scalar) paramOut(cp, #scalar, (int)scalar)
#define UNSERIALIZE_ENUM(scalar) \
do { \
int tmp; \
paramIn(cp, #scalar, tmp); \
scalar = static_cast<decltype(scalar)>(tmp); \
} while (0)
#define SERIALIZE_ARRAY(member, size) \
arrayParamOut(cp, #member, member, size)
#define UNSERIALIZE_ARRAY(member, size) \
arrayParamIn(cp, #member, member, size)
#define SERIALIZE_CONTAINER(member) \
arrayParamOut(cp, #member, member)
#define UNSERIALIZE_CONTAINER(member) \
arrayParamIn(cp, #member, member)
#define SERIALIZE_EVENT(event) event.serializeSection(cp, #event);
#define UNSERIALIZE_EVENT(event) \
do { \
event.unserializeSection(cp, #event); \
eventQueue()->checkpointReschedule(&event); \
} while (0)
#define SERIALIZE_OBJ(obj) obj.serializeSection(cp, #obj)
#define UNSERIALIZE_OBJ(obj) obj.unserializeSection(cp, #obj)
#define SERIALIZE_OBJPTR(objptr) paramOut(cp, #objptr, (objptr)->name())
#define UNSERIALIZE_OBJPTR(objptr) \
do { \
SimObject *sptr; \
objParamIn(cp, #objptr, sptr); \
objptr = dynamic_cast<decltype(objptr)>(sptr); \
} while (0)
// Filename for base checkpoint file within directory.
static const char *baseFilename;
};
/**
* Basic support for object serialization.
@@ -368,58 +267,447 @@ class Serializable
static std::stack<std::string> path;
};
void debug_serialize(const std::string &cpt_dir);
class CheckpointIn
//
// The base implementations use to_number for parsing and '<<' for
// displaying, suitable for integer types.
//
template <class T>
bool
parseParam(const std::string &s, T &value)
{
private:
return to_number(s, value);
}
IniFile *db;
template <class T>
void
showParam(CheckpointOut &os, const T &value)
{
os << value;
}
SimObjectResolver &objNameResolver;
// Treat 8-bit ints (chars) as ints on output, not as chars
template <>
inline void
showParam(CheckpointOut &os, const char &value)
{
os << (int)value;
}
public:
CheckpointIn(const std::string &cpt_dir, SimObjectResolver &resolver);
~CheckpointIn();
template <>
inline void
showParam(CheckpointOut &os, const signed char &value)
{
os << (int)value;
}
const std::string cptDir;
template <>
inline void
showParam(CheckpointOut &os, const unsigned char &value)
{
os << (unsigned int)value;
}
bool find(const std::string &section, const std::string &entry,
std::string &value);
template <>
inline bool
parseParam(const std::string &s, float &value)
{
return to_number(s, value);
}
bool findObj(const std::string &section, const std::string &entry,
SimObject *&value);
template <>
inline bool
parseParam(const std::string &s, double &value)
{
return to_number(s, value);
}
template <>
inline bool
parseParam(const std::string &s, bool &value)
{
return to_bool(s, value);
}
// Display bools as strings
template <>
inline void
showParam(CheckpointOut &os, const bool &value)
{
os << (value ? "true" : "false");
}
// String requires no processing to speak of
template <>
inline bool
parseParam(const std::string &s, std::string &value)
{
value = s;
return true;
}
template <class T>
void
paramOut(CheckpointOut &os, const std::string &name, const T &param)
{
os << name << "=";
showParam(os, param);
os << "\n";
}
template <typename T>
void
paramOut(CheckpointOut &cp, const std::string &name, const BitUnionType<T> &p)
{
paramOut(cp, name, static_cast<BitUnionBaseType<T> >(p));
}
template <class T>
void
paramIn(CheckpointIn &cp, const std::string &name, T &param)
{
const std::string &section(Serializable::currentSection());
std::string str;
if (!cp.find(section, name, str) || !parseParam(str, param)) {
fatal("Can't unserialize '%s:%s'\n", section, name);
}
}
template <typename T>
void
paramIn(CheckpointIn &cp, const std::string &name, BitUnionType<T> &p)
{
BitUnionBaseType<T> b;
paramIn(cp, name, b);
p = b;
}
template <class T>
bool
optParamIn(CheckpointIn &cp, const std::string &name,
T &param, bool warn = true)
{
const std::string &section(Serializable::currentSection());
std::string str;
if (!cp.find(section, name, str) || !parseParam(str, param)) {
if (warn)
warn("optional parameter %s:%s not present\n", section, name);
return false;
} else {
return true;
}
}
template <typename T>
bool
optParamIn(CheckpointIn &cp, const std::string &name,
BitUnionType<T> &p, bool warn = true)
{
BitUnionBaseType<T> b;
if (optParamIn(cp, name, b, warn)) {
p = b;
return true;
} else {
return false;
}
}
template <class T>
void
arrayParamOut(CheckpointOut &os, const std::string &name,
const std::vector<T> &param)
{
typename std::vector<T>::size_type size = param.size();
os << name << "=";
if (size > 0)
showParam(os, param[0]);
for (typename std::vector<T>::size_type i = 1; i < size; ++i) {
os << " ";
showParam(os, param[i]);
}
os << "\n";
}
template <class T>
void
arrayParamOut(CheckpointOut &os, const std::string &name,
const std::list<T> &param)
{
typename std::list<T>::const_iterator it = param.begin();
os << name << "=";
if (param.size() > 0)
showParam(os, *it);
it++;
while (it != param.end()) {
os << " ";
showParam(os, *it);
it++;
}
os << "\n";
}
template <class T>
void
arrayParamOut(CheckpointOut &os, const std::string &name,
const std::set<T> &param)
{
typename std::set<T>::const_iterator it = param.begin();
os << name << "=";
if (param.size() > 0)
showParam(os, *it);
it++;
while (it != param.end()) {
os << " ";
showParam(os, *it);
it++;
}
os << "\n";
}
template <class T>
void
arrayParamOut(CheckpointOut &os, const std::string &name,
const T *param, unsigned size)
{
os << name << "=";
if (size > 0)
showParam(os, param[0]);
for (unsigned i = 1; i < size; ++i) {
os << " ";
showParam(os, param[i]);
}
os << "\n";
}
bool entryExists(const std::string &section, const std::string &entry);
bool sectionExists(const std::string &section);
template <class T>
void
arrayParamIn(CheckpointIn &cp, const std::string &name,
T *param, unsigned size)
{
const std::string &section(Serializable::currentSection());
std::string str;
if (!cp.find(section, name, str)) {
fatal("Can't unserialize '%s:%s'\n", section, name);
}
// The following static functions have to do with checkpoint
// creation rather than restoration. This class makes a handy
// namespace for them though. Currently no Checkpoint object is
// created on serialization (only unserialization) so we track the
// directory name as a global. It would be nice to change this
// someday
// code below stolen from VectorParam<T>::parse().
// it would be nice to unify these somehow...
private:
// current directory we're serializing into.
static std::string currentDirectory;
std::vector<std::string> tokens;
public:
// Set the current directory. This function takes care of
// inserting curTick() if there's a '%d' in the argument, and
// appends a '/' if necessary. The final name is returned.
static std::string setDir(const std::string &base_name);
tokenize(tokens, str, ' ');
// Export current checkpoint directory name so other objects can
// derive filenames from it (e.g., memory). The return value is
// guaranteed to end in '/' so filenames can be directly appended.
// This function is only valid while a checkpoint is being created.
static std::string dir();
// Need this if we were doing a vector
// value.resize(tokens.size());
// Filename for base checkpoint file within directory.
static const char *baseFilename;
};
if (tokens.size() != size) {
fatal("Array size mismatch on %s:%s'\n", section, name);
}
for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
// need to parse into local variable to handle vector<bool>,
// for which operator[] returns a special reference class
// that's not the same as 'bool&', (since it's a packed
// vector)
T scalar_value;
if (!parseParam(tokens[i], scalar_value)) {
std::string err("could not parse \"");
err += str;
err += "\"";
fatal(err);
}
// assign parsed value to vector
param[i] = scalar_value;
}
}
template <class T>
void
arrayParamIn(CheckpointIn &cp, const std::string &name, std::vector<T> &param)
{
const std::string &section(Serializable::currentSection());
std::string str;
if (!cp.find(section, name, str)) {
fatal("Can't unserialize '%s:%s'\n", section, name);
}
// code below stolen from VectorParam<T>::parse().
// it would be nice to unify these somehow...
std::vector<std::string> tokens;
tokenize(tokens, str, ' ');
// Need this if we were doing a vector
// value.resize(tokens.size());
param.resize(tokens.size());
for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
// need to parse into local variable to handle vector<bool>,
// for which operator[] returns a special reference class
// that's not the same as 'bool&', (since it's a packed
// vector)
T scalar_value;
if (!parseParam(tokens[i], scalar_value)) {
std::string err("could not parse \"");
err += str;
err += "\"";
fatal(err);
}
// assign parsed value to vector
param[i] = scalar_value;
}
}
template <class T>
void
arrayParamIn(CheckpointIn &cp, const std::string &name, std::list<T> &param)
{
const std::string &section(Serializable::currentSection());
std::string str;
if (!cp.find(section, name, str)) {
fatal("Can't unserialize '%s:%s'\n", section, name);
}
param.clear();
std::vector<std::string> tokens;
tokenize(tokens, str, ' ');
for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
T scalar_value;
if (!parseParam(tokens[i], scalar_value)) {
std::string err("could not parse \"");
err += str;
err += "\"";
fatal(err);
}
// assign parsed value to vector
param.push_back(scalar_value);
}
}
template <class T>
void
arrayParamIn(CheckpointIn &cp, const std::string &name, std::set<T> &param)
{
const std::string &section(Serializable::currentSection());
std::string str;
if (!cp.find(section, name, str)) {
fatal("Can't unserialize '%s:%s'\n", section, name);
}
param.clear();
std::vector<std::string> tokens;
tokenize(tokens, str, ' ');
for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
T scalar_value;
if (!parseParam(tokens[i], scalar_value)) {
std::string err("could not parse \"");
err += str;
err += "\"";
fatal(err);
}
// assign parsed value to vector
param.insert(scalar_value);
}
}
template <class T>
static void
arrayParamOut(CheckpointOut &cp, const std::string &name,
const BitUnionType<T> *param, unsigned size)
{
// We copy the array into a vector. This is needed since we cannot
// directly typecast a pointer to BitUnionType<T> into a pointer
// of BitUnionBaseType<T> but we can typecast BitUnionType<T>
// to BitUnionBaseType<T> since we overloaded the typecast operator
std::vector<BitUnionBaseType<T>> bitunion_vec(param, param + size);
arrayParamOut(cp, name, bitunion_vec);
}
template <class T>
static void
arrayParamIn(CheckpointIn &cp, const std::string &name,
BitUnionType<T> *param, unsigned size)
{
std::vector<BitUnionBaseType<T>> bitunion_vec(size);
arrayParamIn(cp, name, bitunion_vec);
std::copy(bitunion_vec.begin(), bitunion_vec.end(), param);
}
void
debug_serialize(const std::string &cpt_dir);
void
objParamIn(CheckpointIn &cp, const std::string &name, SimObject * &param);
//
// These macros are streamlined to use in serialize/unserialize
// functions. It's assumed that serialize() has a parameter 'os' for
// the ostream, and unserialize() has parameters 'cp' and 'section'.
#define SERIALIZE_SCALAR(scalar) paramOut(cp, #scalar, scalar)
#define UNSERIALIZE_SCALAR(scalar) paramIn(cp, #scalar, scalar)
#define UNSERIALIZE_OPT_SCALAR(scalar) optParamIn(cp, #scalar, scalar)
// ENUMs are like SCALARs, but we cast them to ints on the way out
#define SERIALIZE_ENUM(scalar) paramOut(cp, #scalar, (int)scalar)
#define UNSERIALIZE_ENUM(scalar) \
do { \
int tmp; \
paramIn(cp, #scalar, tmp); \
scalar = static_cast<decltype(scalar)>(tmp); \
} while (0)
#define SERIALIZE_ARRAY(member, size) \
arrayParamOut(cp, #member, member, size)
#define UNSERIALIZE_ARRAY(member, size) \
arrayParamIn(cp, #member, member, size)
#define SERIALIZE_CONTAINER(member) \
arrayParamOut(cp, #member, member)
#define UNSERIALIZE_CONTAINER(member) \
arrayParamIn(cp, #member, member)
#define SERIALIZE_EVENT(event) event.serializeSection(cp, #event);
#define UNSERIALIZE_EVENT(event) \
do { \
event.unserializeSection(cp, #event); \
eventQueue()->checkpointReschedule(&event); \
} while (0)
#define SERIALIZE_OBJ(obj) obj.serializeSection(cp, #obj)
#define UNSERIALIZE_OBJ(obj) obj.unserializeSection(cp, #obj)
#define SERIALIZE_OBJPTR(objptr) paramOut(cp, #objptr, (objptr)->name())
#define UNSERIALIZE_OBJPTR(objptr) \
do { \
SimObject *sptr; \
objParamIn(cp, #objptr, sptr); \
objptr = dynamic_cast<decltype(objptr)>(sptr); \
} while (0)
#endif // __SERIALIZE_HH__