WIP
This commit is contained in:
parent
db0082c325
commit
2138491ee5
|
@ -39,30 +39,25 @@ BinarySerializationCodeGenerator::BinarySerializationCodeGenerator(CodeFactory &
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the qualified name of the specified \a record if it is considered relevant.
|
* \brief Checks whether \a possiblyRelevantClass is actually relevant.
|
||||||
*/
|
*/
|
||||||
string BinarySerializationCodeGenerator::qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const
|
void BinarySerializationCodeGenerator::computeRelevantClass(RelevantClass &possiblyRelevantClass) const
|
||||||
{
|
{
|
||||||
const string qualifiedName(record->getQualifiedNameAsString());
|
SerializationCodeGenerator::computeRelevantClass(possiblyRelevantClass);
|
||||||
switch (isQualifiedNameIfRelevant(record, qualifiedName)) {
|
if (possiblyRelevantClass.isRelevant != IsRelevant::Maybe) {
|
||||||
case IsRelevant::Yes:
|
return;
|
||||||
return qualifiedName;
|
|
||||||
case IsRelevant::No:
|
|
||||||
return string();
|
|
||||||
default:;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// consider all classes specified via "--additional-classes" argument relevant
|
// consider all classes specified via "--additional-classes" argument relevant
|
||||||
if (!m_options.additionalClassesArg.isPresent()) {
|
if (!m_options.additionalClassesArg.isPresent()) {
|
||||||
return string();
|
return;
|
||||||
}
|
}
|
||||||
for (const char *className : m_options.additionalClassesArg.values()) {
|
for (const char *const className : m_options.additionalClassesArg.values()) {
|
||||||
if (className == qualifiedName) {
|
if (className == possiblyRelevantClass.qualifiedName) {
|
||||||
return qualifiedName;
|
possiblyRelevantClass.isRelevant = IsRelevant::Yes;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return string();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief The RetrieveIntegerLiteralFromDeclaratorDecl struct is used to traverse a variable declaration to get the integer value.
|
/// \brief The RetrieveIntegerLiteralFromDeclaratorDecl struct is used to traverse a variable declaration to get the integer value.
|
||||||
|
@ -250,9 +245,19 @@ void BinarySerializationCodeGenerator::generate(std::ostream &os) const
|
||||||
|
|
||||||
// print writeCustomType method
|
// print writeCustomType method
|
||||||
os << "template <> " << visibility << " void writeCustomType<::" << relevantClass.qualifiedName
|
os << "template <> " << visibility << " void writeCustomType<::" << relevantClass.qualifiedName
|
||||||
<< ">(BinarySerializer &serializer, const ::" << relevantClass.qualifiedName
|
<< ">(BinarySerializer &serializer, const ::" << relevantClass.qualifiedName << " &customObject, BinaryVersion version)\n{\n";
|
||||||
<< " &customObject, BinaryVersion version)\n{\n"
|
if (!relevantClass.relevantBase.empty()) {
|
||||||
" // write base classes\n";
|
os << " // write version\n"
|
||||||
|
" using V = Versioning<"
|
||||||
|
<< relevantClass.relevantBase
|
||||||
|
<< ">;\n"
|
||||||
|
" if constexpr (V::enabled) {\n"
|
||||||
|
" serializer.writeVariableLengthUIntBE(V::applyDefault(version));\n"
|
||||||
|
" } else {\n"
|
||||||
|
" (void)version;\n"
|
||||||
|
" }\n";
|
||||||
|
}
|
||||||
|
os << " // write base classes\n";
|
||||||
for (const RelevantClass *baseClass : relevantBases) {
|
for (const RelevantClass *baseClass : relevantBases) {
|
||||||
os << " serializer.write(static_cast<const ::" << baseClass->qualifiedName << " &>(customObject), version);\n";
|
os << " serializer.write(static_cast<const ::" << baseClass->qualifiedName << " &>(customObject), version);\n";
|
||||||
}
|
}
|
||||||
|
@ -260,7 +265,7 @@ void BinarySerializationCodeGenerator::generate(std::ostream &os) const
|
||||||
auto mt = MemberTracking();
|
auto mt = MemberTracking();
|
||||||
for (clang::Decl *const decl : relevantClass.record->decls()) {
|
for (clang::Decl *const decl : relevantClass.record->decls()) {
|
||||||
// check static member variables for version markers
|
// check static member variables for version markers
|
||||||
if (mt.checkForVersionMarker(decl)) {
|
if (mt.checkForVersionMarker(decl)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,17 +306,25 @@ void BinarySerializationCodeGenerator::generate(std::ostream &os) const
|
||||||
|
|
||||||
// print readCustomType method
|
// print readCustomType method
|
||||||
mt = MemberTracking();
|
mt = MemberTracking();
|
||||||
os << "template <> " << visibility << " void readCustomType<::" << relevantClass.qualifiedName
|
os << "template <> " << visibility << " BinaryVersion readCustomType<::" << relevantClass.qualifiedName
|
||||||
<< ">(BinaryDeserializer &deserializer, ::" << relevantClass.qualifiedName
|
<< ">(BinaryDeserializer &deserializer, ::" << relevantClass.qualifiedName << " &customObject)\n{\n";
|
||||||
<< " &customObject)\n{\n"
|
if (!relevantClass.relevantBase.empty()) {
|
||||||
" // read base classes\n";
|
os << " // read version\n"
|
||||||
|
" auto version = BinaryVersion();\n"
|
||||||
|
" if constexpr (Versioning<"
|
||||||
|
<< relevantClass.relevantBase
|
||||||
|
<< ">::enabled) {\n"
|
||||||
|
" version = deserializer.readVariableLengthUIntBE();\n"
|
||||||
|
" }\n";
|
||||||
|
}
|
||||||
|
os << " // read base classes\n";
|
||||||
for (const RelevantClass *baseClass : relevantBases) {
|
for (const RelevantClass *baseClass : relevantBases) {
|
||||||
os << " deserializer.read(static_cast<::" << baseClass->qualifiedName << " &>(customObject));\n";
|
os << " deserializer.read(static_cast<::" << baseClass->qualifiedName << " &>(customObject));\n";
|
||||||
}
|
}
|
||||||
os << " // read members\n";
|
os << " // read members\n";
|
||||||
for (clang::Decl *const decl : relevantClass.record->decls()) {
|
for (clang::Decl *const decl : relevantClass.record->decls()) {
|
||||||
// check static member variables for version markers
|
// check static member variables for version markers
|
||||||
if (mt.checkForVersionMarker(decl)) {
|
if (mt.checkForVersionMarker(decl)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,6 +352,7 @@ void BinarySerializationCodeGenerator::generate(std::ostream &os) const
|
||||||
if (relevantBases.empty() && !mt.membersWritten) {
|
if (relevantBases.empty() && !mt.membersWritten) {
|
||||||
os << " (void)deserializer;\n (void)customObject;\n";
|
os << " (void)deserializer;\n (void)customObject;\n";
|
||||||
}
|
}
|
||||||
|
os << " return version;\n";
|
||||||
os << "}\n\n";
|
os << "}\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ public:
|
||||||
void generate(std::ostream &os) const override;
|
void generate(std::ostream &os) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const override;
|
void computeRelevantClass(RelevantClass &possiblyRelevantClass) const override;
|
||||||
|
|
||||||
const Options &m_options;
|
const Options &m_options;
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,17 +44,18 @@ bool CodeGenerator::isOnlyIncluded(const clang::Decl *declaration) const
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns whether the specified \a record inherits from an instantiation of the specified \a templateClass.
|
* \brief Returns whether the specified \a record inherits from an instantiation of the specified \a templateClass.
|
||||||
|
* \returns Returns the relevant base class if that's the case and otherwise nullptr.
|
||||||
* \remarks The specified \a record must be defined (not only forward-declared).
|
* \remarks The specified \a record must be defined (not only forward-declared).
|
||||||
*/
|
*/
|
||||||
bool CodeGenerator::inheritsFromInstantiationOf(clang::CXXRecordDecl *const record, const char *const templateClass)
|
clang::CXXBaseSpecifier *CodeGenerator::inheritsFromInstantiationOf(clang::CXXRecordDecl *const record, const char *const templateClass)
|
||||||
{
|
{
|
||||||
for (const clang::CXXBaseSpecifier &base : record->bases()) {
|
for (clang::CXXBaseSpecifier &base : record->bases()) {
|
||||||
const clang::CXXRecordDecl *const baseDecl = base.getType()->getAsCXXRecordDecl();
|
clang::CXXRecordDecl *const baseDecl = base.getType()->getAsCXXRecordDecl();
|
||||||
if (baseDecl && baseDecl->getQualifiedNameAsString() == templateClass) {
|
if (baseDecl && baseDecl->getQualifiedNameAsString() == templateClass) {
|
||||||
return true;
|
return &base;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ReflectiveRapidJSON
|
} // namespace ReflectiveRapidJSON
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
namespace clang {
|
namespace clang {
|
||||||
class Decl;
|
class Decl;
|
||||||
class CXXRecordDecl;
|
class CXXRecordDecl;
|
||||||
|
class CXXBaseSpecifier;
|
||||||
class SourceManager;
|
class SourceManager;
|
||||||
} // namespace clang
|
} // namespace clang
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ protected:
|
||||||
CodeFactory &factory() const;
|
CodeFactory &factory() const;
|
||||||
void lazyInitializeSourceManager() const;
|
void lazyInitializeSourceManager() const;
|
||||||
bool isOnlyIncluded(const clang::Decl *declaration) const;
|
bool isOnlyIncluded(const clang::Decl *declaration) const;
|
||||||
static bool inheritsFromInstantiationOf(clang::CXXRecordDecl *record, const char *templateClass);
|
static clang::CXXBaseSpecifier *inheritsFromInstantiationOf(clang::CXXRecordDecl *record, const char *templateClass);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CodeFactory &m_factory;
|
CodeFactory &m_factory;
|
||||||
|
|
|
@ -35,30 +35,25 @@ JsonSerializationCodeGenerator::JsonSerializationCodeGenerator(CodeFactory &fact
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the qualified name of the specified \a record if it is considered relevant.
|
* \brief Checks whether \a possiblyRelevantClass is actually relevant.
|
||||||
*/
|
*/
|
||||||
string JsonSerializationCodeGenerator::qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const
|
void JsonSerializationCodeGenerator::computeRelevantClass(RelevantClass &possiblyRelevantClass) const
|
||||||
{
|
{
|
||||||
const string qualifiedName(record->getQualifiedNameAsString());
|
SerializationCodeGenerator::computeRelevantClass(possiblyRelevantClass);
|
||||||
switch (isQualifiedNameIfRelevant(record, qualifiedName)) {
|
if (possiblyRelevantClass.isRelevant != IsRelevant::Maybe) {
|
||||||
case IsRelevant::Yes:
|
return;
|
||||||
return qualifiedName;
|
|
||||||
case IsRelevant::No:
|
|
||||||
return string();
|
|
||||||
default:;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// consider all classes specified via "--additional-classes" argument relevant
|
// consider all classes specified via "--additional-classes" argument relevant
|
||||||
if (!m_options.additionalClassesArg.isPresent()) {
|
if (!m_options.additionalClassesArg.isPresent()) {
|
||||||
return string();
|
return;
|
||||||
}
|
}
|
||||||
for (const char *className : m_options.additionalClassesArg.values()) {
|
for (const char *const className : m_options.additionalClassesArg.values()) {
|
||||||
if (className == qualifiedName) {
|
if (className == possiblyRelevantClass.qualifiedName) {
|
||||||
return qualifiedName;
|
possiblyRelevantClass.isRelevant = IsRelevant::Yes;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return string();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -27,7 +27,7 @@ public:
|
||||||
void generate(std::ostream &os) const override;
|
void generate(std::ostream &os) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const override;
|
void computeRelevantClass(RelevantClass &possiblyRelevantClass) const override;
|
||||||
|
|
||||||
const Options &m_options;
|
const Options &m_options;
|
||||||
};
|
};
|
||||||
|
|
|
@ -66,12 +66,12 @@ void SerializationCodeGenerator::addDeclaration(clang::Decl *decl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SerializationCodeGenerator::IsRelevant SerializationCodeGenerator::isQualifiedNameIfRelevant(
|
void SerializationCodeGenerator::computeRelevantClass(RelevantClass &possiblyRelevantClass) const
|
||||||
clang::CXXRecordDecl *record, const std::string &qualifiedName) const
|
|
||||||
{
|
{
|
||||||
// skip all classes which are only forward-declared
|
// skip all classes which are only forward-declared
|
||||||
if (!record->isCompleteDefinition()) {
|
if (!possiblyRelevantClass.record->isCompleteDefinition()) {
|
||||||
return IsRelevant::No;
|
possiblyRelevantClass.isRelevant = IsRelevant::No;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// consider all classes for which a specialization of the "AdaptedJsonSerializable" struct is available
|
// consider all classes for which a specialization of the "AdaptedJsonSerializable" struct is available
|
||||||
|
@ -80,31 +80,39 @@ SerializationCodeGenerator::IsRelevant SerializationCodeGenerator::isQualifiedNa
|
||||||
if (isOnlyIncluded(adaptionRecord.record)) {
|
if (isOnlyIncluded(adaptionRecord.record)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (adaptionRecord.qualifiedName == qualifiedName) {
|
if (adaptionRecord.qualifiedName == possiblyRelevantClass.qualifiedName) {
|
||||||
return IsRelevant::Yes;
|
possiblyRelevantClass.isRelevant = IsRelevant::Yes;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip all classes which are only included
|
// skip all classes which are only included
|
||||||
if (isOnlyIncluded(record)) {
|
if (isOnlyIncluded(possiblyRelevantClass.record)) {
|
||||||
return IsRelevant::No;
|
possiblyRelevantClass.isRelevant = IsRelevant::No;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// consider all classes inheriting from an instantiation of "JsonSerializable" relevant
|
// consider all classes inheriting from an instantiation of "JsonSerializable" relevant
|
||||||
if (inheritsFromInstantiationOf(record, m_qualifiedNameOfRecords)) {
|
if (const auto *const relevantBase = inheritsFromInstantiationOf(possiblyRelevantClass.record, m_qualifiedNameOfRecords)) {
|
||||||
return IsRelevant::Yes;
|
cerr << "record: " << possiblyRelevantClass.qualifiedName << '\n';
|
||||||
|
for (const clang::CXXBaseSpecifier base : possiblyRelevantClass.record->bases()) {
|
||||||
|
cerr << "base: " << base.getType().getAsString() << '\n';
|
||||||
|
}
|
||||||
|
cerr << "relevant base: " << relevantBase->getType().getAsString();
|
||||||
|
possiblyRelevantClass.relevantBase = relevantBase->getType().getAsString();
|
||||||
|
possiblyRelevantClass.isRelevant = IsRelevant::Yes;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return IsRelevant::Maybe;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SerializationCodeGenerator::RelevantClass> SerializationCodeGenerator::findRelevantClasses() const
|
std::vector<SerializationCodeGenerator::RelevantClass> SerializationCodeGenerator::findRelevantClasses() const
|
||||||
{
|
{
|
||||||
std::vector<RelevantClass> relevantClasses;
|
std::vector<RelevantClass> relevantClasses;
|
||||||
for (clang::CXXRecordDecl *record : m_records) {
|
for (clang::CXXRecordDecl *const record : m_records) {
|
||||||
string qualifiedName(qualifiedNameIfRelevant(record));
|
auto &relevantClass = relevantClasses.emplace_back(record->getQualifiedNameAsString(), record);
|
||||||
if (!qualifiedName.empty()) {
|
computeRelevantClass(relevantClass);
|
||||||
relevantClasses.emplace_back(move(qualifiedName), record);
|
if (relevantClass.isRelevant != IsRelevant::Yes) {
|
||||||
|
relevantClasses.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return relevantClasses;
|
return relevantClasses;
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include <llvm/ADT/StringRef.h>
|
#include <llvm/ADT/StringRef.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace ReflectiveRapidJSON {
|
namespace ReflectiveRapidJSON {
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &os, llvm::StringRef str);
|
std::ostream &operator<<(std::ostream &os, llvm::StringRef str);
|
||||||
|
@ -15,11 +17,14 @@ std::ostream &operator<<(std::ostream &os, llvm::StringRef str);
|
||||||
*/
|
*/
|
||||||
class SerializationCodeGenerator : public CodeGenerator {
|
class SerializationCodeGenerator : public CodeGenerator {
|
||||||
public:
|
public:
|
||||||
|
enum class IsRelevant { Yes, No, Maybe };
|
||||||
struct RelevantClass {
|
struct RelevantClass {
|
||||||
explicit RelevantClass(std::string &&qualifiedName, clang::CXXRecordDecl *record);
|
explicit RelevantClass(std::string &&qualifiedName, clang::CXXRecordDecl *record);
|
||||||
|
|
||||||
std::string qualifiedName;
|
std::string qualifiedName;
|
||||||
clang::CXXRecordDecl *record;
|
std::string relevantBase;
|
||||||
|
clang::CXXRecordDecl *record = nullptr;
|
||||||
|
IsRelevant isRelevant = IsRelevant::Maybe;
|
||||||
};
|
};
|
||||||
|
|
||||||
SerializationCodeGenerator(CodeFactory &factory);
|
SerializationCodeGenerator(CodeFactory &factory);
|
||||||
|
@ -27,9 +32,7 @@ public:
|
||||||
void addDeclaration(clang::Decl *decl) override;
|
void addDeclaration(clang::Decl *decl) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum class IsRelevant { Yes, No, Maybe };
|
virtual void computeRelevantClass(RelevantClass &possiblyRelevantClass) const;
|
||||||
IsRelevant isQualifiedNameIfRelevant(clang::CXXRecordDecl *record, const std::string &qualifiedName) const;
|
|
||||||
virtual std::string qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const = 0;
|
|
||||||
std::vector<RelevantClass> findRelevantClasses() const;
|
std::vector<RelevantClass> findRelevantClasses() const;
|
||||||
static std::vector<const RelevantClass *> findRelevantBaseClasses(
|
static std::vector<const RelevantClass *> findRelevantBaseClasses(
|
||||||
const RelevantClass &relevantClass, const std::vector<RelevantClass> &relevantBases);
|
const RelevantClass &relevantClass, const std::vector<RelevantClass> &relevantBases);
|
||||||
|
|
|
@ -74,7 +74,7 @@ struct PointerStruct : public BinarySerializable<PointerStruct> {
|
||||||
* \brief The PointerStruct struct is used to test the behavior of the binary (de)serialization with smart pointer.
|
* \brief The PointerStruct struct is used to test the behavior of the binary (de)serialization with smart pointer.
|
||||||
*/
|
*/
|
||||||
// clang-format off
|
// clang-format off
|
||||||
struct VersionedStruct : public BinarySerializable<VersionedStruct> {
|
struct VersionedStruct : public BinarySerializable<VersionedStruct, 3> {
|
||||||
std::uint32_t a, b;
|
std::uint32_t a, b;
|
||||||
|
|
||||||
until_version(2):
|
until_version(2):
|
||||||
|
@ -82,6 +82,9 @@ until_version(2):
|
||||||
|
|
||||||
as_of_version(3):
|
as_of_version(3):
|
||||||
std::uint32_t e, f;
|
std::uint32_t e, f;
|
||||||
|
|
||||||
|
as_of_version(4):
|
||||||
|
std::uint32_t g;
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|
|
@ -24,15 +24,17 @@
|
||||||
namespace ReflectiveRapidJSON {
|
namespace ReflectiveRapidJSON {
|
||||||
namespace BinaryReflector {
|
namespace BinaryReflector {
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIf<IsCustomType<Type>> *> void readCustomType(BinaryDeserializer &deserializer, Type &customType)
|
template <typename Type, Traits::EnableIf<IsCustomType<Type>> *> BinaryVersion readCustomType(BinaryDeserializer &deserializer, Type &customType)
|
||||||
{
|
{
|
||||||
boost::hana::for_each(
|
boost::hana::for_each(
|
||||||
boost::hana::keys(customType), [&deserializer, &customType](auto key) { deserializer.read(boost::hana::at_key(customType, key)); });
|
boost::hana::keys(customType), [&deserializer, &customType](auto key) { deserializer.read(boost::hana::at_key(customType, key)); });
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIf<IsCustomType<Type>> *>
|
template <typename Type, Traits::EnableIf<IsCustomType<Type>> *>
|
||||||
void writeCustomType(BinarySerializer &serializer, const Type &customType, BinaryVersion version)
|
void writeCustomType(BinarySerializer &serializer, const Type &customType, BinaryVersion version)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(version)
|
||||||
boost::hana::for_each(
|
boost::hana::for_each(
|
||||||
boost::hana::keys(customType), [&serializer, &customType](auto key) { serializer.write(boost::hana::at_key(customType, key)); });
|
boost::hana::keys(customType), [&serializer, &customType](auto key) { serializer.write(boost::hana::at_key(customType, key)); });
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,10 @@
|
||||||
namespace ReflectiveRapidJSON {
|
namespace ReflectiveRapidJSON {
|
||||||
namespace BinaryReflector {
|
namespace BinaryReflector {
|
||||||
|
|
||||||
template <> inline void readCustomType<CppUtilities::DateTime>(BinaryDeserializer &deserializer, CppUtilities::DateTime &dateTime)
|
template <> inline BinaryVersion readCustomType<CppUtilities::DateTime>(BinaryDeserializer &deserializer, CppUtilities::DateTime &dateTime)
|
||||||
{
|
{
|
||||||
deserializer.read(dateTime.ticks());
|
deserializer.read(dateTime.ticks());
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -28,9 +29,10 @@ inline void writeCustomType<CppUtilities::DateTime>(BinarySerializer &serializer
|
||||||
serializer.write(dateTime.totalTicks());
|
serializer.write(dateTime.totalTicks());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> inline void readCustomType<CppUtilities::TimeSpan>(BinaryDeserializer &deserializer, CppUtilities::TimeSpan &timeSpan)
|
template <> inline BinaryVersion readCustomType<CppUtilities::TimeSpan>(BinaryDeserializer &deserializer, CppUtilities::TimeSpan &timeSpan)
|
||||||
{
|
{
|
||||||
deserializer.read(timeSpan.ticks());
|
deserializer.read(timeSpan.ticks());
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
|
|
@ -35,7 +35,7 @@ template <typename T> struct AdaptedBinarySerializable : public Traits::Bool<fal
|
||||||
|
|
||||||
using BinaryVersion = std::uint64_t;
|
using BinaryVersion = std::uint64_t;
|
||||||
|
|
||||||
template <typename Type, BinaryVersion defaultVersion = 0> struct BinarySerializable;
|
template <typename Type, BinaryVersion v = 0> struct BinarySerializable;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief The BinaryReflector namespace contains BinaryReader and BinaryWriter for automatic binary (de)serialization.
|
* \brief The BinaryReflector namespace contains BinaryReader and BinaryWriter for automatic binary (de)serialization.
|
||||||
|
@ -52,7 +52,8 @@ template <typename Type> using IsCustomType = Traits::Not<IsBuiltInType<Type>>;
|
||||||
class BinaryDeserializer;
|
class BinaryDeserializer;
|
||||||
class BinarySerializer;
|
class BinarySerializer;
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr> void readCustomType(BinaryDeserializer &deserializer, Type &customType);
|
template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr>
|
||||||
|
BinaryVersion readCustomType(BinaryDeserializer &deserializer, Type &customType);
|
||||||
template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr>
|
template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr>
|
||||||
void writeCustomType(BinarySerializer &serializer, const Type &customType, BinaryVersion version = 0);
|
void writeCustomType(BinarySerializer &serializer, const Type &customType, BinaryVersion version = 0);
|
||||||
|
|
||||||
|
@ -74,7 +75,7 @@ public:
|
||||||
void read(Type &iteratable);
|
void read(Type &iteratable);
|
||||||
template <typename Type, Traits::EnableIf<std::is_enum<Type>> * = nullptr> void read(Type &enumValue);
|
template <typename Type, Traits::EnableIf<std::is_enum<Type>> * = nullptr> void read(Type &enumValue);
|
||||||
template <typename Type, Traits::EnableIf<IsVariant<Type>> * = nullptr> void read(Type &variant);
|
template <typename Type, Traits::EnableIf<IsVariant<Type>> * = nullptr> void read(Type &variant);
|
||||||
template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr> void read(Type &customType);
|
template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr> BinaryVersion read(Type &customType);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::uint64_t, std::any> m_pointer;
|
std::unordered_map<std::uint64_t, std::any> m_pointer;
|
||||||
|
@ -211,9 +212,9 @@ template <typename Type, Traits::EnableIf<IsVariant<Type>> *> void BinaryDeseria
|
||||||
Detail::readVariantValueByRuntimeIndex(readByte(), variant, *this);
|
Detail::readVariantValueByRuntimeIndex(readByte(), variant, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIf<IsCustomType<Type>> *> void BinaryDeserializer::read(Type &customType)
|
template <typename Type, Traits::EnableIf<IsCustomType<Type>> *> BinaryVersion BinaryDeserializer::read(Type &customType)
|
||||||
{
|
{
|
||||||
readCustomType(*this, customType);
|
return readCustomType(*this, customType);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline BinarySerializer::BinarySerializer(std::ostream *stream)
|
inline BinarySerializer::BinarySerializer(std::ostream *stream)
|
||||||
|
|
|
@ -17,28 +17,30 @@ namespace ReflectiveRapidJSON {
|
||||||
/*!
|
/*!
|
||||||
* \brief The BinarySerializable class provides the CRTP-base for (de)serializable objects.
|
* \brief The BinarySerializable class provides the CRTP-base for (de)serializable objects.
|
||||||
*/
|
*/
|
||||||
template <typename Type, BinaryVersion defaultVersion> struct BinarySerializable {
|
template <typename Type, BinaryVersion v> struct BinarySerializable {
|
||||||
void toBinary(std::ostream &outputStream) const;
|
void toBinary(std::ostream &outputStream, BinaryVersion version = 0) const;
|
||||||
void restoreFromBinary(std::istream &inputStream);
|
BinaryVersion restoreFromBinary(std::istream &inputStream);
|
||||||
static Type fromBinary(std::istream &inputStream);
|
static Type fromBinary(std::istream &inputStream);
|
||||||
|
|
||||||
static constexpr const char *qualifiedName = "ReflectiveRapidJSON::BinarySerializable";
|
static constexpr const char *qualifiedName = "ReflectiveRapidJSON::BinarySerializable";
|
||||||
static constexpr auto defaultSerializeVersion = defaultVersion;
|
static constexpr auto version = v;
|
||||||
|
static constexpr auto versioningEnabled(const BinarySerializable<Type, v> &)
|
||||||
|
{
|
||||||
|
return v != 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Type, BinaryVersion defaultVersion>
|
template <typename Type, BinaryVersion v> inline void BinarySerializable<Type, v>::toBinary(std::ostream &outputStream, BinaryVersion version) const
|
||||||
inline void BinarySerializable<Type, defaultVersion>::toBinary(std::ostream &outputStream) const
|
|
||||||
{
|
{
|
||||||
BinaryReflector::BinarySerializer(&outputStream).write(static_cast<const Type &>(*this), defaultVersion);
|
BinaryReflector::BinarySerializer(&outputStream).write(static_cast<const Type &>(*this), version);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type, BinaryVersion defaultVersion>
|
template <typename Type, BinaryVersion v> inline BinaryVersion BinarySerializable<Type, v>::restoreFromBinary(std::istream &inputStream)
|
||||||
inline void BinarySerializable<Type, defaultVersion>::restoreFromBinary(std::istream &inputStream)
|
|
||||||
{
|
{
|
||||||
BinaryReflector::BinaryDeserializer(&inputStream).read(static_cast<Type &>(*this));
|
return BinaryReflector::BinaryDeserializer(&inputStream).read(static_cast<Type &>(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type, BinaryVersion defaultVersion> Type BinarySerializable<Type, defaultVersion>::fromBinary(std::istream &inputStream)
|
template <typename Type, BinaryVersion v> Type BinarySerializable<Type, v>::fromBinary(std::istream &inputStream)
|
||||||
{
|
{
|
||||||
Type object;
|
Type object;
|
||||||
static_cast<BinarySerializable<Type> &>(object).restoreFromBinary(inputStream);
|
static_cast<BinarySerializable<Type> &>(object).restoreFromBinary(inputStream);
|
||||||
|
|
|
@ -75,7 +75,7 @@ struct ObjectWithVariantsBinary : public BinarySerializable<ObjectWithVariantsBi
|
||||||
namespace ReflectiveRapidJSON {
|
namespace ReflectiveRapidJSON {
|
||||||
namespace BinaryReflector {
|
namespace BinaryReflector {
|
||||||
|
|
||||||
template <> void readCustomType<TestObjectBinary>(BinaryDeserializer &deserializer, TestObjectBinary &customType)
|
template <> BinaryVersion readCustomType<TestObjectBinary>(BinaryDeserializer &deserializer, TestObjectBinary &customType)
|
||||||
{
|
{
|
||||||
deserializer.read(customType.number);
|
deserializer.read(customType.number);
|
||||||
deserializer.read(customType.number2);
|
deserializer.read(customType.number2);
|
||||||
|
@ -92,10 +92,12 @@ template <> void readCustomType<TestObjectBinary>(BinaryDeserializer &deserializ
|
||||||
deserializer.read(customType.someEnumClass);
|
deserializer.read(customType.someEnumClass);
|
||||||
deserializer.read(customType.timeSpan);
|
deserializer.read(customType.timeSpan);
|
||||||
deserializer.read(customType.dateTime);
|
deserializer.read(customType.dateTime);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> void writeCustomType<TestObjectBinary>(BinarySerializer &serializer, const TestObjectBinary &customType, BinaryVersion version)
|
template <> void writeCustomType<TestObjectBinary>(BinarySerializer &serializer, const TestObjectBinary &customType, BinaryVersion version)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(version)
|
||||||
serializer.write(customType.number);
|
serializer.write(customType.number);
|
||||||
serializer.write(customType.number2);
|
serializer.write(customType.number2);
|
||||||
serializer.write(customType.numbers);
|
serializer.write(customType.numbers);
|
||||||
|
@ -113,10 +115,11 @@ template <> void writeCustomType<TestObjectBinary>(BinarySerializer &serializer,
|
||||||
serializer.write(customType.dateTime);
|
serializer.write(customType.dateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> void readCustomType<NestingArrayBinary>(BinaryDeserializer &deserializer, NestingArrayBinary &customType)
|
template <> BinaryVersion readCustomType<NestingArrayBinary>(BinaryDeserializer &deserializer, NestingArrayBinary &customType)
|
||||||
{
|
{
|
||||||
deserializer.read(customType.name);
|
deserializer.read(customType.name);
|
||||||
deserializer.read(customType.testObjects);
|
deserializer.read(customType.testObjects);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> void writeCustomType<NestingArrayBinary>(BinarySerializer &serializer, const NestingArrayBinary &customType, BinaryVersion version)
|
template <> void writeCustomType<NestingArrayBinary>(BinarySerializer &serializer, const NestingArrayBinary &customType, BinaryVersion version)
|
||||||
|
@ -125,16 +128,18 @@ template <> void writeCustomType<NestingArrayBinary>(BinarySerializer &serialize
|
||||||
serializer.write(customType.testObjects);
|
serializer.write(customType.testObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> void readCustomType<ObjectWithVariantsBinary>(BinaryDeserializer &deserializer, ObjectWithVariantsBinary &customType)
|
template <> BinaryVersion readCustomType<ObjectWithVariantsBinary>(BinaryDeserializer &deserializer, ObjectWithVariantsBinary &customType)
|
||||||
{
|
{
|
||||||
deserializer.read(customType.someVariant);
|
deserializer.read(customType.someVariant);
|
||||||
deserializer.read(customType.anotherVariant);
|
deserializer.read(customType.anotherVariant);
|
||||||
deserializer.read(customType.yetAnotherVariant);
|
deserializer.read(customType.yetAnotherVariant);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void writeCustomType<ObjectWithVariantsBinary>(BinarySerializer &serializer, const ObjectWithVariantsBinary &customType, BinaryVersion version)
|
void writeCustomType<ObjectWithVariantsBinary>(BinarySerializer &serializer, const ObjectWithVariantsBinary &customType, BinaryVersion version)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(version)
|
||||||
serializer.write(customType.someVariant);
|
serializer.write(customType.someVariant);
|
||||||
serializer.write(customType.anotherVariant);
|
serializer.write(customType.anotherVariant);
|
||||||
serializer.write(customType.yetAnotherVariant);
|
serializer.write(customType.yetAnotherVariant);
|
||||||
|
|
|
@ -1,13 +1,27 @@
|
||||||
#include "../traits.h"
|
#include "../traits.h"
|
||||||
|
#include "../versioning.h"
|
||||||
|
|
||||||
|
#include "../binary/serializable.h"
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// treat some types differently to test Treat... traits
|
// define structs for testing REFLECTIVE_RAPIDJSON_TREAT_AS_…
|
||||||
struct Foo {
|
struct Foo {
|
||||||
};
|
};
|
||||||
struct Bar {
|
struct Bar {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// define structs for testing versioning
|
||||||
|
struct VersionlessBase : public ReflectiveRapidJSON::BinarySerializable<VersionlessBase> {
|
||||||
|
};
|
||||||
|
struct VersionedDerived : public VersionlessBase, public ReflectiveRapidJSON::BinarySerializable<VersionedDerived, 1> {
|
||||||
|
};
|
||||||
|
struct VersionedBase : public ReflectiveRapidJSON::BinarySerializable<VersionlessBase, 1> {
|
||||||
|
};
|
||||||
|
struct VersionlessDerived : public VersionedBase, public ReflectiveRapidJSON::BinarySerializable<VersionlessDerived> {
|
||||||
|
};
|
||||||
|
|
||||||
namespace ReflectiveRapidJSON {
|
namespace ReflectiveRapidJSON {
|
||||||
REFLECTIVE_RAPIDJSON_TREAT_AS_MAP_OR_HASH(Foo);
|
REFLECTIVE_RAPIDJSON_TREAT_AS_MAP_OR_HASH(Foo);
|
||||||
REFLECTIVE_RAPIDJSON_TREAT_AS_MULTI_MAP_OR_HASH(Foo);
|
REFLECTIVE_RAPIDJSON_TREAT_AS_MULTI_MAP_OR_HASH(Foo);
|
||||||
|
@ -48,3 +62,14 @@ static_assert(IsIteratableExceptString<std::vector<int>>::value, "vector is iter
|
||||||
static_assert(!IsIteratableExceptString<std::string>::value, "string not iteratable");
|
static_assert(!IsIteratableExceptString<std::string>::value, "string not iteratable");
|
||||||
static_assert(!IsIteratableExceptString<std::wstring>::value, "wstring not iteratable");
|
static_assert(!IsIteratableExceptString<std::wstring>::value, "wstring not iteratable");
|
||||||
static_assert(!IsIteratableExceptString<const std::string>::value, "string not iteratable");
|
static_assert(!IsIteratableExceptString<const std::string>::value, "string not iteratable");
|
||||||
|
|
||||||
|
// test versioning traits
|
||||||
|
static_assert(!Versioning<int>::enabled, "versioning for built-in types not enabled");
|
||||||
|
static_assert(!Versioning<std::string>::enabled, "versioning for standard types not enabled");
|
||||||
|
static_assert(!Versioning<VersionlessBase>::enabled, "versioning not enabled by default");
|
||||||
|
static_assert(Versioning<BinarySerializable<VersionedDerived, 1>>::enabled, "versioning enabled if non-zero version parameter specified (derived)");
|
||||||
|
static_assert(Versioning<VersionedBase>::enabled, "versioning enabled if non-zero version parameter specified (base)");
|
||||||
|
static_assert(!Versioning<BinarySerializable<VersionlessDerived>>::enabled, "versioning disabled for derived, even if base is versioned");
|
||||||
|
static_assert(!Versioning<BinarySerializable<Foo, 0>>::enabled, "versioning disabled if zero-version specified");
|
||||||
|
static_assert(Versioning<BinarySerializable<Foo, 3>>::applyDefault(0) == 3, "default version returned");
|
||||||
|
static_assert(Versioning<BinarySerializable<Foo, 3>>::applyDefault(2) == 2, "default version overridden");
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef REFLECTIVE_RAPIDJSON_VERSIONING
|
#ifndef REFLECTIVE_RAPIDJSON_VERSIONING
|
||||||
#define REFLECTIVE_RAPIDJSON_VERSIONING
|
#define REFLECTIVE_RAPIDJSON_VERSIONING
|
||||||
|
|
||||||
|
#include <c++utilities/misc/traits.h>
|
||||||
|
|
||||||
namespace ReflectiveRapidJSON {
|
namespace ReflectiveRapidJSON {
|
||||||
|
|
||||||
#ifdef REFLECTIVE_RAPIDJSON_GENERATOR
|
#ifdef REFLECTIVE_RAPIDJSON_GENERATOR
|
||||||
|
@ -22,6 +24,27 @@ public
|
||||||
#define until_version(version) REFLECTIVE_RAPIDJSON_UNTIL_VERSION(version)
|
#define until_version(version) REFLECTIVE_RAPIDJSON_UNTIL_VERSION(version)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsVersioned, T::version);
|
||||||
|
//CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsVersioned, T::versioningEnabled(std::declval<T &>()));
|
||||||
|
|
||||||
|
//using BinaryVersion = std::uint64_t;
|
||||||
|
|
||||||
|
//template <typename Type, BinaryVersion v = 0> struct BinarySerializable;
|
||||||
|
//CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsVersioned, static_cast<T &>(std::declval<T &>()).version);
|
||||||
|
|
||||||
|
template <typename Type, bool Condition = IsVersioned<Type>::value> struct Versioning {
|
||||||
|
static constexpr auto enabled = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Type> struct Versioning<Type, true> {
|
||||||
|
static constexpr auto enabled = Type::version != 0;
|
||||||
|
static constexpr auto serializationDefault = Type::version;
|
||||||
|
static constexpr auto applyDefault(decltype(serializationDefault) version)
|
||||||
|
{
|
||||||
|
return version ? version : serializationDefault;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace ReflectiveRapidJSON
|
} // namespace ReflectiveRapidJSON
|
||||||
|
|
||||||
#endif // REFLECTIVE_RAPIDJSON_TRAITS
|
#endif // REFLECTIVE_RAPIDJSON_TRAITS
|
||||||
|
|
Loading…
Reference in New Issue