Commit d66ff847 authored by twanvl's avatar twanvl

Split GetMember into GetMember (for handle) and GetDefaultMember (for store);

Split IMPLEMENT_REFLECTION macro to match
parent b8a3bf5e
...@@ -66,6 +66,6 @@ template <> void Reader::handle(Alignment& align) { ...@@ -66,6 +66,6 @@ template <> void Reader::handle(Alignment& align) {
template <> void Writer::handle(const Alignment& align) { template <> void Writer::handle(const Alignment& align) {
handle(toString(align)); handle(toString(align));
} }
template <> void GetMember::store(const Alignment& align) { template <> void GetDefaultMember::handle(const Alignment& align) {
store(toString(align)); handle(toString(align));
} }
...@@ -60,8 +60,8 @@ void Writer::handle(const Defaultable<T>& def) { ...@@ -60,8 +60,8 @@ void Writer::handle(const Defaultable<T>& def) {
} }
} }
template <typename T> template <typename T>
void GetMember::handle(const Defaultable<T>& def) { void GetDefaultMember::handle(const Defaultable<T>& def) {
store(def()); handle(def());
} }
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
......
...@@ -11,22 +11,20 @@ ...@@ -11,22 +11,20 @@
#include <script/value.hpp> #include <script/value.hpp>
#include <script/script.hpp> #include <script/script.hpp>
// ----------------------------------------------------------------------------- : GetDefaultMember
template <> void GetDefaultMember::handle(const String& v) { value = toScript(v); }
template <> void GetDefaultMember::handle(const int& v) { value = toScript(v); }
template <> void GetDefaultMember::handle(const unsigned int& v) { value = toScript((int)v); }
template <> void GetDefaultMember::handle(const double& v) { value = toScript(v); }
template <> void GetDefaultMember::handle(const bool& v) { value = toScript(v); }
template <> void GetDefaultMember::handle(const Vector2D& v) { value = toScript(String::Format(_("(%.10lf,%.10lf)"), v.x, v.y)); }
template <> void GetDefaultMember::handle(const Color& v) { value = toScript(v); }
void GetDefaultMember::handle(const ScriptValueP& v) { value = v; }
void GetDefaultMember::handle(const ScriptP& v) { value = v; }
// ----------------------------------------------------------------------------- : GetMember // ----------------------------------------------------------------------------- : GetMember
GetMember::GetMember(const String& name) GetMember::GetMember(const String& name)
: targetName(name) : target_name(name)
{} {}
template <> void GetMember::store(const String& v) { value = toScript(v); }
//template <> void GetMember::store(const Char* const& v) { value = toScript(v); }
template <> void GetMember::store(const int& v) { value = toScript(v); }
template <> void GetMember::store(const unsigned int& v) { value = toScript((int)v); }
template <> void GetMember::store(const double& v) { value = toScript(v); }
template <> void GetMember::store(const bool& v) { value = toScript(v); }
template <> void GetMember::store(const Vector2D& v) {
value = toScript(String::Format(_("(%.10lf,%.10lf)"), v.x, v.y));
}
void GetMember::store(const ScriptValueP& v) { value = v; }
void GetMember::store(const ScriptP& v) { value = v; }
...@@ -17,85 +17,118 @@ inline void intrusive_ptr_add_ref(ScriptValue* p); ...@@ -17,85 +17,118 @@ inline void intrusive_ptr_add_ref(ScriptValue* p);
inline void intrusive_ptr_release(ScriptValue* p); inline void intrusive_ptr_release(ScriptValue* p);
template <typename T> class Defaultable; template <typename T> class Defaultable;
template <typename T> class Scriptable;
// ----------------------------------------------------------------------------- : GetDefaultMember
/// Find a member without a name using reflection
/** The member is wrapped in a ScriptValue */
class GetDefaultMember {
public:
/// Tell the reflection code we are not reading
inline bool reading() const { return false; }
inline bool isComplex() const { return false; }
/// The result, or script_nil if the member was not found
inline ScriptValueP result() { return value; }
// --------------------------------------------------- : Handling objects
/// Handle an object: we don't match things with a name
template <typename T>
void handle(const Char* name, const T& object) {}
/// Handle an object: investigate children, or store it if we know how
template <typename T> void handle(const T&);
/// Handle a Defaultable: investigate children
template <typename T> void handle(const Defaultable<T>&);
template <typename T> void handle(const Scriptable<T>&);
template <typename T> void handle(const vector<T>& c) { value = toScript(&c); }
template <typename K, typename V> void handle(const map<K,V>& c) { value = toScript(&c); }
template <typename T> void handle(const shared_ptr<T>& p) { value = toScript(p); }
void handle(const ScriptValueP&);
void handle(const ScriptP&);
private:
ScriptValueP value; ///< The value we found (if any)
};
// ----------------------------------------------------------------------------- : GetMember // ----------------------------------------------------------------------------- : GetMember
/// Find a member with a specific name using reflection /// Find a member with a specific name using reflection
/** The member is wrapped in a ScriptValue */ /** The member is wrapped in a ScriptValue */
class GetMember { class GetMember : private GetDefaultMember {
public: public:
/// Construct a member getter that looks for the given name /// Construct a member getter that looks for the given name
GetMember(const String& name); GetMember(const String& name);
/// Tell the reflection code we are not reading /// Tell the reflection code we are not reading
inline bool reading() const { return false; } inline bool reading() const { return false; }
inline bool isComplex() const { return false; }
/// The result, or script_nil if the member was not found /// The result, or script_nil if the member was not found
inline ScriptValueP result() { return value; } inline ScriptValueP result() { return gdm.result(); }
// --------------------------------------------------- : Handling objects // --------------------------------------------------- : Handling objects
/// Handle an object: we are done if the name matches /// Handle an object: we are done if the name matches
template <typename T> template <typename T>
void handle(const Char* name, const T& object) { void handle(const Char* name, const T& object) {
if (!value && name == targetName) store(object); if (!gdm.result() && name == target_name) gdm.handle(object);
} }
/// Handle an object: investigate children /// Handle an object: investigate children
template <typename T> void handle(const T&); template <typename T> void handle(const T&);
/// Handle a Defaultable: investigate children
template <typename T> void handle(const Defaultable<T>& def);
/// Store something in the return value
template <typename T> void store(const T& v);
/// Store a vector in the return value
template <typename T> void store(const vector<T>& vector) {
value = toScript(&vector);
}
/// Store a shared_ptr in the return value
template <typename T> void store(const shared_ptr<T>& pointer) {
value = toScript(pointer);
}
void store(const ScriptValueP&);
void store(const ScriptP&);
private: private:
const String& targetName; ///< The name we are looking for const String& target_name; ///< The name we are looking for
ScriptValueP value; ///< The value we found (if any) GetDefaultMember gdm; ///< Object to store and retrieve the value
}; };
// ----------------------------------------------------------------------------- : Reflection // ----------------------------------------------------------------------------- : Reflection
/// Implement reflection as used by GetMember /// Implement reflection as used by GetDefaultMember
#define REFLECT_OBJECT_GET_MEMBER(Cls) \ #define REFLECT_OBJECT_GET_DEFAULT_MEMBER(Cls) REFLECT_WRITE_YES(Cls,GetDefaultMember)
template<> void GetMember::handle<Cls>(const Cls& object) { \ #define REFLECT_OBJECT_GET_MEMBER(Cls) REFLECT_WRITE_YES(Cls,GetMember)
const_cast<Cls&>(object).reflect(*this); \ #define REFLECT_OBJECT_GET_DEFAULT_MEMBER_NOT(Cls) REFLECT_WRITE_NO(Cls,GetDefaultMember)
#define REFLECT_OBJECT_GET_MEMBER_NOT(Cls) REFLECT_WRITE_NO(Cls,GetMember)
#define REFLECT_WRITE_YES(Cls, Tag) \
template<> void Tag::handle<Cls>(const Cls& object) { \
const_cast<Cls&>(object).reflect(*this); \
} \
void Cls::reflect(Tag& tag) { \
reflect_impl(tag); \
} }
#define REFLECT_WRITE_NO(Cls, Tag) \
template<> void Tag::handle<Cls>(const Cls& object) {} \
void Cls::reflect(Tag& tag) {}
// ----------------------------------------------------------------------------- : Reflection for enumerations // ----------------------------------------------------------------------------- : Reflection for enumerations
/// Implement enum reflection as used by GetMember /// Implement enum reflection as used by GetMember
#define REFLECT_ENUM_GET_MEMBER(Enum) \ #define REFLECT_ENUM_GET_MEMBER(Enum) \
template<> void GetMember::store<Enum>(const Enum& enum_) { \ template<> void GetDefaultMember::handle<Enum>(const Enum& enum_) { \
EnumGetMember gm(*this); \ EnumGetMember egm(*this); \
reflect_ ## Enum(const_cast<Enum&>(enum_), gm); \ reflect_ ## Enum(const_cast<Enum&>(enum_), egm); \
} }
/// 'Tag' to be used when reflecting enumerations for GetMember /// 'Tag' to be used when reflecting enumerations for GetMember
class EnumGetMember { class EnumGetMember {
public: public:
inline EnumGetMember(GetMember& getMember) inline EnumGetMember(GetDefaultMember& gdm)
: getMember(getMember) {} : gdm(gdm) {}
/// Handle a possible value for the enum, if the name matches the name in the input /// Handle a possible value for the enum, if the name matches the name in the input
template <typename Enum> template <typename Enum>
inline void handle(const Char* name, Enum value, Enum enum_) { inline void handle(const Char* name, Enum value, Enum enum_) {
if (enum_ == value) { if (enum_ == value) {
getMember.store(String(name)); gdm.handle(String(name));
} }
} }
private: private:
GetMember& getMember; ///< The writer to write output to GetDefaultMember& gdm; ///< The object to store output in
}; };
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
......
...@@ -130,3 +130,10 @@ template <> void Reader::handle(Vector2D& vec) { ...@@ -130,3 +130,10 @@ template <> void Reader::handle(Vector2D& vec) {
throw ParseError(_("Expected (x,y)")); throw ParseError(_("Expected (x,y)"));
} }
} }
template <> void Reader::handle(Color& col) {
UInt r,g,b;
if (wxSscanf(value.c_str(),_("rgb(%u,%u,%u)"),&r,&g,&b)) {
col.Set(r, g, b);
}
}
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <wx/txtstrm.h> #include <wx/txtstrm.h>
template <typename T> class Defaultable; template <typename T> class Defaultable;
template <typename T> class Scriptable;
// ----------------------------------------------------------------------------- : Reader // ----------------------------------------------------------------------------- : Reader
...@@ -39,6 +40,8 @@ class Reader { ...@@ -39,6 +40,8 @@ class Reader {
/// Tell the reflection code we are reading /// Tell the reflection code we are reading
inline bool reading() const { return true; } inline bool reading() const { return true; }
/// Is the thing currently being read 'complex', i.e. does it have children
inline bool isComplex() const { return value.empty(); }
// --------------------------------------------------- : Handling objects // --------------------------------------------------- : Handling objects
/// Handle an object: read it if it's name matches /// Handle an object: read it if it's name matches
...@@ -58,9 +61,11 @@ class Reader { ...@@ -58,9 +61,11 @@ class Reader {
/// Reads a shared_ptr from the input stream /// Reads a shared_ptr from the input stream
template <typename T> void handle(shared_ptr<T>& pointer); template <typename T> void handle(shared_ptr<T>& pointer);
/// Reads a map from the input stream /// Reads a map from the input stream
//template <typename K, typename V> void handle(map<K,V>& map); template <typename K, typename V> void handle(map<K,V>& map);
/// Reads a Defaultable from the input stream /// Reads a Defaultable from the input stream
template <typename T> void handle(Defaultable<T>& def); template <typename T> void handle(Defaultable<T>&);
/// Reads a Scriptable from the input stream
template <typename T> void handle(Scriptable<T>&);
private: private:
// --------------------------------------------------- : Data // --------------------------------------------------- : Data
...@@ -129,6 +134,11 @@ void Reader::handle(shared_ptr<T>& pointer) { ...@@ -129,6 +134,11 @@ void Reader::handle(shared_ptr<T>& pointer) {
handle(*pointer); handle(*pointer);
} }
template <typename K, typename V>
void Reader::handle(map<K,V>& map) {
// TODO
}
// ----------------------------------------------------------------------------- : Reflection // ----------------------------------------------------------------------------- : Reflection
/// Implement reflection as used by Reader /// Implement reflection as used by Reader
...@@ -144,6 +154,9 @@ void Reader::handle(shared_ptr<T>& pointer) { ...@@ -144,6 +154,9 @@ void Reader::handle(shared_ptr<T>& pointer) {
} while (indent > expected_indent); \ } while (indent > expected_indent); \
} \ } \
} \ } \
} \
void Cls::reflect(Reader& reader) { \
reflect_impl(reader); \
} }
// ----------------------------------------------------------------------------- : Reflection for enumerations // ----------------------------------------------------------------------------- : Reflection for enumerations
......
...@@ -109,3 +109,6 @@ template <> void Writer::handle(const bool& value) { ...@@ -109,3 +109,6 @@ template <> void Writer::handle(const bool& value) {
template <> void Writer::handle(const Vector2D& vec) { template <> void Writer::handle(const Vector2D& vec) {
handle(String::Format(_("(%.10lf,%.10lf)"), vec.x, vec.y)); handle(String::Format(_("(%.10lf,%.10lf)"), vec.x, vec.y));
} }
template <> void Writer::handle(const Color& col) {
handle(String::Format(_("rgb(%u,%u,%u)"), col.Red(), col.Green(), col.Blue()));
}
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <wx/txtstrm.h> #include <wx/txtstrm.h>
template <typename T> class Defaultable; template <typename T> class Defaultable;
template <typename T> class Scriptable;
// ----------------------------------------------------------------------------- : Writer // ----------------------------------------------------------------------------- : Writer
...@@ -26,7 +27,8 @@ class Writer { ...@@ -26,7 +27,8 @@ class Writer {
Writer(const OutputStreamP& output); Writer(const OutputStreamP& output);
/// Tell the reflection code we are not reading /// Tell the reflection code we are not reading
inline bool reading() const { return false; } inline bool reading() const { return false; }
inline bool isComplex() const { return false; }
// --------------------------------------------------- : Handling objects // --------------------------------------------------- : Handling objects
/// Handle an object: write it under the given name /// Handle an object: write it under the given name
...@@ -49,9 +51,11 @@ class Writer { ...@@ -49,9 +51,11 @@ class Writer {
/// Write a shared_ptr to the output stream /// Write a shared_ptr to the output stream
template <typename T> void handle(const shared_ptr<T>& pointer); template <typename T> void handle(const shared_ptr<T>& pointer);
/// Write a map to the output stream /// Write a map to the output stream
//template <typename K, typename V> void handle(map<K,V>& map); template <typename K, typename V> void handle(const map<K,V>& map);
/// Write an object of type Defaultable<T> to the output stream /// Write an object of type Defaultable<T> to the output stream
template <typename T> void handle(const Defaultable<T>& def); template <typename T> void handle(const Defaultable<T>&);
/// Write an object of type Scriptable<T> to the output stream
template <typename T> void handle(const Scriptable<T>&);
private: private:
// --------------------------------------------------- : Data // --------------------------------------------------- : Data
...@@ -85,10 +89,8 @@ class Writer { ...@@ -85,10 +89,8 @@ class Writer {
template <typename T> template <typename T>
void Writer::handle(const Char* name, const vector<T>& vec) { void Writer::handle(const Char* name, const vector<T>& vec) {
String vectorKey = singular_form(name); String vectorKey = singular_form(name);
for (vector<T>::const_iterator it = vec.begin() ; it != vec.end() ; ++it) { for (typename vector<T>::const_iterator it = vec.begin() ; it != vec.end() ; ++it) {
enterBlock(vectorKey); handle(vectorKey, *it);
handle(*it);
exitBlock();
} }
} }
...@@ -96,6 +98,12 @@ template <typename T> ...@@ -96,6 +98,12 @@ template <typename T>
void Writer::handle(const shared_ptr<T>& pointer) { void Writer::handle(const shared_ptr<T>& pointer) {
if (pointer) handle(*pointer); if (pointer) handle(*pointer);
} }
template <typename K, typename V>
void Writer::handle(const map<K,V>& m) {
for (typename map<K,V>::const_iterator it = m.begin() ; it != m.end() ; ++it) {
handle(it->first.c_str(), it->second);
}
}
// ----------------------------------------------------------------------------- : Reflection // ----------------------------------------------------------------------------- : Reflection
...@@ -103,6 +111,9 @@ void Writer::handle(const shared_ptr<T>& pointer) { ...@@ -103,6 +111,9 @@ void Writer::handle(const shared_ptr<T>& pointer) {
#define REFLECT_OBJECT_WRITER(Cls) \ #define REFLECT_OBJECT_WRITER(Cls) \
template<> void Writer::handle<Cls>(const Cls& object) { \ template<> void Writer::handle<Cls>(const Cls& object) { \
const_cast<Cls&>(object).reflect(*this); \ const_cast<Cls&>(object).reflect(*this); \
} \
void Cls::reflect(Writer& writer) { \
reflect_impl(writer); \
} }
// ----------------------------------------------------------------------------- : Reflection for enumerations // ----------------------------------------------------------------------------- : Reflection for enumerations
......
...@@ -28,10 +28,12 @@ ...@@ -28,10 +28,12 @@
template<class Tag> void reflect_impl(Tag& tag); \ template<class Tag> void reflect_impl(Tag& tag); \
friend class Reader; \ friend class Reader; \
friend class Writer; \ friend class Writer; \
friend class GetDefaultMember; \
friend class GetMember; \ friend class GetMember; \
void reflect(Reader& reader); \ void reflect(Reader& reader); \
void reflect(Writer& writer); \ void reflect(Writer& writer); \
void reflect(GetMember& getMember) void reflect(GetDefaultMember& gdm); \
void reflect(GetMember& gm)
/// Declare that a class supports reflection, which can be overridden in derived classes /// Declare that a class supports reflection, which can be overridden in derived classes
#define DECLARE_REFLECTION_VIRTUAL() \ #define DECLARE_REFLECTION_VIRTUAL() \
...@@ -39,10 +41,14 @@ ...@@ -39,10 +41,14 @@
template<class Tag> void reflect_impl(Tag& tag); \ template<class Tag> void reflect_impl(Tag& tag); \
friend class Reader; \ friend class Reader; \
friend class Writer; \ friend class Writer; \
friend class GetDefaultMember; \
friend class GetMember; \ friend class GetMember; \
/* extra level of indirection between Tag::handle \
* and reflect_impl, to allow for virtual */ \
virtual void reflect(Reader& reader); \ virtual void reflect(Reader& reader); \
virtual void reflect(Writer& writer); \ virtual void reflect(Writer& writer); \
virtual void reflect(GetMember& getMember) virtual void reflect(GetDefaultMember& gdm); \
virtual void reflect(GetMember& gm)
// ----------------------------------------------------------------------------- : Implementing reflection // ----------------------------------------------------------------------------- : Implementing reflection
...@@ -50,9 +56,9 @@ ...@@ -50,9 +56,9 @@
/** Reflection allows the member variables of a class to be inspected at runtime. /** Reflection allows the member variables of a class to be inspected at runtime.
* *
* Currently creates the methods: * Currently creates the methods:
* - Reader::handle(Cls&) * - Reader ::handle(Cls&)
* - Writer::handle(Cls&) * - Writer ::handle(const Cls&)
* - GetMember::handle(Cls&) * - GetMember ::handle(const Cls&)
* Usage: * Usage:
* @code * @code
* IMPLEMENT_REFLECTION(MyClass) { * IMPLEMENT_REFLECTION(MyClass) {
...@@ -64,17 +70,24 @@ ...@@ -64,17 +70,24 @@
#define IMPLEMENT_REFLECTION(Cls) \ #define IMPLEMENT_REFLECTION(Cls) \
REFLECT_OBJECT_READER(Cls) \ REFLECT_OBJECT_READER(Cls) \
REFLECT_OBJECT_WRITER(Cls) \ REFLECT_OBJECT_WRITER(Cls) \
REFLECT_OBJECT_GET_DEFAULT_MEMBER_NOT(Cls) \
REFLECT_OBJECT_GET_MEMBER(Cls) \ REFLECT_OBJECT_GET_MEMBER(Cls) \
/* Extra level, so it can be declared virtual */ \ template <class Tag> \
void Cls::reflect(Reader& reader) { \ void Cls::reflect_impl(Tag& tag)
reflect_impl(reader); \
} \ /// Implement the refelection of a class type Cls that only uses REFLECT_NAMELESS
void Cls::reflect(Writer& writer) { \ #define IMPLEMENT_REFLECTION_NAMELESS(Cls) \
reflect_impl(writer); \ REFLECT_OBJECT_READER(Cls) \
} \ REFLECT_OBJECT_WRITER(Cls) \
void Cls::reflect(GetMember& getMember) { \ REFLECT_OBJECT_GET_DEFAULT_MEMBER(Cls) \
reflect_impl(getMember); \ REFLECT_OBJECT_GET_MEMBER_NOT(Cls) \
} \ template <class Tag> \
void Cls::reflect_impl(Tag& tag)
/// Implement the refelection of a class type Cls, but only for Reader and Writer
#define IMPLEMENT_REFLECTION_NO_GET_MEMBER(Cls) \
REFLECT_OBJECT_READER(Cls) \
REFLECT_OBJECT_WRITER(Cls) \
template <class Tag> \ template <class Tag> \
void Cls::reflect_impl(Tag& tag) void Cls::reflect_impl(Tag& tag)
...@@ -105,7 +118,7 @@ ...@@ -105,7 +118,7 @@
* Currently creates the methods: * Currently creates the methods:
* - Reader::handle(Enum& * - Reader::handle(Enum&
* - Writer::handle(const Enum&) * - Writer::handle(const Enum&)
* - GetMember::handle(const Enum&) * - GetDefaultMember::handle(const Enum&)
*/ */
#define IMPLEMENT_REFLECTION_ENUM(Enum) \ #define IMPLEMENT_REFLECTION_ENUM(Enum) \
template <class Tag> \ template <class Tag> \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment