Files
mlpack/fastlib2/fastlib/base/otrav_impl.h
T
2008-04-07 23:07:18 +00:00

1332 lines
31 KiB
C++

// Copyright 2007 Georgia Institute of Technology. All rights reserved.
/**
* otrav_impl.h (this file not included by Doxygen)
*
* Default definitions for untraversed types, printer formats, and
* traversal implementations.
*/
#ifndef NEED_OTRAV_IMPL
#error Include base/otrav.h instead of this file.
#endif
#include <typeinfo>
template<typename T>
inline void OT__BecomeNonAlias(T *ot__obj) {}
template<typename T>
inline void OT__BecomeAlias(T *ot__obj) {
DEBUG_ONLY(NONFATAL(
"Aliasing non-aliasable %s; may double-destruct.",
typeid(T).name()));
}
template<typename T>
inline bool OT__IsAlias(T *ot__obj) { return false; }
template<typename T>
inline bool OT__Aliasable(const T *ot__obj) { return false; }
template<typename T>
inline void OT__DefaultConstruct(T *ot__obj) {
if (OT__Aliasable(ot__obj)) {
OT__BecomeAlias(ot__obj);
}
}
template<typename T>
inline bool OT__DebugInitOK(T *ot__obj) {
return !OT__Aliasable(ot__obj) || OT__IsAlias(ot__obj);
}
template<typename T>
inline bool OT__DebugModifyOK(T *ot__obj) {
return !OT__Aliasable(ot__obj) || !OT__IsAlias(ot__obj);
}
template<typename T>
inline void OT__RefillTransients(T *ot__obj) {
OT__BecomeNonAlias(ot__obj);
}
template<typename T, typename TVisitor>
inline void OT__TraverseTransients(T *ot__obj, TVisitor *ot__visitor) {}
template<typename T, typename TVisitor>
inline bool OT__PreTraverse(T *ot__dest, const T *ot__src,
index_t ot__len, TVisitor *ot__visitor) {
return ot__visitor->PreUntraversed(ot__dest, ot__src, ot__len);
}
template<typename T, typename TVisitor>
inline void OT__TraverseObject(T *ot__obj, TVisitor *ot__visitor) {
ot__visitor->Untraversed(ot__obj);
}
template<typename T>
inline bool OT__Shallow(const T *ot__obj) { return false; }
#define OT__MAKE_SHALLOW(T, TF) \
template<> \
inline bool OT__Shallow< T >(const T *ot__obj) { return true; }
FOR_ALL_PRIMITIVES_DO(OT__MAKE_SHALLOW)
template<typename T>
inline bool OT__Shallow(const T *const *ot__obj) { return true; }
#undef OT__MAKE_SHALLOW
template<typename T>
inline bool OT__ShallowOrPtr(T *const *ot__obj) { return true; }
template<typename T>
inline bool OT__ShallowOrPtr(const T *ot__obj) {
return OT__Shallow(ot__obj);
}
template<typename T>
inline bool OT__NonConstPtr(const T *ot__obj) {
return OT__ShallowOrPtr(ot__obj) && !OT__Shallow(ot__obj);
}
namespace ot {
/**
* Defines the print format exemplified by:
* @code
* name : object_type =
* {
* member : primitive_type = value
* array : len n array_type =
* {
* [0] : elem_type = ...
* ...
* }
* }
* @endcode
*/
class StandardFormat {
FORBID_ACCIDENTAL_COPIES(StandardFormat);
private:
FILE *stream_;
int indent_;
public:
StandardFormat(FILE *stream) {
stream_ = stream;
indent_ = 0;
}
private:
void PrintIndent_();
void PrintHeader_(const char *name, index_t index,
const char *type, index_t len);
public:
void Untraversed(const unsigned char *obj, size_t bytes);
#define STANDARD_FORMAT__PRIMITIVE(T, TF) \
void Primitive(const char *name, index_t index, \
const char *type, T val);
FOR_ALL_PRIMITIVES_DO(STANDARD_FORMAT__PRIMITIVE)
#undef STANDARD_FORMAT__PRIMITIVE
void Str(const char *name, index_t index,
const char *type, const char *str);
void Ptr(const char *name, index_t index,
const char *type, ptrdiff_t ptr);
void Open(const char *name, index_t index,
const char *type, index_t len = -1);
void Close(const char *name, const char *type);
};
/**
* Defines the print format exemplified by:
* @code
* <object_type name="name">
* <primitive_type name="member">value</primitive_type>
* <array_type name="array" len="n">
* <elem_type index="0">...</elem_type>
* ...
* </array_type>
* </object_type>
* @endcode
*/
class XMLFormat {
FORBID_ACCIDENTAL_COPIES(XMLFormat);
private:
FILE *stream_;
int indent_;
public:
XMLFormat(FILE *stream) {
stream_ = stream;
indent_ = 0;
}
private:
void PrintIndent_();
void PrintHeader_(const char *name, index_t index,
const char *type, index_t len);
void PrintFooter_(const char *type);
public:
void Untraversed(const unsigned char *obj, size_t bytes);
#define XML_FORMAT__PRIMITIVE(T, TF) \
void Primitive(const char *name, index_t index, \
const char *type, T val);
FOR_ALL_PRIMITIVES_DO(XML_FORMAT__PRIMITIVE)
#undef XML_FORMAT__PRIMITIVE
void Str(const char *name, index_t index,
const char *type, const char *str);
void Ptr(const char *name, index_t index,
const char *type, ptrdiff_t ptr);
void Open(const char *name, index_t index,
const char *type, index_t len = -1);
void Close(const char *name, const char *type);
};
};
namespace ot__private {
/**
* Traversal handler for pretty-printing objects.
*/
template<typename TPrintFormat>
class Printer {
FORBID_ACCIDENTAL_COPIES(Printer)
private:
TPrintFormat format_;
const char *name_;
const char *type_;
ptrdiff_t array_;
index_t index_;
public:
enum { IS_PRINTER = 1 };
template<typename T>
Printer(const T &obj, const char *name, FILE *stream)
: format_(stream) {
name_ = name;
type_ = typeid(obj).name();
array_ = 0;
index_ = -1;
Obj(const_cast<T &>(obj));
}
template<typename T>
void ElemOf(const T *array) {
array_ = mem::PtrAbsAddr(array);
}
template<typename T>
void Name(const char *name, const T &obj) {
name_ = name;
type_ = typeid(obj).name();
if (array_) {
index_ = &obj - reinterpret_cast<const T *>(array_);
array_ = 0;
} else {
index_ = -1;
}
}
template<typename T>
bool PreUntraversed(T *dest, const T *src, index_t len) { return false; }
template<typename T>
bool PreTraverse(T *dest, const T *src, index_t len) { return false; }
template<typename T>
void Untraversed(T &obj) {
format_.Untraversed(
reinterpret_cast<const unsigned char *>(&obj), sizeof(T));
}
#define PRINTER__PRIMITIVE_OBJ(T, TF) \
void Obj(T val) { \
format_.Primitive(name_, index_, type_, val); \
}
FOR_ALL_PRIMITIVES_DO(PRINTER__PRIMITIVE_OBJ)
#undef PRINTER__PRIMITIVE_OBJ
void Obj(const char *str) {
format_.Str(name_, index_, type_, str);
}
template<typename T>
void Obj(T *ptr) {
format_.Ptr(name_, index_, type_, mem::PtrAbsAddr(ptr));
}
template<typename T>
void Obj(T &obj) {
const char *name = name_;
const char *type = type_;
format_.Open(name, index_, type);
OT__TraverseObject(&obj, this);
format_.Close(name, type);
}
template<typename T>
bool PreStaticArray(T *ptr, index_t len) {
format_.Open(name_, index_, type_, len);
return true;
}
template<typename T>
void PostStaticArray(T *ptr, index_t len) {
format_.Close(name_, type_);
}
template<typename T>
bool PreArray(T *ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
if (nullable && ptr == NULL) {
format_.Ptr(name_, index_, type_, 0);
return false;
} else {
return PreStaticArray(ptr, len);
}
}
template<typename T>
void PostArray(T *ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
PostStaticArray(ptr, len);
}
void Str(const char *str, bool nullable, bool alloc) {
format_.Str(name_, index_, type_, str);
}
};
/**
* Traversal handler for debug-poisoning objects' transients.
*/
template<bool t_semi>
class TransientUnstructor {
FORBID_ACCIDENTAL_COPIES(TransientUnstructor)
public:
enum { IS_PRINTER = 0 };
template<typename T>
TransientUnstructor(T *obj) {
OT__TraverseTransients(obj, this);
}
template<typename T>
void ElemOf(const T *array) {}
template<typename T>
void Name(const char *name, const T &obj) {}
template<typename T>
bool PreUntraversed(T *dest, const T *src, index_t len) { return false; }
template<typename T>
bool PreTraverse(T *dest, const T *src, index_t len) { return false; }
template<typename T>
void Untraversed(T &obj) {}
template<typename T>
void Obj(T *&ptr) {
DEBUG_POISON_PTR(ptr);
}
template<typename T>
void Obj(T &obj) {
if (OT__Shallow(&obj)) {
mem::DebugPoison(&obj);
} else if (t_semi) {
mem::Construct(&obj);
}
}
template<typename T>
bool PreStaticArray(T *ptr, index_t len) {
if (OT__Shallow(ptr)) {
mem::DebugPoison(ptr, len);
} else if (t_semi) {
mem::Construct(ptr, len);
}
return false;
}
template<typename T>
bool PreStaticArray(T **ptr, index_t len) {
return true;
}
template<typename T>
void PostStaticArray(T *ptr, index_t len) {}
template<typename T>
bool PreArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
DEBUG_ASSERT(!unitary || len == 1);
if (nullable) {
ptr = NULL;
} else {
DEBUG_POISON_PTR(ptr);
}
return false;
}
template<typename T>
void PostArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {}
void Str(char *&str, bool nullable, bool alloc) {
if (nullable) {
str = NULL;
} else {
DEBUG_POISON_PTR(str);
}
}
};
/**
* Traversal handler for debug-poisoning objects and setting
* nullable pointers to NULL.
*/
class Unstructor {
FORBID_ACCIDENTAL_COPIES(Unstructor)
public:
enum { IS_PRINTER = 0 };
template<typename T>
Unstructor(T *obj) {
OT__TraverseObject(obj, this);
TransientUnstructor<false> ot__unstructor(&obj);
}
template<typename T>
void ElemOf(const T *array) {}
template<typename T>
void Name(const char *name, const T &obj) {}
template<typename T>
bool PreUntraversed(T *dest, const T *src, index_t len) { return false; }
template<typename T>
bool PreTraverse(T *dest, const T *src, index_t len) { return false; }
template<typename T>
void Untraversed(T &obj) {}
template<typename T>
void Obj(T *&ptr) {
DEBUG_POISON_PTR(ptr);
}
template<typename T>
void Obj(T &obj) {
if (OT__Shallow(&obj)) {
mem::DebugPoison(&obj);
}
}
template<typename T>
bool PreStaticArray(T *ptr, index_t len) {
if (OT__Shallow(ptr)) {
mem::DebugPoison(ptr, len);
}
return false;
}
template<typename T>
bool PreStaticArray(T **ptr, index_t len) {
return true;
}
template<typename T>
void PostStaticArray(T *ptr, index_t len) {}
template<typename T>
bool PreArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
DEBUG_ASSERT(!unitary || len == 1);
if (nullable) {
ptr = NULL;
} else {
DEBUG_POISON_PTR(ptr);
}
return false;
}
template<typename T>
void PostArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {}
void Str(char *&str, bool nullable, bool alloc) {
if (nullable) {
str = NULL;
} else {
DEBUG_POISON_PTR(str);
}
}
};
/**
* Traversal handler for freeing objects' transient memory.
*/
template<bool t_semi>
class TransientDestructor {
FORBID_ACCIDENTAL_COPIES(TransientDestructor)
public:
enum { IS_PRINTER = 0 };
template<typename T>
TransientDestructor(T *obj) {
OT__TraverseTransients(obj, this);
}
template<typename T>
void ElemOf(const T *array) {}
template<typename T>
void Name(const char *name, const T &obj) {}
template<typename T>
bool PreUntraversed(T *dest, const T *src, index_t len) {
if (OT__Shallow(dest)) {
mem::DebugPoison(dest, len);
}
return OT__NonConstPtr(dest);
}
template<typename T>
bool PreTraverse(T *dest, const T *src, index_t len) {
return false;
}
template<typename T>
void Untraversed(T &obj) {}
template<typename T>
void Obj(T &obj) {
if (t_semi && !OT__ShallowOrPtr(&obj)) {
mem::Destruct(&obj);
}
}
template<typename T>
bool PreStaticArray(T *ptr, index_t len) {
return (t_semi && !OT__Shallow(ptr)) || OT__NonConstPtr(ptr);
}
template<typename T>
void PostStaticArray(T *ptr, index_t len) {}
template<typename T>
bool PreArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
DEBUG_ASSERT(!unitary || len == 1);
if (unlikely(!nullable || ptr != NULL)) {
if (OT__PreTraverse(ptr, (T *)NULL, len, this)) {
return true;
}
PostArray(ptr, len, nullable, alloc, unitary);
}
return false;
}
template<typename T>
void PostArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
if (alloc) {
mem::FreeDestruct(ptr, len);
} else if (unitary) {
delete ptr;
} else {
delete[] ptr;
}
DEBUG_POISON_PTR(ptr);
}
void Str(char *&str, bool nullable, bool alloc) {
if (unlikely(!nullable || str != NULL)) {
DEBUG_ONLY(mem::DebugPoison(str, strlen(str) + 1));
if (alloc) {
mem::Free(str);
} else {
delete[] str;
}
DEBUG_POISON_PTR(str);
}
}
};
/**
* Traversal handler for freeing objects' allocated memory.
*/
template<bool t_semi>
class Destructor {
FORBID_ACCIDENTAL_COPIES(Destructor)
public:
enum { IS_PRINTER = 0 };
template<typename T>
Destructor(T *obj) {
/* Optimized for faster case */
if (unlikely(!OT__IsAlias(obj))) {
TransientDestructor<t_semi> ot__destructor(obj);
OT__TraverseObject(obj, this);
}
if (t_semi) {
mem::DebugPoison(obj);
} else {
#ifdef DEBUG
Unstructor ot__unstructor(obj);
#endif
}
}
template<typename T>
void ElemOf(const T *array) {}
template<typename T>
void Name(const char *name, const T &obj) {}
template<typename T>
bool PreUntraversed(T *dest, const T *src, index_t len) {
if (!t_semi && OT__Shallow(dest)) {
mem::DebugPoison(dest, len);
}
return OT__NonConstPtr(dest);
}
template<typename T>
bool PreTraverse(T *dest, const T *src, index_t len) {
return t_semi && !OT__Shallow(dest);
}
template<typename T>
void Untraversed(T &obj) {}
template<typename T>
void Obj(T &obj) {
if (t_semi && !OT__ShallowOrPtr(&obj)) {
TransientDestructor<t_semi> ot__destructor(&obj);
OT__TraverseObject(&obj, this);
}
}
template<typename T>
bool PreStaticArray(T *ptr, index_t len) {
return (t_semi && !OT__Shallow(ptr)) || OT__NonConstPtr(ptr);
}
template<typename T>
void PostStaticArray(T *ptr, index_t len) {}
template<typename T>
bool PreArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
DEBUG_ASSERT(!unitary || len == 1);
if (unlikely(!nullable || ptr != NULL)) {
if (OT__PreTraverse(ptr, (T *)NULL, len, this)) {
return true;
}
PostArray(ptr, len, nullable, alloc, unitary);
}
return false;
}
template<typename T>
void PostArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
if (t_semi) {
mem::DebugPoison(ptr, len);
} else {
if (alloc) {
mem::FreeDestruct(ptr, len);
} else if (unitary) {
delete ptr;
} else {
delete[] ptr;
}
}
DEBUG_POISON_PTR(ptr);
}
void Str(char *&str, bool nullable, bool alloc) {
if (unlikely(!nullable || str != NULL)) {
DEBUG_ONLY(mem::DebugPoison(str, strlen(str) + 1));
if (alloc) {
mem::Free(str);
} else {
delete[] str;
}
DEBUG_POISON_PTR(str);
}
}
};
/**
* Traversal handler for recursively copying objects and their
* contents, allocating memory as necessary. Can copy from frozen
* objects.
*/
template<bool t_thawing>
class Copier {
FORBID_ACCIDENTAL_COPIES(Copier)
private:
ptrdiff_t offset_;
public:
enum { IS_PRINTER = 0 };
template<typename T>
Copier(T *dest, const T *src) {
offset_ = mem::PtrAbsAddr(src);
if (OT__PreTraverse(dest, src, 1, this)) {
Obj(*dest);
}
}
template<typename T>
Copier(T *dest, const T *src, index_t len) {
offset_ = mem::PtrAbsAddr(src);
if (OT__PreTraverse(dest, src, len, this)) {
for (index_t i = 0; i < len; ++i) {
Obj(dest[i]);
}
}
}
template<typename T>
void ElemOf(const T *array) {}
template<typename T>
void Name(const char *name, const T &obj) {}
template<typename T>
bool PreUntraversed(T *dest, const T *src, index_t len) {
mem::CopyConstruct(dest, src, len);
return OT__NonConstPtr(dest);
}
template<typename T>
bool PreTraverse(T *dest, const T *src, index_t len) {
mem::Copy(dest, src, len);
return !OT__Shallow(dest);
}
template<typename T>
void Untraversed(T &obj) {
char buf[sizeof(T)];
mem::Copy<T, char, T>(buf, &obj);
mem::CopyConstruct(&obj, reinterpret_cast<T *>(buf));
}
template<typename T>
void Obj(T &obj) {
if (!OT__ShallowOrPtr(&obj)) {
OT__TraverseObject(&obj, this);
TransientUnstructor<false> ot__unstructor(&obj);
OT__RefillTransients(&obj);
}
}
template<typename T>
bool PreStaticArray(T *ptr, index_t len) {
return !OT__Shallow(ptr);
}
template<typename T>
void PostStaticArray(T *ptr, index_t len) {}
template<typename T>
bool PreArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
DEBUG_ASSERT(!unitary || len == 1);
if (likely(nullable && ptr == NULL)) {
return false;
} else {
const T *src = t_thawing ? mem::PtrAddBytes(ptr, offset_) : ptr;
if (alloc) {
ptr = mem::Alloc<T>(len);
} else if (unitary) {
ptr = new T;
} else {
ptr = new T[len];
}
return OT__PreTraverse(ptr, src, len, this);
}
}
template<typename T>
void PostArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {}
void Str(char *&str, bool nullable, bool alloc) {
if (unlikely(!nullable || str != NULL)) {
char *src = t_thawing ? mem::PtrAddBytes(str, offset_) : str;
index_t len = strlen(src) + 1;
if (alloc) {
str = mem::AllocCopy(src, len);
} else {
str = mem::Copy(new char[len], src, len);
}
}
}
};
/**
* Traversal handler for recursively marking an object as an alias.
*/
class Aliaser {
FORBID_ACCIDENTAL_COPIES(Aliaser)
public:
enum { IS_PRINTER = 0 };
template<typename T>
Aliaser(T *obj) {
Obj(*obj);
}
template<typename T>
void ElemOf(const T *array) {}
template<typename T>
void Name(const char *name, const T &obj) {}
template<typename T>
bool PreUntraversed(T *dest, const T *src, index_t len) { return false; }
template<typename T>
bool PreTraverse(T *dest, const T *src, index_t len) { return false; }
template<typename T>
void Untraversed(T &obj) {
DEBUG_ONLY(NONFATAL(
"Aliasing untraversed %s; may double-destruct.",
typeid(T).name()));
}
template<typename T>
void Obj(T &obj) {
if (!OT__ShallowOrPtr(&obj)) {
OT__BecomeAlias(&obj);
OT__TraverseObject(&obj, this);
OT__TraverseTransients(&obj, this);
}
}
template<typename T>
bool PreStaticArray(T *ptr, index_t len) {
return !OT__Shallow(ptr);
}
template<typename T>
void PostStaticArray(T *ptr, index_t len) {}
template<typename T>
bool PreArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
return false;
}
template<typename T>
void PostArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {}
void Str(char *&str, bool nullable, bool alloc) {}
};
/**
* Traversal handler for freezing objects and computing frozen size.
*/
template<bool t_size_only>
class Freezer {
FORBID_ACCIDENTAL_COPIES(Freezer)
private:
char *block_;
size_t pos_;
public:
enum { IS_PRINTER = 0 };
template<typename T>
Freezer(char *block, const T &src) {
block_ = block;
pos_ = sizeof(T);
if (!t_size_only) {
mem::Copy<T, char, T>(block, &src);
Obj(*reinterpret_cast<T *>(block));
} else {
Obj(const_cast<T &>(src));
}
}
size_t size() {
return pos_;
}
template<typename T>
void ElemOf(const T *array) {}
template<typename T>
void Name(const char *name, const T &obj) {}
template<typename T>
bool PreUntraversed(T *dest, const T *src, index_t len) { return false; }
template<typename T>
bool PreTraverse(T *dest, const T *src, index_t len) { return false; }
template<typename T>
void Untraversed(T &obj) {
DEBUG_ONLY(NONFATAL(
"Freezing untraversed %s with bit-copy.",
typeid(T).name()));
}
template<typename T>
void Obj(T *&ptr) {
DEBUG_ONLY(NONFATAL(
"Freezing pointer %s as primitive.",
typeid(T *).name()));
}
template<typename T>
void Obj(T &obj) {
if (!OT__Shallow(&obj)) {
OT__TraverseObject(&obj, this);
}
}
template<typename T>
bool PreStaticArray(T *ptr, index_t len) {
return !OT__Shallow(ptr);
}
template<typename T>
void PostStaticArray(T *ptr, index_t len) {}
template<typename T>
bool PreArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
DEBUG_ASSERT(!unitary || len == 1);
if (likely(nullable && ptr == NULL)) {
return false;
} else {
pos_ = stride_align(pos_, T);
if (!t_size_only) {
T *dest = reinterpret_cast<T *>(mem::PtrAddBytes(block_, pos_));
mem::Copy(dest, ptr, len);
ptr = OT__Shallow(ptr) ? reinterpret_cast<T *>(pos_) : dest;
}
pos_ += sizeof(T) * len;
return !OT__Shallow(ptr);
}
}
template<typename T>
void PostArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
if (!t_size_only) {
ptr = reinterpret_cast<T *>(mem::PtrDiffBytes(ptr, block_));
}
}
void Str(char *&str, bool nullable, bool alloc) {
if (unlikely(!nullable || str != NULL)) {
index_t len = strlen(str) + 1;
pos_ = stride_align(pos_, char);
if (!t_size_only) {
char *dest = mem::PtrAddBytes(block_, pos_);
mem::Copy(dest, str, len);
str = reinterpret_cast<char *>(pos_);
}
pos_ += sizeof(char) * len;
}
}
};
/**
* Traversal handler for moving frozen objects. Also can re-freeze,
* semi-thaw, and semi-copy.
*/
template<bool t_freezing, bool t_transients>
class Relocator {
FORBID_ACCIDENTAL_COPIES(Relocator)
private:
const char *block_;
const char *orig_;
ptrdiff_t offset_;
public:
enum { IS_PRINTER = 0 };
template<typename T>
Relocator(char *block, const T *orig) {
block_ = block;
orig_ = reinterpret_cast<const char *>(orig);
offset_ = mem::PtrDiffBytes(block, orig);
Obj(*reinterpret_cast<T *>(block));
}
template<typename T>
void ElemOf(const T *array) {}
template<typename T>
void Name(const char *name, const T &obj) {}
template<typename T>
bool PreUntraversed(T *dest, const T *src, index_t len) { return false; }
template<typename T>
bool PreTraverse(T *dest, const T *src, index_t len) { return false; }
template<typename T>
void Untraversed(T &obj) {}
template<typename T>
void Obj(T &obj) {
if (!OT__ShallowOrPtr(&obj)) {
if (t_freezing && t_transients) {
TransientDestructor<true> ot__destructor(&obj);
}
OT__TraverseObject(&obj, this);
if (!t_freezing && t_transients) {
TransientUnstructor<true> ot__unstructor(&obj);
OT__RefillTransients(&obj);
}
}
}
template<typename T>
bool PreStaticArray(T *ptr, index_t len) {
return !OT__Shallow(ptr);
}
template<typename T>
void PostStaticArray(T *ptr, index_t len) {}
template<typename T>
bool PreArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
DEBUG_ASSERT(!unitary || len == 1);
if (likely(nullable && ptr == NULL)) {
return false;
} else if (t_freezing && OT__Shallow(ptr)) {
ptr = reinterpret_cast<T *>(mem::PtrDiffBytes(ptr, orig_));
return false;
} else {
ptr = mem::PtrAddBytes(ptr, offset_);
return !OT__Shallow(ptr);
}
}
template<typename T>
void PostArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
if (t_freezing) {
ptr = reinterpret_cast<T *>(mem::PtrDiffBytes(ptr, block_));
}
}
void Str(char *&str, bool nullable, bool alloc) {
if (unlikely(!nullable || str != NULL)) {
if (t_freezing) {
str = reinterpret_cast<char *>(mem::PtrDiffBytes(str, orig_));
} else {
str = mem::PtrAddBytes(str, offset_);
}
}
}
};
/**
* Traversal handler for serializing objects or computing serial
* size.
*/
template<bool t_size_only>
class Serializer {
FORBID_ACCIDENTAL_COPIES(Serializer)
private:
FILE *stream_;
size_t size_;
template<typename T>
void Write_(T *val, index_t elems = 1) {
if (!t_size_only) {
fwrite(val, sizeof(T), elems, stream_);
}
size += sizeof(T) * elems;
}
public:
enum { IS_PRINTER = 0 };
template<typename T>
Serializer(const T &obj, FILE *stream) {
stream_ = stream;
size_ = 0;
Obj(const_cast<T *>(&obj));
}
size_t size() {
return size_;
}
template<typename T>
void ElemOf(const T *array) {}
template<typename T>
void Name(const char *name, const T &obj) {}
template<typename T>
bool PreUntraversed(T **dest, const T **src, index_t len) {
if (OT__NonConstPtr(src)) {
return true;
} else {
DEBUG_WARN_MSG_IF(!t_size_only,
"Serializing pointer %s as primitive.",
typeid(T *).name());
Write_(src, len);
return false;
}
}
template<typename T>
bool PreUntraversed(T *dest, const T *src, index_t len) {
DEBUG_WARN_MSG_IF(!t_size_only && !OT__Shallow(src),
"Serializing untraversed %s with bit-copy.",
typeid(T).name());
Write_(src, len);
return false;
}
template<typename T>
bool PreTraverse(T *dest, const T *src, index_t len) {
if (OT__IsShallow(src)) {
Write_(src, len);
return false;
} else {
return true;
}
}
template<typename T>
void Untraversed(T &obj) {
DEBUG_WARN_MSG_IF(!t_size_only && !OT__Shallow(&obj),
"Serializing untraversed %s with bit-copy.",
typeid(T).name());
Write_(&obj);
}
template<typename T>
void Obj(T *&ptr) {
DEBUG_WARN_MSG_IF(!t_size_only,
"Serializing pointer %s as primitive.",
typeid(T *).name());
Write_(&ptr);
}
template<typename T>
void Obj(T &obj) {
if (OT__Shallow(&obj)) {
Write_(&obj);
} else {
OT__TraverseObject(&obj, this);
}
}
template<typename T>
bool PreStaticArray(T *ptr, index_t len) {
return OT__PreTraverse((T *)NULL, ptr, len, this);
}
template<typename T>
void PostStaticArray(T *ptr, index_t len) {}
template<typename T>
bool PreArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
DEBUG_ASSERT(!unitary || len == 1);
if (nullable) {
bool temp = ptr != NULL;
Write_(&temp);
if (likely(!temp)) {
return false;
}
}
return OT__PreTraverse((T *)NULL, ptr, len, this);
}
template<typename T>
void PostArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {}
void Str(char *&str, bool nullable, bool alloc) {
if (nullable) {
bool temp = str != NULL;
Write_(&temp);
if (likely(!temp)) {
return;
}
}
Write_(str, strlen(str) + 1);
}
};
/**
* Traversal handler for deserializing objects.
*/
class Deserializer {
FORBID_ACCIDENTAL_COPIES(Deserializer)
private:
FILE *stream_;
size_t size_;
template<typename T>
void Read_(T *ptr, index_t elems = 1) {
fread(ptr, sizeof(T), elems, stream_);
size_ += sizeof(T) * elems;
}
index_t ReadStrLen_() {
index_t len = 0;
fpos_t pos;
fgetpos(stream_, &pos);
while (getc(stream_)) {
++len;
}
fsetpos(stream_, &pos);
return len;
}
public:
enum { IS_PRINTER = 0 };
template<typename T>
Deserializer(T &obj, FILE *stream) {
stream_ = stream;
size_ = 0;
Obj(&obj);
}
size_t size() {
return size_;
}
template<typename T>
void ElemOf(const T *array) {}
template<typename T>
void Name(const char *name, const T &obj) {}
template<typename T>
bool PreUntraversed(T **dest, const T **src, index_t len) {
if (OT__NonConstPtr(dest)) {
return true;
} else {
Read_(dest, len);
return false;
}
}
template<typename T>
bool PreUntraversed(T *dest, const T *src, index_t len) {
Read_(dest, len);
return false;
}
template<typename T>
bool PreTraverse(T *dest, const T *src, index_t len) {
if (OT__IsShallow(src)) {
Read_(dest, len);
return false;
} else {
return true;
}
}
template<typename T>
void Untraversed(T &obj) {
Read_(&obj);
}
template<typename T>
void Obj(T &obj) {
if (OT__ShallowOrPtr(&obj)) {
Read_(&obj);
} else {
OT__TraverseObject(&obj, this);
TransientUnstructor<false> ot__unstructor(&obj);
OT__RefillTransients(&obj);
}
}
template<typename T>
bool PreStaticArray(T *ptr, index_t len) {
return OT__PreTraverse(ptr, (T *)NULL, len, this);
}
template<typename T>
void PostStaticArray(T *ptr, index_t len) {}
template<typename T>
bool PreArray(T *&ptr, index_t len,
bool nullable, bool alloc, bool unitary) {
DEBUG_ASSERT(!unitary || len == 1);
if (nullable) {
bool temp;
Read_(&temp);
if (likely(!temp)) {
ptr = NULL;
return false;
}
}
if (alloc) {
ptr = mem::Alloc<T>(len);
} else if (unitary) {
ptr = new T;
} else {
ptr = new T[len];
}
return OT__PreTraverse(ptr, (T *)NULL, len, this);
}
template<typename T>
void PostArray(T *&ptr, index_t len) {}
void Str(char *&str, bool nullable, bool alloc) {
if (nullable) {
bool temp;
Read_(&temp);
if (likely(!temp)) {
str = NULL;
return;
}
}
index_t len = ReadStrLen_() + 1;
if (alloc) {
str = mem::Alloc<char>(len);
} else {
str = new char[len];
}
Read_(str, len);
}
};
};