mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
06471e5231
This should fix #8
193 lines
7.3 KiB
C++
193 lines
7.3 KiB
C++
//+----------------------------------------------------------------------------+
|
|
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
|
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
|
|
//| License: GNU General Public License 2 or later (see file COPYING) |
|
|
//+----------------------------------------------------------------------------+
|
|
|
|
#pragma once
|
|
|
|
/** @file util/reflect.hpp
|
|
*
|
|
* @brief Reflection of classes, currently reflection is used for (de)serialization.
|
|
*/
|
|
|
|
// ----------------------------------------------------------------------------- : Includes
|
|
|
|
#include <util/io/reader.hpp>
|
|
#include <util/io/writer.hpp>
|
|
#include <util/io/get_member.hpp>
|
|
|
|
// ----------------------------------------------------------------------------- : Declaring reflection
|
|
|
|
/// Declare that a class supports reflection
|
|
/** Reflection allows the member variables of a class to be inspected at runtime.
|
|
*/
|
|
#define DECLARE_REFLECTION_PREFIX(PREFIX,SUFFIX) \
|
|
private: \
|
|
template<class Handler> void reflect_impl(Handler&); \
|
|
protected: \
|
|
friend class Reader; \
|
|
friend class Writer; \
|
|
friend class GetDefaultMember; \
|
|
friend class GetMember; \
|
|
PREFIX void reflect(Reader& reader) SUFFIX; \
|
|
PREFIX void reflect(Writer& writer) SUFFIX; \
|
|
PREFIX void reflect(GetDefaultMember& gdm) SUFFIX; \
|
|
PREFIX void reflect(GetMember& gm) SUFFIX
|
|
|
|
#define DECLARE_REFLECTION() DECLARE_REFLECTION_PREFIX(,)
|
|
|
|
/// Declare that a class supports reflection, which can be overridden in derived classes
|
|
#define DECLARE_REFLECTION_VIRTUAL() DECLARE_REFLECTION_PREFIX(virtual,)
|
|
|
|
#define DECLARE_REFLECTION_OVERRIDE() DECLARE_REFLECTION_PREFIX(,override)
|
|
|
|
// ----------------------------------------------------------------------------- : Implementing reflection
|
|
|
|
/// Implement the refelection of a class type Cls
|
|
/** Reflection allows the member variables of a class to be inspected at runtime.
|
|
*
|
|
* Currently creates the methods:
|
|
* - Reader ::handle(Cls&)
|
|
* - Writer ::handle(const Cls&)
|
|
* - GetMember ::handle(const Cls&)
|
|
* Usage:
|
|
* @code
|
|
* IMPLEMENT_REFLECTION(MyClass) {
|
|
* REFLECT(a_variable_in_my_class);
|
|
* REFLECT(another_variable_in_my_class);
|
|
* }
|
|
* @endcode
|
|
*/
|
|
#define IMPLEMENT_REFLECTION(Cls) \
|
|
REFLECT_OBJECT_READER(Cls) \
|
|
REFLECT_OBJECT_WRITER(Cls) \
|
|
REFLECT_OBJECT_GET_DEFAULT_MEMBER_NOT(Cls) \
|
|
REFLECT_OBJECT_GET_MEMBER(Cls) \
|
|
template <class Handler> \
|
|
void Cls::reflect_impl(Handler& handler)
|
|
|
|
/// Implement the refelection of a class type Cls that only uses REFLECT_NAMELESS
|
|
#define IMPLEMENT_REFLECTION_NAMELESS(Cls) \
|
|
REFLECT_OBJECT_READER(Cls) \
|
|
REFLECT_OBJECT_WRITER(Cls) \
|
|
REFLECT_OBJECT_GET_DEFAULT_MEMBER(Cls) \
|
|
REFLECT_OBJECT_GET_MEMBER_NOT(Cls) \
|
|
template <class Handler> \
|
|
void Cls::reflect_impl(Handler& handler)
|
|
|
|
/// Implement the refelection of a class type Cls, but only for Reader and Writer,
|
|
/** There is custom code for GetMember and GetDefaultMember */
|
|
#define IMPLEMENT_REFLECTION_NO_GET_MEMBER(Cls) \
|
|
REFLECT_OBJECT_READER(Cls) \
|
|
REFLECT_OBJECT_WRITER(Cls) \
|
|
template <class Handler> \
|
|
void Cls::reflect_impl(Handler& handler)
|
|
|
|
/// Implement the refelection of a class type Cls, but only for Reader and Writer
|
|
/** There is no code for GetMember and GetDefaultMember */
|
|
#define IMPLEMENT_REFLECTION_NO_SCRIPT(Cls) \
|
|
REFLECT_OBJECT_READER(Cls) \
|
|
REFLECT_OBJECT_WRITER(Cls) \
|
|
REFLECT_OBJECT_GET_DEFAULT_MEMBER_NOT(Cls) \
|
|
REFLECT_OBJECT_GET_MEMBER_NOT(Cls) \
|
|
template <class Handler> \
|
|
void Cls::reflect_impl(Handler& handler)
|
|
|
|
/// Reflect a variable
|
|
#define REFLECT(var) handler.handle(_(#var), var)
|
|
/// Reflect a variable under the given name
|
|
#define REFLECT_N(name, var) handler.handle(_(name), var)
|
|
/// Reflect a variable without a name, should be used only once per class
|
|
#define REFLECT_NAMELESS(var) handler.handle(var)
|
|
|
|
/// Declare that the variables of a base class should also be reflected
|
|
#define REFLECT_BASE(Base) Base::reflect(handler)
|
|
|
|
/// Reflect a group of declarations only when reading
|
|
/** Usage:
|
|
* @code
|
|
* REFLECT_IF_READING {
|
|
* // only executed by Reader
|
|
* }
|
|
* @endcode
|
|
*/
|
|
#define REFLECT_IF_READING if (Handler::isReading)
|
|
|
|
/// Reflect a group of declarations only when *not* reading
|
|
/** Usage:
|
|
* @code
|
|
* REFLECT_IF_NOT_READING {
|
|
* // only executed by Writer, GetMember, GetDefaultMember
|
|
* }
|
|
* @endcode
|
|
*/
|
|
#define REFLECT_IF_NOT_READING if (!Handler::isReading)
|
|
|
|
/// Reflect a group of declarations only when reading and when the value is a single line value
|
|
#define REFLECT_IF_READING_SINGLE_VALUE if (Handler::isReading && !handler.isCompound())
|
|
|
|
#define REFLECT_IF_READING_SINGLE_VALUE_AND(cond) if (Handler::isReading && !handler.isCompound() && cond)
|
|
|
|
/// Add an alias for backwards compatibility
|
|
/** If a key 'name' is encountered in the input file, it is interpreted as 'var' for versions < version
|
|
* Example:
|
|
* @code
|
|
* REFLECT_COMPAT(<300, "style", stylesheet) // prior to 0.3.0 style was used instead of stylesheet
|
|
* @encode
|
|
*/
|
|
#define REFLECT_COMPAT(cond, name, var) if (handler.formatVersion() cond) REFLECT_N(name,var)
|
|
|
|
/// Ignore things for backwards compatibility for versions < 'version'
|
|
#define REFLECT_COMPAT_IGNORE(cond, name, Type) if (reflector.formatVersion() cond) {Type ignored; REFLECT_N(name,ignored);}
|
|
|
|
/// Reflect a variable, ignores the variable for scripting
|
|
#define REFLECT_NO_SCRIPT(var) handler.handleNoScript(_(#var), var)
|
|
/// Reflect a variable under the given name
|
|
#define REFLECT_NO_SCRIPT_N(name, var) handler.handleNoScript(_(name), var)
|
|
|
|
/// Explicitly instantiate reflection; this is occasionally required.
|
|
#define INSTANTIATE_REFLECTION(Class) \
|
|
template void Class::reflect_impl<Reader> (Reader&); \
|
|
template void Class::reflect_impl<Writer> (Writer&); \
|
|
template void Class::reflect_impl<GetMember> (GetMember&);
|
|
|
|
#define INSTANTIATE_REFLECTION_NAMELESS(Class) \
|
|
template void Class::reflect_impl<Reader> (Reader&); \
|
|
template void Class::reflect_impl<Writer> (Writer&); \
|
|
template void Class::reflect_impl<GetDefaultMember> (GetDefaultMember&);
|
|
|
|
// ----------------------------------------------------------------------------- : Reflecting enums
|
|
|
|
/// Implement the refelection of a enumeration type Enum
|
|
/** Usage:
|
|
* @code
|
|
* IMPLEMENT_REFLECTION_ENUM(MyEnum) {
|
|
* VALUE(value_of_enum_1);
|
|
* VALUE(value_of_enum_2);
|
|
* }
|
|
* @endcode
|
|
*
|
|
* When reading the first value declared is the default value
|
|
*
|
|
* Currently creates the methods:
|
|
* - Reader::handle(Enum&)
|
|
* - Writer::handle(const Enum&)
|
|
* - GetDefaultMember::handle(const Enum&)
|
|
*/
|
|
#define IMPLEMENT_REFLECTION_ENUM(Enum) \
|
|
template <class Handler> \
|
|
void reflect_ ## Enum (Enum& enum_, Handler& handler); \
|
|
REFLECT_ENUM_READER(Enum) \
|
|
REFLECT_ENUM_WRITER(Enum) \
|
|
REFLECT_ENUM_GET_MEMBER(Enum) \
|
|
template <class Handler> \
|
|
void reflect_ ## Enum (Enum& enum_, Handler& handler)
|
|
|
|
/// Declare a possible value of an enum
|
|
#define VALUE(val) handler.handle(_(#val), val, enum_)
|
|
|
|
/// Declare a possible value of an enum under the given name
|
|
#define VALUE_N(name, val) handler.handle(_(name), val, enum_)
|
|
|