532 lines
22 KiB
C++
532 lines
22 KiB
C++
#ifndef U_CORE_PROPERTY_H
|
|
#define U_CORE_PROPERTY_H
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <sstream>
|
|
#include <typeinfo>
|
|
#include <typeindex>
|
|
#include <boost/serialization/nvp.hpp>
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <boost/type_traits/is_class.hpp>
|
|
#include <boost/mpl/bool.hpp>
|
|
#include <set>
|
|
#include <boost/type_traits/is_base_of.hpp>
|
|
#include "Core/Archives.h"
|
|
#include "Core/Signal.h"
|
|
#include "Core/Object.h"
|
|
#include "Core/SmartPointer.h"
|
|
|
|
// Type traits for detecting SmartPointer<T>
|
|
namespace uLib {
|
|
template<typename T> struct is_smart_pointer : std::false_type {};
|
|
template<typename T> struct is_smart_pointer<SmartPointer<T>> : std::true_type {};
|
|
template<typename T> struct smart_pointer_element { using type = void; };
|
|
template<typename T> struct smart_pointer_element<SmartPointer<T>> { using type = T; };
|
|
} // namespace uLib
|
|
|
|
namespace uLib {
|
|
|
|
namespace Archive {
|
|
class property_register_archive;
|
|
}
|
|
|
|
/**
|
|
* @brief Base class for properties to allow runtime listing and identification.
|
|
*/
|
|
class PropertyBase : public Object {
|
|
public:
|
|
virtual ~PropertyBase() {}
|
|
virtual const std::string& GetName() const = 0;
|
|
virtual const char* GetTypeName() const = 0;
|
|
virtual std::string GetValueAsString() const = 0;
|
|
virtual std::type_index GetTypeIndex() const = 0;
|
|
virtual const std::string& GetUnits() const = 0;
|
|
virtual void SetUnits(const std::string& units) = 0;
|
|
virtual const std::vector<std::string>& GetEnumLabels() const {
|
|
static std::vector<std::string> empty;
|
|
return empty;
|
|
}
|
|
virtual const std::string& GetGroup() const = 0;
|
|
virtual void SetGroup(const std::string& group) = 0;
|
|
|
|
virtual bool HasRange() const { return false; }
|
|
virtual double GetMin() const { return 0; }
|
|
virtual double GetMax() const { return 0; }
|
|
virtual bool HasDefault() const { return false; }
|
|
virtual std::string GetDefaultValueAsString() const { return ""; }
|
|
virtual bool IsReadOnly() const = 0;
|
|
|
|
std::string GetQualifiedName() const {
|
|
if (GetGroup().empty()) return GetName();
|
|
return GetGroup() + "." + GetName();
|
|
}
|
|
|
|
|
|
// Serialization support for different uLib archives
|
|
virtual void serialize(Archive::xml_oarchive & ar, const unsigned int version) override = 0;
|
|
virtual void serialize(Archive::xml_iarchive & ar, const unsigned int version) override = 0;
|
|
virtual void serialize(Archive::text_oarchive & ar, const unsigned int version) override = 0;
|
|
virtual void serialize(Archive::text_iarchive & ar, const unsigned int version) override = 0;
|
|
virtual void serialize(Archive::hrt_oarchive & ar, const unsigned int version) override = 0;
|
|
virtual void serialize(Archive::hrt_iarchive & ar, const unsigned int version) override = 0;
|
|
virtual void serialize(Archive::log_archive & ar, const unsigned int version) override = 0;
|
|
|
|
virtual void serialize(Archive::property_register_archive & ar, const unsigned int v) = 0;
|
|
};
|
|
|
|
/**
|
|
* @brief Template class for typed properties.
|
|
*/
|
|
template <typename T>
|
|
class Property : public PropertyBase {
|
|
public:
|
|
Property(Object* owner, const std::string& name, T* valuePtr, const std::string& units = "", const std::string& group = "")
|
|
: m_owner(owner), m_name(name), m_units(units), m_group(group), m_value(valuePtr), m_own(false),
|
|
m_HasRange(false), m_HasDefault(false), m_ReadOnly(false) {
|
|
if (m_owner) m_owner->RegisterProperty(this);
|
|
}
|
|
|
|
Property(Object* owner, const std::string& name, const T& defaultValue = T(), const std::string& units = "", const std::string& group = "")
|
|
: m_owner(owner), m_name(name), m_units(units), m_group(group), m_value(new T(defaultValue)), m_own(true),
|
|
m_HasRange(false), m_HasDefault(true), m_Default(defaultValue), m_ReadOnly(false) {
|
|
if (m_owner) m_owner->RegisterProperty(this);
|
|
}
|
|
|
|
virtual ~Property() { if (m_own) delete m_value; }
|
|
|
|
// Identification
|
|
virtual const std::string& GetName() const override { return m_name; }
|
|
virtual const char* GetTypeName() const override { return typeid(T).name(); }
|
|
virtual std::type_index GetTypeIndex() const override { return std::type_index(typeid(T)); }
|
|
virtual const std::string& GetUnits() const override { return m_units; }
|
|
virtual void SetUnits(const std::string& units) override { m_units = units; }
|
|
virtual const std::string& GetGroup() const override { return m_group; }
|
|
virtual void SetGroup(const std::string& group) override { m_group = group; }
|
|
|
|
std::string GetValueAsString() const override {
|
|
try { return boost::lexical_cast<std::string>(*m_value); }
|
|
catch (...) { std::stringstream ss; ss << *m_value; return ss.str(); }
|
|
}
|
|
|
|
// Accessors
|
|
const T& Get() const { return *m_value; }
|
|
void Set(const T& value) {
|
|
if (!m_value) return;
|
|
T val = value;
|
|
if constexpr (std::is_arithmetic<T>::value) {
|
|
if (m_HasRange) { if (val < m_Min) val = m_Min; if (val > m_Max) val = m_Max; }
|
|
}
|
|
if (*m_value != val) {
|
|
*m_value = val;
|
|
ULIB_SIGNAL_EMIT(Property<T>::PropertyChanged);
|
|
this->Updated();
|
|
if (m_owner) m_owner->Updated();
|
|
}
|
|
}
|
|
|
|
void SetRange(const T& min, const T& max) { m_Min = min; m_Max = max; m_HasRange = true; }
|
|
void SetDefault(const T& def) { m_Default = def; m_HasDefault = true; }
|
|
void SetReadOnly(bool ro) { m_ReadOnly = ro; }
|
|
|
|
virtual bool IsReadOnly() const override { return m_ReadOnly; }
|
|
virtual bool HasRange() const override { return m_HasRange; }
|
|
virtual double GetMin() const override { return m_HasRange ? convert_to_double(m_Min) : 0.0; }
|
|
virtual double GetMax() const override { return m_HasRange ? convert_to_double(m_Max) : 0.0; }
|
|
|
|
const T& GetMinTyped() const { return m_Min; }
|
|
const T& GetMaxTyped() const { return m_Max; }
|
|
|
|
virtual bool HasDefault() const override { return m_HasDefault; }
|
|
virtual std::string GetDefaultValueAsString() const override {
|
|
try { return boost::lexical_cast<std::string>(m_Default); } catch (...) { return ""; }
|
|
}
|
|
|
|
// Operators
|
|
operator const T&() const { return *m_value; }
|
|
Property& operator=(const T& value) { Set(value); return *this; }
|
|
|
|
signals:
|
|
virtual void PropertyChanged() { ULIB_SIGNAL_EMIT(Property<T>::PropertyChanged); }
|
|
|
|
private:
|
|
template <typename U>
|
|
static double convert_to_double(const U& val) {
|
|
return convert_to_double_impl(val, typename std::is_arithmetic<U>::type());
|
|
}
|
|
template <typename U>
|
|
static double convert_to_double_impl(const U& val, std::true_type) { return (double)val; }
|
|
template <typename U>
|
|
static double convert_to_double_impl(const U& val, std::false_type) { return 0.0; }
|
|
|
|
public:
|
|
// Serialization
|
|
template <class ArchiveT>
|
|
void serialize_helper(ArchiveT & ar, const unsigned int version) {
|
|
ar & boost::serialization::make_hrp(m_name.c_str(), *m_value, m_units.c_str());
|
|
}
|
|
|
|
virtual void serialize(Archive::xml_oarchive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
|
virtual void serialize(Archive::xml_iarchive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
|
virtual void serialize(Archive::text_oarchive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
|
virtual void serialize(Archive::text_iarchive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
|
virtual void serialize(Archive::hrt_oarchive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
|
virtual void serialize(Archive::hrt_iarchive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
|
virtual void serialize(Archive::log_archive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
|
|
|
virtual void serialize(Archive::property_register_archive & ar, const unsigned int v) override;
|
|
|
|
|
|
protected:
|
|
std::string m_name;
|
|
std::string m_units;
|
|
std::string m_group;
|
|
T* m_value;
|
|
bool m_own;
|
|
Object* m_owner;
|
|
bool m_HasRange;
|
|
T m_Min;
|
|
T m_Max;
|
|
bool m_HasDefault;
|
|
T m_Default;
|
|
bool m_ReadOnly;
|
|
};
|
|
|
|
/**
|
|
* @brief Property specialized for enumerations.
|
|
*/
|
|
class EnumProperty : public Property<int> {
|
|
public:
|
|
EnumProperty(Object* owner, const std::string& name, int* valuePtr, const std::vector<std::string>& labels, const std::string& units = "", const std::string& group = "")
|
|
: Property<int>(owner, name, valuePtr, units, group), m_Labels(labels) {}
|
|
|
|
const std::vector<std::string>& GetEnumLabels() const override { return m_Labels; }
|
|
const char* GetTypeName() const override { return "Enum"; }
|
|
virtual std::type_index GetTypeIndex() const override { return std::type_index(typeid(EnumProperty)); }
|
|
|
|
template <class ArchiveT>
|
|
void serialize_enum_helper(ArchiveT & ar, const unsigned int version) {
|
|
ar & boost::serialization::make_hrp_enum(m_name.c_str(), *m_value, m_Labels, m_units.c_str());
|
|
}
|
|
|
|
virtual void serialize(Archive::xml_oarchive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
virtual void serialize(Archive::xml_iarchive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
virtual void serialize(Archive::text_oarchive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
virtual void serialize(Archive::text_iarchive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
virtual void serialize(Archive::hrt_oarchive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
virtual void serialize(Archive::hrt_iarchive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
virtual void serialize(Archive::log_archive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
|
|
virtual void serialize(Archive::property_register_archive & ar, const unsigned int v) override;
|
|
|
|
private:
|
|
std::vector<std::string> m_Labels;
|
|
};
|
|
|
|
} // namespace uLib
|
|
|
|
namespace uLib {
|
|
|
|
/**
|
|
* @brief Base class for reference properties (SmartPointer<T> fields).
|
|
* Provides a type-erased interface for getting/setting object references
|
|
* and checking type compatibility.
|
|
*/
|
|
class ReferencePropertyBase : public PropertyBase {
|
|
public:
|
|
virtual ~ReferencePropertyBase() {}
|
|
virtual Object* GetReferencedObject() const = 0;
|
|
virtual void SetReferencedObject(Object* obj) = 0;
|
|
virtual bool IsCompatible(Object* obj) const = 0;
|
|
virtual const char* GetReferenceTypeName() const = 0;
|
|
};
|
|
|
|
/**
|
|
* @brief Typed reference property for SmartPointer<T> fields.
|
|
* Filters context objects by dynamic_cast compatibility with T.
|
|
*/
|
|
template <typename T>
|
|
class ReferenceProperty : public ReferencePropertyBase {
|
|
public:
|
|
ReferenceProperty(Object* owner, const std::string& name, SmartPointer<T>& ref,
|
|
const std::string& units = "", const std::string& group = "")
|
|
: m_owner(owner), m_name(name), m_units(units), m_group(group), m_ref(ref), m_ReadOnly(false) {
|
|
if (m_owner) m_owner->RegisterProperty(this);
|
|
}
|
|
|
|
virtual ~ReferenceProperty() {}
|
|
|
|
// PropertyBase interface
|
|
virtual const std::string& GetName() const override { return m_name; }
|
|
virtual const char* GetTypeName() const override { return typeid(SmartPointer<T>).name(); }
|
|
virtual std::type_index GetTypeIndex() const override { return std::type_index(typeid(ReferencePropertyBase)); }
|
|
virtual const std::string& GetUnits() const override { return m_units; }
|
|
virtual void SetUnits(const std::string& units) override { m_units = units; }
|
|
virtual const std::string& GetGroup() const override { return m_group; }
|
|
virtual void SetGroup(const std::string& group) override { m_group = group; }
|
|
virtual bool IsReadOnly() const override { return m_ReadOnly; }
|
|
void SetReadOnly(bool ro) { m_ReadOnly = ro; }
|
|
|
|
virtual std::string GetValueAsString() const override {
|
|
T* ptr = m_ref.Get();
|
|
if (!ptr) return "(none)";
|
|
Object* obj = dynamic_cast<Object*>(ptr);
|
|
if (obj) {
|
|
std::string iname = obj->GetInstanceName();
|
|
if (!iname.empty()) return iname;
|
|
return obj->GetClassName();
|
|
}
|
|
return "(set)";
|
|
}
|
|
|
|
// ReferencePropertyBase interface
|
|
virtual Object* GetReferencedObject() const override {
|
|
return dynamic_cast<Object*>(m_ref.Get());
|
|
}
|
|
|
|
virtual void SetReferencedObject(Object* obj) override {
|
|
if (!obj) {
|
|
m_ref = SmartPointer<T>(nullptr);
|
|
this->Updated();
|
|
if (m_owner) m_owner->Updated();
|
|
return;
|
|
}
|
|
T* casted = dynamic_cast<T*>(obj);
|
|
if (casted) {
|
|
m_ref = SmartPointer<T>(casted);
|
|
this->Updated();
|
|
if (m_owner) m_owner->Updated();
|
|
}
|
|
}
|
|
|
|
virtual bool IsCompatible(Object* obj) const override {
|
|
return dynamic_cast<T*>(obj) != nullptr;
|
|
}
|
|
|
|
virtual const char* GetReferenceTypeName() const override {
|
|
return typeid(T).name();
|
|
}
|
|
|
|
// Serialization stubs
|
|
virtual void serialize(Archive::xml_oarchive & ar, const unsigned int v) override {}
|
|
virtual void serialize(Archive::xml_iarchive & ar, const unsigned int v) override {}
|
|
virtual void serialize(Archive::text_oarchive & ar, const unsigned int v) override {}
|
|
virtual void serialize(Archive::text_iarchive & ar, const unsigned int v) override {}
|
|
virtual void serialize(Archive::hrt_oarchive & ar, const unsigned int v) override {}
|
|
virtual void serialize(Archive::hrt_iarchive & ar, const unsigned int v) override {}
|
|
virtual void serialize(Archive::log_archive & ar, const unsigned int v) override {}
|
|
virtual void serialize(Archive::property_register_archive & ar, const unsigned int v) override {}
|
|
|
|
private:
|
|
Object* m_owner;
|
|
std::string m_name;
|
|
std::string m_units;
|
|
std::string m_group;
|
|
SmartPointer<T>& m_ref;
|
|
bool m_ReadOnly;
|
|
};
|
|
|
|
} // namespace uLib
|
|
|
|
namespace uLib {
|
|
namespace Archive {
|
|
|
|
class property_register_archive
|
|
: public boost::archive::detail::common_oarchive<property_register_archive> {
|
|
protected:
|
|
Object* m_Object;
|
|
bool m_DisplayOnly;
|
|
public:
|
|
friend class boost::archive::detail::interface_oarchive<property_register_archive>;
|
|
friend class boost::archive::save_access;
|
|
|
|
using boost::archive::detail::common_oarchive<property_register_archive>::save_override;
|
|
|
|
property_register_archive(Object* obj, bool displayOnly = false) :
|
|
boost::archive::detail::common_oarchive<property_register_archive>(boost::archive::no_header),
|
|
m_Object(obj), m_DisplayOnly(displayOnly) {
|
|
if (obj) m_Visited.insert(dynamic_cast<const void*>(obj));
|
|
}
|
|
|
|
template<class T> property_register_archive &operator&(const T &t) { this->save_override(t); return *this; }
|
|
template<class T> property_register_archive &operator<<(const T &t) { this->save_override(t); return *this; }
|
|
|
|
std::string GetCurrentGroup() const {
|
|
std::string group;
|
|
for (const auto& g : m_GroupStack) {
|
|
if (!group.empty()) group += ".";
|
|
group += g;
|
|
}
|
|
return group;
|
|
}
|
|
|
|
template<class T> void register_property(Property<T>& p) {
|
|
save_property_impl(p.GetName().c_str(), const_cast<T&>(p.Get()), p.GetUnits().c_str(),
|
|
p.HasRange(), p.GetMinTyped(), p.GetMaxTyped(), p.IsReadOnly());
|
|
}
|
|
|
|
void register_enum_property(EnumProperty& p) {
|
|
if (!m_Object) return;
|
|
EnumProperty* newP = new EnumProperty(m_Object, p.GetName(), const_cast<int*>(&p.Get()), p.GetEnumLabels(), p.GetUnits(), GetCurrentGroup());
|
|
newP->SetReadOnly(p.IsReadOnly());
|
|
if (m_DisplayOnly) {
|
|
m_Object->RegisterDisplayProperty(newP);
|
|
Object* obj = m_Object;
|
|
Object::connect(newP, &Object::Updated, [obj]() { obj->Updated(); });
|
|
} else {
|
|
m_Object->RegisterDynamicProperty(newP);
|
|
}
|
|
}
|
|
|
|
template<class T> void save_property_impl(const char* name, T& val, const char* units, bool hasRange, const T& minVal, const T& maxVal, bool isReadOnly) {
|
|
if (!m_Object) return;
|
|
if constexpr (is_smart_pointer<T>::value) {
|
|
// SmartPointer<U> field: create a ReferenceProperty<U> for type-safe selection
|
|
using ElementT = typename smart_pointer_element<T>::type;
|
|
auto* p = new ReferenceProperty<ElementT>(m_Object, name, val, units ? units : "", GetCurrentGroup());
|
|
p->SetReadOnly(isReadOnly);
|
|
if (m_DisplayOnly) {
|
|
m_Object->RegisterDisplayProperty(p);
|
|
Object* obj = m_Object;
|
|
Object::connect(p, &Object::Updated, [obj]() { obj->Updated(); });
|
|
} else {
|
|
m_Object->RegisterDynamicProperty(p);
|
|
}
|
|
} else {
|
|
Property<T>* p = new Property<T>(m_Object, name, &val, units ? units : "", GetCurrentGroup());
|
|
set_range_helper(p, hasRange, minVal, maxVal, typename std::is_arithmetic<T>::type());
|
|
p->SetReadOnly(isReadOnly);
|
|
if (m_DisplayOnly) {
|
|
m_Object->RegisterDisplayProperty(p);
|
|
Object* obj = m_Object;
|
|
Object::connect(p, &Object::Updated, [obj]() { obj->Updated(); });
|
|
} else {
|
|
m_Object->RegisterDynamicProperty(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<class U> static void set_range_helper(Property<U>* p, bool hasRange, const U& minVal, const U& maxVal, std::true_type) { if (hasRange) p->SetRange(minVal, maxVal); }
|
|
template<class U> static void set_range_helper(Property<U>* p, bool hasRange, const U& minVal, const U& maxVal, std::false_type) {}
|
|
|
|
template<class T> void save_override(const boost::serialization::hrp<T> &t) {
|
|
// To handle T correctly without deduction issues, we assume T can be passed to save_property_impl
|
|
T dummy = T(); // Ensure we can construct T
|
|
save_property_impl(t.name(), const_cast<boost::serialization::hrp<T>&>(t).value(), t.units(), t.has_range(), t.has_range() ? t.min_val() : dummy, t.has_range() ? t.max_val() : dummy, t.is_read_only());
|
|
}
|
|
template<class T> void save_override(const boost::serialization::hrp_val<T> &t) {
|
|
T dummy = T();
|
|
save_property_impl(t.name(), const_cast<boost::serialization::hrp_val<T>&>(t).value(), t.units(), t.has_range(), t.has_range() ? t.min_val() : dummy, t.has_range() ? t.max_val() : dummy, t.is_read_only());
|
|
}
|
|
template<class T> void save_override(const boost::serialization::hrp_enum<T> &t) {
|
|
if (m_Object) {
|
|
EnumProperty* p = new EnumProperty(m_Object, t.name(), (int*)&const_cast<boost::serialization::hrp_enum<T>&>(t).value(), t.labels(), t.units() ? t.units() : "", GetCurrentGroup());
|
|
p->SetReadOnly(t.is_read_only());
|
|
if (m_DisplayOnly) { m_Object->RegisterDisplayProperty(p); Object* obj = m_Object; Object::connect(p, &Object::Updated, [obj]() { obj->Updated(); }); }
|
|
else { m_Object->RegisterDynamicProperty(p); }
|
|
}
|
|
}
|
|
template<class T> void save_override(const boost::serialization::hrp_enum_val<T> &t) {
|
|
if (m_Object) {
|
|
EnumProperty* p = new EnumProperty(m_Object, t.name(), (int*)&const_cast<boost::serialization::hrp_enum_val<T>&>(t).value(), t.labels(), t.units() ? t.units() : "", GetCurrentGroup());
|
|
p->SetReadOnly(t.is_read_only());
|
|
if (m_DisplayOnly) { m_Object->RegisterDisplayProperty(p); Object* obj = m_Object; Object::connect(p, &Object::Updated, [obj]() { obj->Updated(); }); }
|
|
else { m_Object->RegisterDynamicProperty(p); }
|
|
}
|
|
}
|
|
|
|
template<class T> void save_override(const boost::serialization::nvp<T> &t) {
|
|
if (t.name()) m_GroupStack.push_back(t.name());
|
|
this->save_helper(t.const_value(), typename boost::is_class<T>::type());
|
|
if (t.name()) m_GroupStack.pop_back();
|
|
}
|
|
|
|
void save_override(const std::string &t) {}
|
|
template<class T> void save_override(T * const & t) {
|
|
if (!t) return;
|
|
this->save_pointer_helper(t, typename boost::is_base_of<Object, T>::type());
|
|
}
|
|
template<class T> void save_pointer_helper(T* t, boost::mpl::true_) {
|
|
const void* ptr = dynamic_cast<const void*>(t);
|
|
if (m_Visited.find(ptr) != m_Visited.end()) return;
|
|
m_Visited.insert(ptr);
|
|
this->save_override(*t);
|
|
}
|
|
template<class T> void save_pointer_helper(T* t, boost::mpl::false_) {}
|
|
template<class T> void save_override(const T &t) { this->save_helper(t, typename boost::is_class<T>::type()); }
|
|
template<class T> void save_helper(const T &t, boost::mpl::true_) { boost::serialization::serialize_adl(*this, const_cast<T&>(t), 0); }
|
|
void save_helper(const std::string &t, boost::mpl::true_) {}
|
|
template<class T> void save_helper(const T &t, boost::mpl::false_) {}
|
|
|
|
void save_override(const boost::archive::object_id_type & t) {}
|
|
void save_override(const boost::archive::object_reference_type & t) {}
|
|
void save_override(const boost::archive::version_type & t) {}
|
|
void save_override(const boost::archive::class_id_type & t) {}
|
|
void save_override(const boost::archive::class_id_optional_type & t) {}
|
|
void save_override(const boost::archive::class_id_reference_type & t) {}
|
|
void save_override(const boost::archive::class_name_type & t) {}
|
|
void save_override(const boost::archive::tracking_type & t) {}
|
|
|
|
protected:
|
|
std::vector<std::string> m_GroupStack;
|
|
std::set<const void*> m_Visited;
|
|
};
|
|
|
|
} // namespace Archive
|
|
} // namespace uLib
|
|
|
|
namespace uLib {
|
|
|
|
template <typename T>
|
|
inline void Property<T>::serialize(Archive::property_register_archive & ar, const unsigned int v) {
|
|
ar.register_property(*this);
|
|
}
|
|
|
|
inline void EnumProperty::serialize(Archive::property_register_archive & ar, const unsigned int v) {
|
|
ar.register_enum_property(*this);
|
|
}
|
|
|
|
namespace Archive {
|
|
|
|
#define ULIB_ACTIVATE_PROPERTIES(obj) \
|
|
{ uLib::Archive::property_register_archive _ar_tmp(&(obj)); _ar_tmp & (obj); }
|
|
|
|
#define ULIB_DECLARE_PROPERTIES(SelfType) \
|
|
private: \
|
|
struct _PropActivator { \
|
|
_PropActivator(SelfType* self) { \
|
|
uLib::Archive::property_register_archive _ar(self); \
|
|
_ar & *self; \
|
|
} \
|
|
} _prop_activator{this};
|
|
|
|
} // namespace Archive
|
|
|
|
// Convenience macro: declares a named Property<T> member with a default value.
|
|
// Usage inside a class body (requires 'this' to be available, so use in-class initializer):
|
|
// ULIB_PROPERTY(int, MyProp, 42)
|
|
#define ULIB_PROPERTY(type, name, defaultVal) \
|
|
::uLib::Property<type> name{this, #name, (type)(defaultVal)};
|
|
|
|
// Common property type aliases
|
|
typedef Property<bool> BoolProperty;
|
|
typedef Property<int> IntProperty;
|
|
typedef Property<float> FloatProperty;
|
|
typedef Property<double> DoubleProperty;
|
|
typedef Property<std::string> StringProperty;
|
|
|
|
template <class ArchiveT>
|
|
void serialize_properties_helper(ArchiveT &ar, const std::vector<PropertyBase*> &props, unsigned int version) {
|
|
for (auto* prop : props) prop->serialize(ar, version);
|
|
}
|
|
|
|
template <class ArchiveT>
|
|
void Object::serialize(ArchiveT &ar, const unsigned int version) {
|
|
ar & boost::serialization::make_nvp("InstanceName", this->GetInstanceName());
|
|
serialize_properties_helper(ar, this->GetProperties(), version);
|
|
}
|
|
|
|
} // namespace uLib
|
|
|
|
#endif // U_CORE_PROPERTY_H
|