mirror of https://github.com/SeanOMik/libki.git
etc: Combine IProperty with IDynamicProperty, and cleanup StaticProperty
This commit is contained in:
parent
f3aa42578d
commit
b5559834ac
|
@ -32,15 +32,18 @@ namespace pclass
|
||||||
|
|
||||||
virtual bool is_pointer() const;
|
virtual bool is_pointer() const;
|
||||||
virtual bool is_dynamic() const;
|
virtual bool is_dynamic() const;
|
||||||
|
virtual bool is_array() const;
|
||||||
|
virtual std::size_t get_element_count() const;
|
||||||
|
virtual void set_element_count(std::size_t size) = 0;
|
||||||
|
|
||||||
virtual Value get_value() const = 0;
|
virtual Value get_value(std::size_t index = 0) const = 0;
|
||||||
virtual void set_value(Value value) = 0;
|
virtual void set_value(Value value, std::size_t index = 0) = 0;
|
||||||
|
|
||||||
virtual const PropertyClass *get_object() const = 0;
|
virtual const PropertyClass *get_object(std::size_t index = 0) const = 0;
|
||||||
virtual void set_object(std::unique_ptr<PropertyClass> &object) = 0;
|
virtual void set_object(std::unique_ptr<PropertyClass> &object, std::size_t index = 0) = 0;
|
||||||
|
|
||||||
virtual void write_value_to(BitStream &stream) const = 0;
|
virtual void write_value_to(BitStream &stream, std::size_t index = 0) const = 0;
|
||||||
virtual void read_value_from(BitStream &stream) = 0;
|
virtual void read_value_from(BitStream &stream, std::size_t index = 0) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const PropertyClass *m_instance;
|
const PropertyClass *m_instance;
|
||||||
|
@ -49,41 +52,5 @@ namespace pclass
|
||||||
hash_t m_full_hash;
|
hash_t m_full_hash;
|
||||||
const Type *m_type;
|
const Type *m_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Documentation
|
|
||||||
*/
|
|
||||||
class IDynamicProperty : public IProperty
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Do not allow copy assignment. Once a property has been constructed,
|
|
||||||
// it shouldn't be able to change.
|
|
||||||
IDynamicProperty & operator=(const IDynamicProperty &that) = delete;
|
|
||||||
|
|
||||||
IDynamicProperty(PropertyClass &object,
|
|
||||||
const std::string &name, const Type &type);
|
|
||||||
IDynamicProperty(PropertyClass &object,
|
|
||||||
const IDynamicProperty &that);
|
|
||||||
|
|
||||||
virtual ~IDynamicProperty() {}
|
|
||||||
|
|
||||||
bool is_dynamic() const override;
|
|
||||||
virtual std::size_t get_element_count() const = 0;
|
|
||||||
virtual void set_element_count(std::size_t size) = 0;
|
|
||||||
|
|
||||||
Value get_value() const final override;
|
|
||||||
void set_value(Value value) final override;
|
|
||||||
const PropertyClass *get_object() const final override;
|
|
||||||
void set_object(std::unique_ptr<PropertyClass> &object) final override;
|
|
||||||
void write_value_to(BitStream &stream) const final override;
|
|
||||||
void read_value_from(BitStream &stream) final override;
|
|
||||||
|
|
||||||
virtual Value get_value(int index) const = 0;
|
|
||||||
virtual void set_value(Value value, int index) = 0;
|
|
||||||
virtual const PropertyClass *get_object(int index) const = 0;
|
|
||||||
virtual void set_object(std::unique_ptr<PropertyClass> &object, int index) = 0;
|
|
||||||
virtual void write_value_to(BitStream &stream, int index) const = 0;
|
|
||||||
virtual void read_value_from(BitStream &stream, int index) = 0;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,6 @@ namespace pclass
|
||||||
PropertyList &get_properties();
|
PropertyList &get_properties();
|
||||||
const PropertyList &get_properties() const;
|
const PropertyList &get_properties() const;
|
||||||
|
|
||||||
virtual PropertyClass *copy() const;
|
|
||||||
virtual void on_created() const {}
|
virtual void on_created() const {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -11,426 +11,415 @@ namespace pclass
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
class StaticProperty;
|
class StaticProperty;
|
||||||
|
|
||||||
/// @cond DOXYGEN_SKIP
|
namespace detail
|
||||||
/**
|
|
||||||
* A helper utility that provides the right implementation of construct(),
|
|
||||||
* copy(), get_object() and set_object(), based on characteristics of type: ValueT.
|
|
||||||
*/
|
|
||||||
template <
|
|
||||||
typename ValueT,
|
|
||||||
typename IsPointerEnable = void,
|
|
||||||
typename IsBaseEnable = void
|
|
||||||
>
|
|
||||||
struct value_object_helper
|
|
||||||
{
|
{
|
||||||
static ValueT construct(const Type &type)
|
/**
|
||||||
|
* Provides default implementations for static_object_helper.
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
struct default_static_object_helper
|
||||||
{
|
{
|
||||||
// In cases where ValueT is not a pointer, and does not derive from PropertyClass,
|
static ValueT construct(const Type &type)
|
||||||
// just call the default constructor.
|
{
|
||||||
return ValueT();
|
// In cases where ValueT is not a pointer, and does not derive from PropertyClass,
|
||||||
}
|
// just call the default constructor.
|
||||||
|
return ValueT();
|
||||||
|
}
|
||||||
|
|
||||||
static ValueT copy(const StaticProperty<ValueT> &prop)
|
static ValueT copy(const StaticProperty<ValueT> &prop)
|
||||||
|
{
|
||||||
|
// In cases where ValueT is not a pointer, and does not derive from PropertyClass,
|
||||||
|
// just call the copy constructor.
|
||||||
|
return ValueT(prop.m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PropertyClass *get_object(
|
||||||
|
const StaticProperty<ValueT> &prop, int index)
|
||||||
|
{
|
||||||
|
// By default, assume that ValueT is not a
|
||||||
|
throw runtime_error(
|
||||||
|
"Tried calling get_object() on a property that does not store an object."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_object(StaticProperty<ValueT> &prop,
|
||||||
|
std::unique_ptr<PropertyClass> &object, int index)
|
||||||
|
{
|
||||||
|
throw runtime_error(
|
||||||
|
"Tried calling set_object() on a property that does not store an object."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialization for when ValueT is an explicitly-sized array.
|
||||||
|
* Removes construct() and copy() to stop the compiler complaining about
|
||||||
|
* a function returning an array.
|
||||||
|
*/
|
||||||
|
template <typename ValueT, int N>
|
||||||
|
struct default_static_object_helper<ValueT[N]>
|
||||||
{
|
{
|
||||||
// In cases where ValueT is not a pointer, and does not derive from PropertyClass,
|
static const PropertyClass *get_object(
|
||||||
// just call the copy constructor.
|
const StaticProperty<ValueT[N]> &prop, int index)
|
||||||
return ValueT(prop.m_value);
|
{
|
||||||
}
|
// By default, assume that ValueT is not a
|
||||||
|
throw runtime_error(
|
||||||
|
"Tried calling get_object() on a property that does not store an object."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static Value get_value(const StaticProperty<ValueT> &prop)
|
static void set_object(StaticProperty<ValueT[N]> &prop,
|
||||||
|
std::unique_ptr<PropertyClass> &object, int index)
|
||||||
|
{
|
||||||
|
throw runtime_error(
|
||||||
|
"Tried calling set_object() on a property that does not store an object."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides default implementations of construct() and copy()
|
||||||
|
* for static_object_helper where ValueT is a pointer type.
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
struct pointer_static_object_helper
|
||||||
{
|
{
|
||||||
// Return a reference to the property's value
|
static ValueT *construct(const Type &type)
|
||||||
return Value::make_reference<ValueT>(prop.m_value);
|
{
|
||||||
}
|
// The default value of pointers is null
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
static void set_value(StaticProperty<ValueT> &prop, Value value)
|
static ValueT *copy(const StaticProperty<ValueT *> &prop)
|
||||||
|
{
|
||||||
|
// The copy constructor for all pointers is to copy the pointer
|
||||||
|
// without creating a new copy of the object it's pointing to.
|
||||||
|
return prop.m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PropertyClass *get_object(
|
||||||
|
const StaticProperty<ValueT *> &prop, int index)
|
||||||
|
{
|
||||||
|
// By default, assume that ValueT is not a
|
||||||
|
throw runtime_error(
|
||||||
|
"Tried calling get_object() on a property that does not store an object."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_object(StaticProperty<ValueT *> &prop,
|
||||||
|
std::unique_ptr<PropertyClass> &object, int index)
|
||||||
|
{
|
||||||
|
throw runtime_error(
|
||||||
|
"Tried calling set_object() on a property that does not store an object."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper utility that provides the right implementation of construct(),
|
||||||
|
* copy(), get_object() and set_object(), based on characteristics of type: ValueT.
|
||||||
|
*/
|
||||||
|
template <
|
||||||
|
typename ValueT,
|
||||||
|
typename Enable = void
|
||||||
|
>
|
||||||
|
struct static_object_helper : default_static_object_helper<ValueT>
|
||||||
{
|
{
|
||||||
prop.m_value = value
|
using default_static_object_helper<ValueT>::construct;
|
||||||
.dereference<ValueT>()
|
using default_static_object_helper<ValueT>::copy;
|
||||||
.get<ValueT>();
|
using default_static_object_helper<ValueT>::get_object;
|
||||||
}
|
using default_static_object_helper<ValueT>::set_object;
|
||||||
|
};
|
||||||
|
|
||||||
static const PropertyClass *get_object(const StaticProperty<ValueT> &prop)
|
/**
|
||||||
|
* Specialization for when ValueT is:
|
||||||
|
* - Not a pointer; but
|
||||||
|
* - does derive from PropertyClass
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
struct static_object_helper<
|
||||||
|
ValueT,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_base_of<PropertyClass, ValueT>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
|
: default_static_object_helper<ValueT>
|
||||||
{
|
{
|
||||||
// ValueT does not derive from PropertyClass, and so, this property is not
|
using default_static_object_helper<ValueT>::copy;
|
||||||
// storing an object.
|
|
||||||
throw runtime_error(
|
|
||||||
"Tried calling get_object() on a property that does not store an object."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_object(StaticProperty<ValueT> &prop,
|
static ValueT construct(const Type &type)
|
||||||
std::unique_ptr<PropertyClass> &object)
|
{
|
||||||
|
// Derivitives of PropertyClass cannot have a default constructor since
|
||||||
|
// they require their Type and TypeSystem, so we need to pass these
|
||||||
|
// along from what the StaticProperty constructor has been given.
|
||||||
|
return ValueT(type, type.get_type_system());
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PropertyClass *get_object(
|
||||||
|
const StaticProperty<ValueT> &prop, int index)
|
||||||
|
{
|
||||||
|
// ValueT does derive from PropertyClass, and we have an instance of ValueT,
|
||||||
|
// so we can cast down to a PropertyClass pointer.
|
||||||
|
return dynamic_cast<const PropertyClass *>(&prop.m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_object(StaticProperty<ValueT> &prop,
|
||||||
|
std::unique_ptr<PropertyClass> &object, int index)
|
||||||
|
{
|
||||||
|
// Ensure that object is not nullptr
|
||||||
|
if (!object)
|
||||||
|
throw runtime_error("Value cannot be null.");
|
||||||
|
|
||||||
|
// Ensure that object is exactly the type of the property.
|
||||||
|
assert_type_match(prop.get_type(), object->get_type());
|
||||||
|
|
||||||
|
// ValueT does derive from PropertyClass, but we don't store a pointer,
|
||||||
|
// so we need to copy the value in.
|
||||||
|
prop.m_value = *dynamic_cast<ValueT *>(object.get());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialization for when ValueT is:
|
||||||
|
* - A pointer; but
|
||||||
|
* - does not derive from PropertyClass
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
struct static_object_helper<
|
||||||
|
ValueT *,
|
||||||
|
typename std::enable_if<
|
||||||
|
!std::is_base_of<PropertyClass, ValueT>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
|
: pointer_static_object_helper<ValueT>
|
||||||
{
|
{
|
||||||
// ValueT does not derive from PropertyClass, and so, this property is not
|
using pointer_static_object_helper<ValueT>::construct;
|
||||||
// storing an object.
|
using pointer_static_object_helper<ValueT>::copy;
|
||||||
throw runtime_error(
|
using pointer_static_object_helper<ValueT>::get_object;
|
||||||
"Tried calling set_object() on a property that does not store an object."
|
using pointer_static_object_helper<ValueT>::set_object;
|
||||||
);
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specialization for when ValueT is:
|
* Specialization for when ValueT is:
|
||||||
* - A pointer; but
|
* - A pointer; and
|
||||||
* - does not derive from PropertyClass
|
* - does derive from PropertyClass
|
||||||
*
|
*/
|
||||||
* This should:
|
template <typename ValueT>
|
||||||
* - Construct to a nullptr;
|
struct static_object_helper<
|
||||||
* - Copy construct to the same pointer as the original; and
|
ValueT *,
|
||||||
* - Throw an exception when get_object() or set_object() is called.
|
typename std::enable_if<
|
||||||
*/
|
std::is_base_of<PropertyClass, ValueT>::value
|
||||||
template <typename ValueT>
|
>::type
|
||||||
struct value_object_helper<
|
>
|
||||||
ValueT,
|
: pointer_static_object_helper<ValueT>
|
||||||
typename std::enable_if<
|
|
||||||
std::is_pointer<ValueT>::value
|
|
||||||
>::type,
|
|
||||||
typename std::enable_if<
|
|
||||||
!std::is_base_of<
|
|
||||||
PropertyClass,
|
|
||||||
typename std::remove_pointer<ValueT>::type
|
|
||||||
>::value
|
|
||||||
>::type
|
|
||||||
>
|
|
||||||
{
|
|
||||||
using nonpointer_type = typename std::remove_pointer<ValueT>::type;
|
|
||||||
|
|
||||||
static ValueT construct(const Type &type)
|
|
||||||
{
|
{
|
||||||
// The default value of pointers is null
|
using pointer_static_object_helper<ValueT>::construct;
|
||||||
return nullptr;
|
using pointer_static_object_helper<ValueT>::copy;
|
||||||
}
|
|
||||||
|
|
||||||
static ValueT copy(const StaticProperty<ValueT> &prop)
|
static const PropertyClass *get_object(
|
||||||
|
const StaticProperty<ValueT *> &prop, int index)
|
||||||
|
{
|
||||||
|
// ValueT does derive from PropertyClass, and we have a pointer to an instance
|
||||||
|
// of ValueT, so we can cast down to a PropertyClass pointer.
|
||||||
|
return dynamic_cast<const PropertyClass *>(prop.m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_object(StaticProperty<ValueT *> &prop,
|
||||||
|
std::unique_ptr<PropertyClass> &object, int index)
|
||||||
|
{
|
||||||
|
// Ensure that object inherits the type of the property
|
||||||
|
if (object)
|
||||||
|
assert_type_match(prop.get_type(), object->get_type(), true);
|
||||||
|
|
||||||
|
// ValueT does derive from PropertyClass, and we have a pointer to an instance
|
||||||
|
// of PropertyClass, so cast the pointer up to a ValueT.
|
||||||
|
prop.m_value = dynamic_cast<ValueT *>(object.release());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialization for when ValueT is:
|
||||||
|
* - An explicitly-sized array; and
|
||||||
|
* - does not derive from PropertyClass
|
||||||
|
*/
|
||||||
|
template <typename ValueT, int N>
|
||||||
|
struct static_object_helper<
|
||||||
|
ValueT[N],
|
||||||
|
typename std::enable_if<
|
||||||
|
!std::is_base_of<PropertyClass, ValueT>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
|
: default_static_object_helper<ValueT[N]>
|
||||||
{
|
{
|
||||||
// The copy constructor for all pointers is to copy the pointer
|
using default_static_object_helper<ValueT[N]>::get_object;
|
||||||
// without creating a new copy of the object it's pointing to.
|
using default_static_object_helper<ValueT[N]>::set_object;
|
||||||
return prop.m_value;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static Value get_value(const StaticProperty<ValueT> &prop)
|
/**
|
||||||
|
* Specialization for when ValueT is:
|
||||||
|
* - An explicitly-sized array of non-pointer values; and
|
||||||
|
* - does derive from PropertyClass
|
||||||
|
*/
|
||||||
|
template <typename ValueT, int N>
|
||||||
|
struct static_object_helper<
|
||||||
|
ValueT[N],
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_base_of<PropertyClass, ValueT>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
{
|
{
|
||||||
return Value::make_reference<nonpointer_type>(*prop.m_value);
|
static const PropertyClass *get_object(
|
||||||
}
|
const StaticProperty<ValueT> &prop, const int index)
|
||||||
|
{
|
||||||
|
// ValueT does derive from PropertyClass, and we have an instance of ValueT,
|
||||||
|
// so we can cast down to a PropertyClass pointer.
|
||||||
|
return dynamic_cast<const PropertyClass *>(&prop.m_value[index]);
|
||||||
|
}
|
||||||
|
|
||||||
static void set_value(StaticProperty<ValueT> &prop, Value value)
|
static void set_object(StaticProperty<ValueT> &prop,
|
||||||
|
std::unique_ptr<PropertyClass> &object, const int index)
|
||||||
|
{
|
||||||
|
// Ensure that object is not nullptr
|
||||||
|
if (!object)
|
||||||
|
throw runtime_error("Value cannot be null.");
|
||||||
|
|
||||||
|
// Ensure that object is exactly the type of the property.
|
||||||
|
assert_type_match(prop.get_type(), object->get_type());
|
||||||
|
|
||||||
|
// ValueT does derive from PropertyClass, but we don't store a pointer,
|
||||||
|
// so we need to copy the value in.
|
||||||
|
prop.m_value[index] = *dynamic_cast<ValueT *>(object.get());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialization for when ValueT is:
|
||||||
|
* - An explicitly-sized array of pointer values; and
|
||||||
|
* - does derive from PropertyClass
|
||||||
|
*/
|
||||||
|
template <typename ValueT, int N>
|
||||||
|
struct static_object_helper<
|
||||||
|
ValueT *[N],
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_base_of<PropertyClass, ValueT>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
{
|
{
|
||||||
prop.m_value = value
|
static const PropertyClass *get_object(
|
||||||
.dereference<nonpointer_type>()
|
const StaticProperty<ValueT> &prop, const int index)
|
||||||
.take<nonpointer_type>();
|
{
|
||||||
}
|
// ValueT does derive from PropertyClass, and we have an instance of ValueT,
|
||||||
|
// so we can cast down to a PropertyClass pointer.
|
||||||
|
return dynamic_cast<const PropertyClass *>(prop.m_value[index]);
|
||||||
|
}
|
||||||
|
|
||||||
static const PropertyClass *get_object(const StaticProperty<ValueT> &prop)
|
static void set_object(StaticProperty<ValueT> &prop,
|
||||||
{
|
std::unique_ptr<PropertyClass> &object, const int index)
|
||||||
// ValueT does not derive from PropertyClass, and so, this property is not
|
{
|
||||||
// storing an object.
|
// Ensure that object inherits the type of the property
|
||||||
throw runtime_error(
|
if (object)
|
||||||
"Tried calling get_object() on a property that does not store an object."
|
assert_type_match(prop.get_type(), object->get_type(), true);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_object(StaticProperty<ValueT> &prop,
|
// ValueT does derive from PropertyClass, and we have a pointer to an instance
|
||||||
std::unique_ptr<PropertyClass> &object)
|
// of PropertyClass, so cast the pointer up to a ValueT.
|
||||||
{
|
prop.m_value[index] = dynamic_cast<ValueT *>(object.release());
|
||||||
// ValueT does not derive from PropertyClass, and so, this property is not
|
}
|
||||||
// storing an object.
|
};
|
||||||
throw runtime_error(
|
|
||||||
"Tried calling set_object() on a property that does not store an object."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specialization for when ValueT is:
|
|
||||||
* - A pointer; and
|
|
||||||
* - does derive from PropertyClass
|
|
||||||
*
|
|
||||||
* This should:
|
|
||||||
* - Construct to a nullptr;
|
|
||||||
* - Copy construct to the same pointer as the original;
|
|
||||||
* - Return a pointer to a ValueT instance (as a PropertyClass *)
|
|
||||||
* when get_object() is called; and
|
|
||||||
* - Throw an exception when the object supplied to set_object()
|
|
||||||
* does not inherit from the property's type, but set m_value otherwise.
|
|
||||||
*/
|
|
||||||
template <typename ValueT>
|
|
||||||
struct value_object_helper<
|
|
||||||
ValueT,
|
|
||||||
typename std::enable_if<
|
|
||||||
std::is_pointer<ValueT>::value
|
|
||||||
>::type,
|
|
||||||
typename std::enable_if<
|
|
||||||
std::is_base_of<
|
|
||||||
PropertyClass,
|
|
||||||
typename std::remove_pointer<ValueT>::type
|
|
||||||
>::value
|
|
||||||
>::type
|
|
||||||
>
|
|
||||||
{
|
|
||||||
using nonpointer_type = typename std::remove_pointer<ValueT>::type;
|
|
||||||
|
|
||||||
static ValueT construct(const Type &type)
|
|
||||||
{
|
|
||||||
// The default value of pointers is null
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ValueT copy(const StaticProperty<ValueT> &prop)
|
|
||||||
{
|
|
||||||
// The copy constructor for all pointers is to copy the pointer
|
|
||||||
// without creating a new copy of the object it's pointing to.
|
|
||||||
return prop.m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Value get_value(const StaticProperty<ValueT> &prop)
|
|
||||||
{
|
|
||||||
return Value::make_reference<nonpointer_type>(*prop.m_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_value(StaticProperty<ValueT> &prop, Value value)
|
|
||||||
{
|
|
||||||
prop.m_value = value
|
|
||||||
.dereference<nonpointer_type>()
|
|
||||||
.take<nonpointer_type>();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const PropertyClass *get_object(const StaticProperty<ValueT> &prop)
|
|
||||||
{
|
|
||||||
// ValueT does derive from PropertyClass, and we have a pointer to an instance
|
|
||||||
// of ValueT, so we can cast down to a PropertyClass pointer.
|
|
||||||
return dynamic_cast<const PropertyClass *>(prop.m_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_object(StaticProperty<ValueT> &prop,
|
|
||||||
std::unique_ptr<PropertyClass> &object)
|
|
||||||
{
|
|
||||||
// Ensure that object inherits the type of the property
|
|
||||||
if (object)
|
|
||||||
assert_type_match(prop.get_type(), object->get_type(), true);
|
|
||||||
|
|
||||||
// ValueT does derive from PropertyClass, and we have a pointer to an instance
|
|
||||||
// of PropertyClass, so cast the pointer up to a ValueT.
|
|
||||||
prop.m_value = dynamic_cast<ValueT>(object.release());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specialization for when ValueT is:
|
|
||||||
* - Not a pointer; and
|
|
||||||
* - does derive from PropertyClass
|
|
||||||
*
|
|
||||||
* This should:
|
|
||||||
* - Construct an instance of ValueT by passing the property
|
|
||||||
* type and the type's type system; and
|
|
||||||
* - Return a pointer to a ValueT instance (as a PropertyClass *)
|
|
||||||
* when get_object() is called.
|
|
||||||
*/
|
|
||||||
template <typename ValueT>
|
|
||||||
struct value_object_helper<
|
|
||||||
ValueT,
|
|
||||||
typename std::enable_if<
|
|
||||||
!std::is_pointer<ValueT>::value
|
|
||||||
>::type,
|
|
||||||
typename std::enable_if<
|
|
||||||
std::is_base_of<
|
|
||||||
PropertyClass,
|
|
||||||
typename std::remove_pointer<ValueT>::type
|
|
||||||
>::value
|
|
||||||
>::type
|
|
||||||
>
|
|
||||||
{
|
|
||||||
static ValueT construct(const Type &type)
|
|
||||||
{
|
|
||||||
// Derivitives of PropertyClass cannot have a default constructor since
|
|
||||||
// they require their Type and TypeSystem, so we need to pass these
|
|
||||||
// along from what the StaticProperty constructor has been given.
|
|
||||||
return ValueT(type, type.get_type_system());
|
|
||||||
}
|
|
||||||
|
|
||||||
static ValueT copy(const StaticProperty<ValueT> &prop)
|
|
||||||
{
|
|
||||||
// Derivitives of PropertyClass implement a clone method that returns
|
|
||||||
// a pointer to a copy.
|
|
||||||
ValueT *value_ptr = dynamic_cast<ValueT *>(prop.m_value.clone());
|
|
||||||
ValueT value = *value_ptr;
|
|
||||||
delete value_ptr;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Value get_value(const StaticProperty<ValueT> &prop)
|
|
||||||
{
|
|
||||||
return Value::make_reference<ValueT>(prop.m_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_value(StaticProperty<ValueT> &prop, Value value)
|
|
||||||
{
|
|
||||||
prop.m_value = value
|
|
||||||
.dereference<ValueT>()
|
|
||||||
.get<ValueT>();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const PropertyClass *get_object(const StaticProperty<ValueT> &prop)
|
|
||||||
{
|
|
||||||
// ValueT does derive from PropertyClass, and we have an instance of ValueT,
|
|
||||||
// so we can cast down to a PropertyClass pointer.
|
|
||||||
return dynamic_cast<const PropertyClass *>(&prop.m_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_object(StaticProperty<ValueT> &prop,
|
|
||||||
std::unique_ptr<PropertyClass> &object)
|
|
||||||
{
|
|
||||||
// Ensure that object is not nullptr
|
|
||||||
if (!object)
|
|
||||||
throw runtime_error("Value cannot be null.");
|
|
||||||
|
|
||||||
// Ensure that object is exactly the type of the property.
|
|
||||||
assert_type_match(prop.get_type(), object->get_type());
|
|
||||||
|
|
||||||
// ValueT does derive from PropertyClass, but we don't store a pointer,
|
|
||||||
// so we need to copy the value in.
|
|
||||||
prop.m_value = *dynamic_cast<ValueT *>(object.get());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper utility that provides the right implementation of write() and read()
|
* A helper utility that provides the right implementation of
|
||||||
* based on whether ValueT is a pointer.
|
* get_value() and set_value() based on whether ValueT is a pointer.
|
||||||
*/
|
*/
|
||||||
template <
|
template <typename ValueT>
|
||||||
typename ValueT,
|
struct static_value_helper
|
||||||
typename IsPointerEnable = void
|
|
||||||
>
|
|
||||||
struct value_rw_helper
|
|
||||||
{
|
|
||||||
static void write(const StaticProperty<ValueT> &prop, BitStream &stream)
|
|
||||||
{
|
{
|
||||||
prop.get_type().write_to(
|
static Value get_value(const StaticProperty<ValueT> &prop, int index)
|
||||||
stream,
|
{
|
||||||
Value::make_reference<ValueT>(prop.m_value)
|
return Value::make_reference<ValueT>(prop.m_value);
|
||||||
);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void read(StaticProperty<ValueT> &prop, BitStream &stream)
|
static void set_value(StaticProperty<ValueT> &prop, Value value, int index)
|
||||||
|
{
|
||||||
|
prop.m_value = value.as<ValueT>().get<ValueT>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialization for when ValueT is a pointer.
|
||||||
|
*
|
||||||
|
* Dereference the pointer before creating Value instances.
|
||||||
|
* This is so that the Value stores a pointer to a ValueT instance,
|
||||||
|
* rather than storing a pointer to a pointer.
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
struct static_value_helper<ValueT *>
|
||||||
{
|
{
|
||||||
Value value = prop.get_type().read_from(stream);
|
static Value get_value(const StaticProperty<ValueT *> &prop, int index)
|
||||||
prop.m_value = value.get<ValueT>();
|
{
|
||||||
}
|
return Value::make_reference<ValueT>(*prop.m_value);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
static void set_value(StaticProperty<ValueT *> &prop, Value value, int index)
|
||||||
* Specialization for when ValueT is a pointer.
|
{
|
||||||
*
|
prop.m_value = value.as<ValueT>().release<ValueT>();
|
||||||
* Dereference the pointer before creating Value instances.
|
}
|
||||||
* This is so that the Value stores a pointer to a ValueT instance,
|
};
|
||||||
* rather than storing a pointer to a pointer.
|
|
||||||
*/
|
|
||||||
template <typename ValueT>
|
|
||||||
struct value_rw_helper<
|
|
||||||
ValueT,
|
|
||||||
typename std::enable_if<
|
|
||||||
std::is_pointer<ValueT>::value
|
|
||||||
>::type
|
|
||||||
>
|
|
||||||
{
|
|
||||||
using type = typename std::remove_pointer<ValueT>::type;
|
|
||||||
|
|
||||||
static void write(const StaticProperty<ValueT> &prop, BitStream &stream)
|
/**
|
||||||
|
* Specialization for when ValueT is an explicitly-sized array
|
||||||
|
* of non-pointer values.
|
||||||
|
*/
|
||||||
|
template <typename ValueT, int N>
|
||||||
|
struct static_value_helper<ValueT[N]>
|
||||||
{
|
{
|
||||||
prop.get_type().write_to(
|
static Value get_value(const StaticProperty<ValueT[N]> &prop, const int index)
|
||||||
stream,
|
{
|
||||||
Value::make_reference<type>(*prop.m_value)
|
return Value::make_reference<ValueT>(prop.m_value[index]);
|
||||||
);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void read(StaticProperty<ValueT> &prop, BitStream &stream)
|
static void set_value(StaticProperty<ValueT[N]> &prop, Value value, const int index)
|
||||||
{
|
{
|
||||||
Value value = prop.get_type().read_from(stream);
|
prop.m_value[index] = value.as<ValueT>().get<ValueT>();
|
||||||
prop.m_value = value.take<type>();
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper utility that combines functions provided by value_object_helper
|
* Specialization for when ValueT is an explicitly-sized array
|
||||||
* and value_rw_helper into a single type.
|
* of pointer values.
|
||||||
*/
|
*/
|
||||||
template <typename ValueT>
|
template <typename ValueT, int N>
|
||||||
struct value_helper
|
struct static_value_helper<ValueT *[N]>
|
||||||
{
|
|
||||||
static ValueT construct(const Type &type)
|
|
||||||
{
|
{
|
||||||
return value_object_helper<ValueT>::construct(type);
|
static Value get_value(const StaticProperty<ValueT[N]> &prop, const int index)
|
||||||
}
|
{
|
||||||
|
return Value::make_reference<ValueT>(*prop.m_value[index]);
|
||||||
|
}
|
||||||
|
|
||||||
static ValueT copy(const StaticProperty<ValueT> &prop)
|
static void set_value(StaticProperty<ValueT[N]> &prop, Value value, const int index)
|
||||||
{
|
{
|
||||||
return value_object_helper<ValueT>::copy(prop);
|
prop.m_value[index] = value.as<ValueT>().release<ValueT>();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
static Value get_value(const StaticProperty<ValueT> &prop)
|
}
|
||||||
{
|
|
||||||
return value_object_helper<ValueT>::get_value(prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_value(StaticProperty<ValueT> &prop, Value value)
|
|
||||||
{
|
|
||||||
return value_object_helper<ValueT>::set_value(prop, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const PropertyClass *get_object(const StaticProperty<ValueT> &prop)
|
|
||||||
{
|
|
||||||
return value_object_helper<ValueT>::get_object(prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_object(StaticProperty<ValueT> &prop,
|
|
||||||
std::unique_ptr<PropertyClass> &object)
|
|
||||||
{
|
|
||||||
value_object_helper<ValueT>::set_object(prop, object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write(const StaticProperty<ValueT> &prop, BitStream &stream)
|
|
||||||
{
|
|
||||||
value_rw_helper<ValueT>::write(prop, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void read(StaticProperty<ValueT> &prop, BitStream &stream)
|
|
||||||
{
|
|
||||||
value_rw_helper<ValueT>::read(prop, stream);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/// @endcond
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Documentation
|
* TODO: Documentation
|
||||||
*/
|
*/
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
class StaticProperty : public IProperty
|
class IStaticProperty : public IProperty
|
||||||
{
|
{
|
||||||
// Allow helper utilities access to m_value
|
|
||||||
friend value_object_helper<ValueT>;
|
|
||||||
friend value_rw_helper<ValueT>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Do not allow copy assignment. Once a property has been constructed,
|
// Do not allow copy assignment. Once a property has been constructed,
|
||||||
// it shouldn't be able to change.
|
// it shouldn't be able to change.
|
||||||
StaticProperty<ValueT> &operator=(const StaticProperty<ValueT> &that) = delete;
|
virtual IStaticProperty<ValueT> &operator=(const IStaticProperty<ValueT> &that) = delete;
|
||||||
|
|
||||||
StaticProperty(PropertyClass &object,
|
IStaticProperty(PropertyClass &object,
|
||||||
const std::string &name, const Type &type)
|
const std::string &name, const Type &type)
|
||||||
: IProperty(object, name, type)
|
: IProperty(object, name, type)
|
||||||
, m_value(value_helper<ValueT>::construct(type))
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
StaticProperty(PropertyClass &object,
|
IStaticProperty(PropertyClass &object, const StaticProperty<ValueT> &that)
|
||||||
const std::string &name, const Type &type, ValueT value)
|
|
||||||
: IProperty(object, name, type)
|
|
||||||
{
|
|
||||||
m_value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
StaticProperty(PropertyClass &object, const StaticProperty<ValueT> &that)
|
|
||||||
: IProperty(object, that)
|
: IProperty(object, that)
|
||||||
, m_value(value_helper<ValueT>::copy(that))
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
constexpr bool is_pointer() const override
|
constexpr bool is_pointer() const override
|
||||||
|
@ -443,34 +432,92 @@ namespace pclass
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value get_value() const override
|
void set_element_count(std::size_t size) override
|
||||||
{
|
{
|
||||||
return value_helper<ValueT>::get_value(*this);
|
throw runtime_error("Tried to call set_element_count() on a property that is not dynamic.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_value(Value value) override
|
void write_value_to(BitStream &stream, const std::size_t index) const override
|
||||||
{
|
{
|
||||||
value_helper<ValueT>::set_value(*this, value);
|
if (index < 0 || index >= get_element_count())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
get_type().write_to(stream, get_value(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
const PropertyClass *get_object() const override
|
void read_value_from(BitStream &stream, const std::size_t index) override
|
||||||
{
|
{
|
||||||
return value_helper<ValueT>::get_object(*this);
|
if (index < 0 || index >= get_element_count())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
set_value(get_type().read_from(stream), index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A statically-sized property.
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
class StaticProperty : public IStaticProperty<ValueT>
|
||||||
|
{
|
||||||
|
// Allow helper utilities access to m_value
|
||||||
|
friend detail::default_static_object_helper<ValueT>;
|
||||||
|
friend detail::pointer_static_object_helper<ValueT>;
|
||||||
|
friend detail::static_object_helper<ValueT>;
|
||||||
|
friend detail::static_value_helper<ValueT>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Do not allow copy assignment. Once a property has been constructed,
|
||||||
|
// it shouldn't be able to change.
|
||||||
|
StaticProperty<ValueT> &operator=(const StaticProperty<ValueT> &that) = delete;
|
||||||
|
|
||||||
|
StaticProperty(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type)
|
||||||
|
: IStaticProperty(object, name, type)
|
||||||
|
, m_value(detail::static_object_helper<ValueT>::construct(type))
|
||||||
|
{}
|
||||||
|
|
||||||
|
StaticProperty(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type, ValueT value)
|
||||||
|
: IStaticProperty(object, name, type)
|
||||||
|
{
|
||||||
|
m_value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_object(std::unique_ptr<PropertyClass> &object) override
|
StaticProperty(PropertyClass &object, const StaticProperty<ValueT> &that)
|
||||||
|
: IStaticProperty(object, that)
|
||||||
|
, m_value(detail::static_object_helper<ValueT>::copy(that))
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::size_t get_element_count() const override
|
||||||
{
|
{
|
||||||
return value_helper<ValueT>::set_object(*this, object);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_value_to(BitStream &stream) const override
|
Value get_value(std::size_t index) const override
|
||||||
{
|
{
|
||||||
value_helper<ValueT>::write(*this, stream);
|
if (index < 0 || index >= get_element_count())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
return detail::static_value_helper<ValueT>::get_value(*this, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_value_from(BitStream &stream) override
|
void set_value(Value value, const std::size_t index) override
|
||||||
{
|
{
|
||||||
value_helper<ValueT>::read(*this, stream);
|
if (index < 0 || index >= get_element_count())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
detail::static_value_helper<ValueT>::set_value(*this, value, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const PropertyClass *get_object(const std::size_t index) const override
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= get_element_count())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
return detail::static_object_helper<ValueT>::get_object(*this, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_object(std::unique_ptr<PropertyClass> &object, const std::size_t index) override
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= get_element_count())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
return detail::static_object_helper<ValueT>::set_object(*this, object, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueT &get()
|
ValueT &get()
|
||||||
|
@ -511,5 +558,84 @@ namespace pclass
|
||||||
protected:
|
protected:
|
||||||
ValueT m_value;
|
ValueT m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialization of StaticProperty to support explicitly-sized arrays.
|
||||||
|
*/
|
||||||
|
template <typename ValueT, int N>
|
||||||
|
class StaticProperty<ValueT[N]> : public IStaticProperty<ValueT[N]>
|
||||||
|
{
|
||||||
|
// Allow helper utilities access to m_value
|
||||||
|
friend detail::static_object_helper<ValueT[N]>;
|
||||||
|
friend detail::static_value_helper<ValueT[N]>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Do not allow copy assignment. Once a property has been constructed,
|
||||||
|
// it shouldn't be able to change.
|
||||||
|
StaticProperty<ValueT[N]> &operator=(const StaticProperty<ValueT[N]> &that) = delete;
|
||||||
|
|
||||||
|
StaticProperty(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type)
|
||||||
|
: IStaticProperty(object, name, type)
|
||||||
|
{
|
||||||
|
for (auto i = 0; i < N; ++i)
|
||||||
|
m_value[i] = detail::static_object_helper<ValueT>::construct(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticProperty(PropertyClass &object, const StaticProperty<ValueT[N]> &that)
|
||||||
|
: IStaticProperty(object, that)
|
||||||
|
{
|
||||||
|
for (auto i = 0; i < N; ++i)
|
||||||
|
m_value[i] = that.m_value[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_array() const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t get_element_count() const override
|
||||||
|
{
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value get_value(std::size_t index) const override
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= get_element_count())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
return detail::static_value_helper<ValueT[N]>::get_value(*this, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_value(Value value, const std::size_t index) override
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= get_element_count())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
detail::static_value_helper<ValueT[N]>::set_value(*this, value, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const PropertyClass *get_object(const std::size_t index) const override
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= get_element_count())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
return detail::static_object_helper<ValueT[N]>::get_object(*this, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_object(std::unique_ptr<PropertyClass> &object, const std::size_t index) override
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= get_element_count())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
return detail::static_object_helper<ValueT[N]>::set_object(*this, object, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueT &operator[](const int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= get_element_count())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
return m_value[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ValueT m_value[N];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace pclass
|
||||||
{
|
{
|
||||||
template <
|
template <
|
||||||
typename SrcT, typename DestT,
|
typename SrcT, typename DestT,
|
||||||
typename SrcEnable = void, typename DestEnable = void
|
typename Enable = void
|
||||||
>
|
>
|
||||||
struct value_caster;
|
struct value_caster;
|
||||||
|
|
||||||
|
@ -53,10 +53,7 @@ namespace pclass
|
||||||
/**
|
/**
|
||||||
* TODO: Documentation
|
* TODO: Documentation
|
||||||
*/
|
*/
|
||||||
template <
|
template <typename SrcT, typename DestT, typename Enable>
|
||||||
typename SrcT, typename DestT,
|
|
||||||
typename SrcEnable, typename DestEnable
|
|
||||||
>
|
|
||||||
struct value_caster : value_caster_impl<SrcT, DestT>
|
struct value_caster : value_caster_impl<SrcT, DestT>
|
||||||
{
|
{
|
||||||
DestT cast_value(const SrcT &value) const override
|
DestT cast_value(const SrcT &value) const override
|
||||||
|
@ -238,16 +235,6 @@ namespace pclass
|
||||||
Value &operator=(Value &&that) noexcept;
|
Value &operator=(Value &&that) noexcept;
|
||||||
~Value();
|
~Value();
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns Whether or the not the value is holding a reference or a value.
|
|
||||||
*/
|
|
||||||
bool is_reference() const
|
|
||||||
{
|
|
||||||
// If the pointer isn't owned, then it isn't this Value's responsibility
|
|
||||||
// to clean it up, so we say it's referencing something.
|
|
||||||
return !m_ptr_is_owned;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns Whether or not the value being held is of type T.
|
* @returns Whether or not the value being held is of type T.
|
||||||
*/
|
*/
|
||||||
|
@ -257,34 +244,40 @@ namespace pclass
|
||||||
// Do the type hashes match?
|
// Do the type hashes match?
|
||||||
return m_type_hash == typeid(T).hash_code();
|
return m_type_hash == typeid(T).hash_code();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns Whether or the not the value is holding a reference or a value.
|
||||||
|
*/
|
||||||
|
bool is_reference() const
|
||||||
|
{
|
||||||
|
// If the pointer isn't owned, then it isn't this Value's responsibility
|
||||||
|
// to clean it up, so we say it's referencing something.
|
||||||
|
return !m_ptr_is_owned;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @tparam T
|
* @tparam T The expected type.
|
||||||
* @returns A new Value instance that owns it's value.
|
* @returns A new Value instance that owns it's value.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Value dereference() const
|
Value dereference() const
|
||||||
{
|
{
|
||||||
// Do we need to attempt casting?
|
|
||||||
if (!is<T>())
|
if (!is<T>())
|
||||||
return m_caster->cast_value<T>(*this);
|
throw runtime_error("Invalid call to Value::dereference<T>.");
|
||||||
return Value::make_value<T>(*static_cast<T *>(m_value_ptr));
|
return Value::make_value<T>(*static_cast<T *>(m_value_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @tparam T The expected type.
|
* @tparam T The type to cast to.
|
||||||
* @returns A reference to the value being held.
|
* @returns A new Value instance holding a T value.
|
||||||
* @throws ki::runtime_error The expected type and the type of the value being held are not the same.
|
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const T &get() const
|
Value as() const
|
||||||
{
|
{
|
||||||
// Make sure they requested the correct type
|
// Do we need to cast?
|
||||||
if (!is<T>())
|
if (!is<T>())
|
||||||
throw runtime_error("Invalid call to Value::get<T>.");
|
return m_caster->cast_value<T>(*this);
|
||||||
|
return Value::make_value<T>(*static_cast<T *>(m_value_ptr));
|
||||||
// Return a reference to the value being held
|
|
||||||
return *static_cast<T *>(m_value_ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -303,6 +296,22 @@ namespace pclass
|
||||||
return *static_cast<T *>(m_value_ptr);
|
return *static_cast<T *>(m_value_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @tparam T The expected type.
|
||||||
|
* @returns A reference to the value being held.
|
||||||
|
* @throws ki::runtime_error The expected type and the type of the value being held are not the same.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
const T &get() const
|
||||||
|
{
|
||||||
|
// Make sure they requested the correct type
|
||||||
|
if (!is<T>())
|
||||||
|
throw runtime_error("Invalid call to Value::get<T>.");
|
||||||
|
|
||||||
|
// Return a reference to the value being held
|
||||||
|
return *static_cast<T *>(m_value_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @tparam T The expected type.
|
* @tparam T The expected type.
|
||||||
* @returns A pointer to the value being held (that the caller takes ownership of).
|
* @returns A pointer to the value being held (that the caller takes ownership of).
|
||||||
|
@ -310,11 +319,11 @@ namespace pclass
|
||||||
* @throws ki::runtime_error If the expected type and the type of the value being held are not the same.
|
* @throws ki::runtime_error If the expected type and the type of the value being held are not the same.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T *take()
|
T *release()
|
||||||
{
|
{
|
||||||
// Make sure this Value is not a reference
|
// Make sure this Value is not a reference
|
||||||
if (is_reference())
|
if (is_reference())
|
||||||
throw runtime_error("Cannot take ownership from a reference Value.");
|
throw runtime_error("Cannot release ownership from a reference Value.");
|
||||||
|
|
||||||
// Make sure they requested the correct type
|
// Make sure they requested the correct type
|
||||||
if (!is<T>())
|
if (!is<T>())
|
||||||
|
@ -335,7 +344,7 @@ namespace pclass
|
||||||
{
|
{
|
||||||
auto *ptr = static_cast<void *>(new T(value));
|
auto *ptr = static_cast<void *>(new T(value));
|
||||||
auto val = Value(ptr, true);
|
auto val = Value(ptr, true);
|
||||||
val.construct<T>();
|
val.set_type<T>();
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,7 +358,7 @@ namespace pclass
|
||||||
{
|
{
|
||||||
auto *ptr = static_cast<void *>(&value);
|
auto *ptr = static_cast<void *>(&value);
|
||||||
auto val = Value(ptr);
|
auto val = Value(ptr);
|
||||||
val.construct<T>();
|
val.set_type<T>();
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,7 +372,7 @@ namespace pclass
|
||||||
{
|
{
|
||||||
auto *ptr = const_cast<void *>(static_cast<const void *>(&value));
|
auto *ptr = const_cast<void *>(static_cast<const void *>(&value));
|
||||||
auto val = Value(ptr);
|
auto val = Value(ptr);
|
||||||
val.construct<T>();
|
val.set_type<T>();
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,7 +390,7 @@ namespace pclass
|
||||||
* @tparam T The type that is being held.
|
* @tparam T The type that is being held.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void construct()
|
void set_type()
|
||||||
{
|
{
|
||||||
m_type_hash = typeid(T).hash_code();
|
m_type_hash = typeid(T).hash_code();
|
||||||
m_caster = &ValueCaster::get<T>();
|
m_caster = &ValueCaster::get<T>();
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace pclass
|
||||||
Value value, const int index)
|
Value value, const int index)
|
||||||
{
|
{
|
||||||
prop.at(index) = value
|
prop.at(index) = value
|
||||||
.dereference<ValueT>()
|
.as<ValueT>()
|
||||||
.get<ValueT>();
|
.get<ValueT>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,8 +112,8 @@ namespace pclass
|
||||||
Value value, const int index)
|
Value value, const int index)
|
||||||
{
|
{
|
||||||
prop.at(index) = value
|
prop.at(index) = value
|
||||||
.dereference<nonpointer_type>()
|
.as<nonpointer_type>()
|
||||||
.take<nonpointer_type>();
|
.release<nonpointer_type>();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const PropertyClass *get_object(const VectorProperty<ValueT> &prop, const int index)
|
static const PropertyClass *get_object(const VectorProperty<ValueT> &prop, const int index)
|
||||||
|
@ -174,8 +174,8 @@ namespace pclass
|
||||||
Value value, const int index)
|
Value value, const int index)
|
||||||
{
|
{
|
||||||
prop.at(index) = value
|
prop.at(index) = value
|
||||||
.dereference<nonpointer_type>()
|
.as<nonpointer_type>()
|
||||||
.take<nonpointer_type>();
|
.release<nonpointer_type>();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const PropertyClass *get_object(const VectorProperty<ValueT> &prop, const int index)
|
static const PropertyClass *get_object(const VectorProperty<ValueT> &prop, const int index)
|
||||||
|
@ -249,7 +249,7 @@ namespace pclass
|
||||||
Value value, const int index)
|
Value value, const int index)
|
||||||
{
|
{
|
||||||
prop.at(index) = value
|
prop.at(index) = value
|
||||||
.dereference<ValueT>()
|
.as<ValueT>()
|
||||||
.get<ValueT>();
|
.get<ValueT>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +347,7 @@ namespace pclass
|
||||||
|
|
||||||
Value value = prop.get_type().read_from(stream);
|
Value value = prop.get_type().read_from(stream);
|
||||||
ValueT &value_ref = prop.at(index);
|
ValueT &value_ref = prop.at(index);
|
||||||
value_ref = value.take<type>();
|
value_ref = value.release<type>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -404,7 +404,7 @@ namespace pclass
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
class VectorProperty : public std::vector<ValueT>, public IDynamicProperty
|
class VectorProperty : public std::vector<ValueT>, public IProperty
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Do not allow copy assignment. Once a property has been constructed,
|
// Do not allow copy assignment. Once a property has been constructed,
|
||||||
|
@ -413,12 +413,12 @@ namespace pclass
|
||||||
|
|
||||||
VectorProperty(PropertyClass &object,
|
VectorProperty(PropertyClass &object,
|
||||||
const std::string &name, const Type &type)
|
const std::string &name, const Type &type)
|
||||||
: IDynamicProperty(object, name, type)
|
: IProperty(object, name, type)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
VectorProperty(PropertyClass &object,
|
VectorProperty(PropertyClass &object,
|
||||||
const VectorProperty<ValueT> &that)
|
const VectorProperty<ValueT> &that)
|
||||||
: IDynamicProperty(object, that)
|
: IProperty(object, that)
|
||||||
{
|
{
|
||||||
// Copy vector values into this vector
|
// Copy vector values into this vector
|
||||||
for (auto i = 0; i < this->size(); i++)
|
for (auto i = 0; i < this->size(); i++)
|
||||||
|
@ -430,6 +430,16 @@ namespace pclass
|
||||||
return std::is_pointer<ValueT>::value;
|
return std::is_pointer<ValueT>::value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_dynamic() const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_array() const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t get_element_count() const override
|
std::size_t get_element_count() const override
|
||||||
{
|
{
|
||||||
return this->size();
|
return this->size();
|
||||||
|
@ -440,36 +450,36 @@ namespace pclass
|
||||||
this->resize(size);
|
this->resize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value get_value(int index) const override
|
Value get_value(std::size_t index) const override
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= this->size())
|
if (index < 0 || index >= this->size())
|
||||||
throw runtime_error("Index out of bounds.");
|
throw runtime_error("Index out of bounds.");
|
||||||
return vector_value_helper<ValueT>::get_value(*this, index);
|
return vector_value_helper<ValueT>::get_value(*this, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_value(Value value, int index) override
|
void set_value(Value value, std::size_t index) override
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= this->size())
|
if (index < 0 || index >= this->size())
|
||||||
throw runtime_error("Index out of bounds.");
|
throw runtime_error("Index out of bounds.");
|
||||||
return vector_value_helper<ValueT>::set_value(*this, value, index);
|
return vector_value_helper<ValueT>::set_value(*this, value, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PropertyClass *get_object(const int index) const override
|
const PropertyClass *get_object(const std::size_t index) const override
|
||||||
{
|
{
|
||||||
return vector_value_helper<ValueT>::get_object(*this, index);
|
return vector_value_helper<ValueT>::get_object(*this, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_object(std::unique_ptr<PropertyClass> &object, int index) override
|
void set_object(std::unique_ptr<PropertyClass> &object, std::size_t index) override
|
||||||
{
|
{
|
||||||
return vector_value_helper<ValueT>::set_object(*this, object, index);
|
return vector_value_helper<ValueT>::set_object(*this, object, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_value_to(BitStream &stream, const int index) const override
|
void write_value_to(BitStream &stream, const std::size_t index) const override
|
||||||
{
|
{
|
||||||
vector_value_helper<ValueT>::write_value_to(*this, stream, index);
|
vector_value_helper<ValueT>::write_value_to(*this, stream, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_value_from(BitStream &stream, const int index) override
|
void read_value_from(BitStream &stream, const std::size_t index) override
|
||||||
{
|
{
|
||||||
vector_value_helper<ValueT>::read_value_from(*this, stream, index);
|
vector_value_helper<ValueT>::read_value_from(*this, stream, index);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,50 +46,47 @@ namespace serialization
|
||||||
virtual ~BinarySerializer() {}
|
virtual ~BinarySerializer() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param object
|
* @param object The object to write to the stream.
|
||||||
* @param stream
|
* @param stream The stream to write the object to.
|
||||||
*/
|
*/
|
||||||
void save(const pclass::PropertyClass *object, BitStream &stream);
|
void save(const pclass::PropertyClass *object, BitStream &stream);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param dest
|
* @param dest Where to load the PropertyClass instance into.
|
||||||
* @param stream
|
* @param stream The stream to read the object from.
|
||||||
* @param size
|
* @param size The size of the stream's available data.
|
||||||
*/
|
*/
|
||||||
void load(std::unique_ptr<pclass::PropertyClass> &dest,
|
void load(std::unique_ptr<pclass::PropertyClass> &dest,
|
||||||
BitStream &stream, std::size_t size);
|
BitStream &stream, std::size_t size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @param object
|
* @param object The object that is being saved.
|
||||||
* @param stream
|
* @param stream The stream to write the object header to.
|
||||||
|
* @returns Whether or not the object is null.
|
||||||
*/
|
*/
|
||||||
virtual bool presave_object(const pclass::PropertyClass *object, BitStream &stream) const;
|
virtual bool presave_object(const pclass::PropertyClass *object, BitStream &stream) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read an object header, and instantiate the necessary PropertyClass.
|
* Read an object header, and instantiate the necessary PropertyClass.
|
||||||
* @param dest
|
* @param dest Where to instantiate the PropertyClass.
|
||||||
* @param stream
|
* @param stream The stream to read the object header from.
|
||||||
*/
|
*/
|
||||||
virtual void preload_object(
|
virtual void preload_object(
|
||||||
std::unique_ptr<pclass::PropertyClass> &dest, BitStream &stream) const;
|
std::unique_ptr<pclass::PropertyClass> &dest, BitStream &stream) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const pclass::PropertyClass *m_root_object;
|
||||||
const pclass::TypeSystem *m_type_system;
|
const pclass::TypeSystem *m_type_system;
|
||||||
bool m_is_file;
|
bool m_is_file;
|
||||||
flags m_flags;
|
flags m_flags;
|
||||||
|
|
||||||
const pclass::PropertyClass *m_root_object;
|
|
||||||
|
|
||||||
void save_object(const pclass::PropertyClass *object, BitStream &stream) const;
|
void save_object(const pclass::PropertyClass *object, BitStream &stream) const;
|
||||||
void save_property(const pclass::IProperty &prop, BitStream &stream) const;
|
void save_property(const pclass::IProperty &prop, BitStream &stream) const;
|
||||||
void save_dynamic_property(
|
|
||||||
const pclass::IDynamicProperty &prop, BitStream &stream) const;
|
|
||||||
|
|
||||||
void load_object(
|
void load_object(
|
||||||
std::unique_ptr<pclass::PropertyClass> &dest, BitStream &stream) const;
|
std::unique_ptr<pclass::PropertyClass> &dest, BitStream &stream) const;
|
||||||
void load_property(pclass::IProperty &prop, BitStream &stream) const;
|
void load_property(pclass::IProperty &prop, BitStream &stream) const;
|
||||||
void load_dynamic_property(pclass::IDynamicProperty &prop, BitStream &stream) const;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,10 @@ namespace serialization
|
||||||
virtual bool presave_object(nlohmann::json &j, const pclass::PropertyClass *object) const;
|
virtual bool presave_object(nlohmann::json &j, const pclass::PropertyClass *object) const;
|
||||||
nlohmann::json save_object(const pclass::PropertyClass *object) const;
|
nlohmann::json save_object(const pclass::PropertyClass *object) const;
|
||||||
void save_property(nlohmann::json &j, const pclass::IProperty &prop) const;
|
void save_property(nlohmann::json &j, const pclass::IProperty &prop) const;
|
||||||
void save_dynamic_property(nlohmann::json &j, const pclass::IDynamicProperty &prop) const;
|
|
||||||
|
|
||||||
virtual bool preload_object(std::unique_ptr<pclass::PropertyClass> &dest, nlohmann::json &j) const;
|
virtual bool preload_object(std::unique_ptr<pclass::PropertyClass> &dest, nlohmann::json &j) const;
|
||||||
void load_object(std::unique_ptr<pclass::PropertyClass> &dest, nlohmann::json &j) const;
|
void load_object(std::unique_ptr<pclass::PropertyClass> &dest, nlohmann::json &j) const;
|
||||||
void load_property(pclass::IProperty &prop, nlohmann::json &j) const;
|
void load_property(pclass::IProperty &prop, nlohmann::json &j) const;
|
||||||
void load_dynamic_property(pclass::IDynamicProperty &prop, nlohmann::json &j) const;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,55 +71,14 @@ namespace pclass
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
IDynamicProperty::IDynamicProperty(PropertyClass &object,
|
bool IProperty::is_array() const
|
||||||
const std::string& name, const Type& type)
|
|
||||||
: IProperty(object, name, type)
|
|
||||||
{}
|
|
||||||
|
|
||||||
IDynamicProperty::IDynamicProperty(PropertyClass &object,
|
|
||||||
const IDynamicProperty &that)
|
|
||||||
: IProperty(object, that)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool IDynamicProperty::is_dynamic() const
|
|
||||||
{
|
{
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IDynamicProperty::get_value() const
|
std::size_t IProperty::get_element_count() const
|
||||||
{
|
{
|
||||||
// The caller must specify an index
|
return 0;
|
||||||
throw runtime_error("Called get_value() on a dynamic property. Use get_value(index) instead.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDynamicProperty::set_value(Value value)
|
|
||||||
{
|
|
||||||
// The caller must specify an index
|
|
||||||
throw runtime_error("Called set_value() on a dynamic property. Use set_value(index) instead.");
|
|
||||||
}
|
|
||||||
|
|
||||||
const PropertyClass *IDynamicProperty::get_object() const
|
|
||||||
{
|
|
||||||
// The caller must specify an index
|
|
||||||
throw runtime_error("Called get_object() on a dynamic property. Use get_object(index) instead.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDynamicProperty::set_object(std::unique_ptr<PropertyClass> &object)
|
|
||||||
{
|
|
||||||
// The caller must specify an index
|
|
||||||
throw runtime_error("Called set_object() on a dynamic property. Use set_object(index) instead.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDynamicProperty::write_value_to(BitStream &stream) const
|
|
||||||
{
|
|
||||||
// The caller must specify an index
|
|
||||||
throw runtime_error("Called write_value_to() on a dynamic property. Use write_value_to(index) instead.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDynamicProperty::read_value_from(BitStream &stream)
|
|
||||||
{
|
|
||||||
// The caller must specify an index
|
|
||||||
throw runtime_error("Called read_value_from() on a dynamic property. Use read_value_from(index) instead.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,11 +37,6 @@ namespace pclass
|
||||||
return m_properties;
|
return m_properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyClass *PropertyClass::copy() const
|
|
||||||
{
|
|
||||||
return new PropertyClass(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PropertyClass::add_property(IProperty &prop)
|
void PropertyClass::add_property(IProperty &prop)
|
||||||
{
|
{
|
||||||
m_properties.add_property(prop);
|
m_properties.add_property(prop);
|
||||||
|
|
|
@ -176,27 +176,21 @@ namespace serialization
|
||||||
stream.write<uint32_t>(prop.get_full_hash());
|
stream.write<uint32_t>(prop.get_full_hash());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is the property dynamic? (holding more than one value)
|
// If the property is dynamic, write the element count
|
||||||
if (prop.is_dynamic())
|
if (prop.is_dynamic())
|
||||||
|
stream.write<uint32_t>(prop.get_element_count());
|
||||||
|
|
||||||
|
for (auto i = 0; i < prop.get_element_count(); ++i)
|
||||||
{
|
{
|
||||||
// Cast the property to a IDynamicProperty
|
if (prop.is_pointer()
|
||||||
const auto &dynamic_property =
|
&& prop.get_type().get_kind() == pclass::Type::kind::CLASS)
|
||||||
dynamic_cast<const pclass::IDynamicProperty &>(prop);
|
{
|
||||||
save_dynamic_property(dynamic_property, stream);
|
|
||||||
}
|
|
||||||
else if (prop.is_pointer())
|
|
||||||
{
|
|
||||||
// Does this property hold a pointer to another object?
|
|
||||||
if (prop.get_type().get_kind() == pclass::Type::kind::CLASS)
|
|
||||||
// Write the value as a nested object
|
// Write the value as a nested object
|
||||||
save_object(prop.get_object(), stream);
|
save_object(prop.get_object(i), stream);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
// Write the value as normal (let the property deal with dereferencing)
|
prop.write_value_to(stream, i);
|
||||||
prop.write_value_to(stream);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
// If the value isn't a pointer, and it's not dynamic, just write it as a value
|
|
||||||
prop.write_value_to(stream);
|
|
||||||
|
|
||||||
// Finish writing the property header by writing the length
|
// Finish writing the property header by writing the length
|
||||||
if (m_is_file)
|
if (m_is_file)
|
||||||
|
@ -212,32 +206,6 @@ namespace serialization
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BinarySerializer::save_dynamic_property(
|
|
||||||
const pclass::IDynamicProperty& prop, BitStream& stream) const
|
|
||||||
{
|
|
||||||
// Write the number of elements
|
|
||||||
stream.write<uint32_t>(prop.get_element_count());
|
|
||||||
|
|
||||||
// Iterate through the elements
|
|
||||||
for (auto i = 0; i < prop.get_element_count(); i++)
|
|
||||||
{
|
|
||||||
// Is this a collection of pointers?
|
|
||||||
if (prop.is_pointer())
|
|
||||||
{
|
|
||||||
// Is the property a collection of pointers to other objects?
|
|
||||||
if (prop.get_type().get_kind() == pclass::Type::kind::CLASS)
|
|
||||||
// Write the value as a nested object
|
|
||||||
save_object(prop.get_object(i), stream);
|
|
||||||
else
|
|
||||||
// Write the value as normal (let the property deal with dereferencing)
|
|
||||||
prop.write_value_to(stream, i);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// If the value isn't a pointer, and it's not dynamic, just write it as a value
|
|
||||||
prop.write_value_to(stream, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BinarySerializer::load(
|
void BinarySerializer::load(
|
||||||
std::unique_ptr<pclass::PropertyClass> &dest,
|
std::unique_ptr<pclass::PropertyClass> &dest,
|
||||||
BitStream &stream, const std::size_t size)
|
BitStream &stream, const std::size_t size)
|
||||||
|
@ -380,58 +348,24 @@ namespace serialization
|
||||||
|
|
||||||
void BinarySerializer::load_property(pclass::IProperty &prop, BitStream &stream) const
|
void BinarySerializer::load_property(pclass::IProperty &prop, BitStream &stream) const
|
||||||
{
|
{
|
||||||
|
// If the property is dynamic, we need to load the element count
|
||||||
if (prop.is_dynamic())
|
if (prop.is_dynamic())
|
||||||
{
|
{
|
||||||
auto &dynamic_property =
|
const auto element_count = stream.read<uint32_t>();
|
||||||
dynamic_cast<pclass::IDynamicProperty &>(prop);
|
prop.set_element_count(element_count);
|
||||||
load_dynamic_property(dynamic_property, stream);
|
|
||||||
}
|
}
|
||||||
else if (prop.is_pointer())
|
|
||||||
|
for (auto i = 0; i < prop.get_element_count(); ++i)
|
||||||
{
|
{
|
||||||
// Does this property hold a pointer to another object?
|
if (prop.is_pointer() &&
|
||||||
if (prop.get_type().get_kind() == pclass::Type::kind::CLASS)
|
prop.get_type().get_kind() == pclass::Type::kind::CLASS)
|
||||||
{
|
{
|
||||||
// Read the object as a nested object
|
// Read the object as a nested object
|
||||||
std::unique_ptr<pclass::PropertyClass> object = nullptr;
|
std::unique_ptr<pclass::PropertyClass> object = nullptr;
|
||||||
load_object(object, stream);
|
load_object(object, stream);
|
||||||
prop.set_object(object);
|
prop.set_object(object, i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// Read the value as normal (let the property deal with dereferencing)
|
|
||||||
prop.read_value_from(stream);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// If the value isn't a pointer, and it's not dynamic, just read it as a value
|
|
||||||
prop.read_value_from(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BinarySerializer::load_dynamic_property(
|
|
||||||
pclass::IDynamicProperty& prop, BitStream& stream) const
|
|
||||||
{
|
|
||||||
// How many elements are there in this dynamic property?
|
|
||||||
const auto element_count = stream.read<uint32_t>();
|
|
||||||
prop.set_element_count(element_count);
|
|
||||||
|
|
||||||
// Load each of the elements
|
|
||||||
for (uint16_t i = 0; i < element_count; i++)
|
|
||||||
{
|
|
||||||
// Is this a collection of pointers?
|
|
||||||
if (prop.is_pointer())
|
|
||||||
{
|
|
||||||
// Is the property a collection of pointers to other objects?
|
|
||||||
if (prop.get_type().get_kind() == pclass::Type::kind::CLASS)
|
|
||||||
{
|
|
||||||
// Read the object as a nested object
|
|
||||||
std::unique_ptr<pclass::PropertyClass> object = nullptr;
|
|
||||||
load_object(object, stream);
|
|
||||||
prop.set_object(object, i);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// Read the value as normal (let the property deal with dereferencing)
|
|
||||||
prop.read_value_from(stream, i);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// If the value isn't a pointer, and it's not dynamic, just read it as a value
|
|
||||||
prop.read_value_from(stream, i);
|
prop.read_value_from(stream, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,48 +50,28 @@ namespace serialization
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonSerializer::save_property(json& j,
|
void JsonSerializer::save_property(
|
||||||
const pclass::IProperty &prop) const
|
json& j, const pclass::IProperty &prop) const
|
||||||
{
|
{
|
||||||
if (prop.is_dynamic())
|
for (std::size_t i = 0; i < prop.get_element_count(); ++i)
|
||||||
{
|
|
||||||
const auto &dynamic_property =
|
|
||||||
dynamic_cast<const pclass::IDynamicProperty &>(prop);
|
|
||||||
return save_dynamic_property(j, dynamic_property);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prop.get_type().get_kind() == pclass::Type::kind::CLASS)
|
|
||||||
{
|
|
||||||
auto *other_object = prop.get_object();
|
|
||||||
j[prop.get_name()] = save_object(other_object);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto value = prop.get_value().dereference<json>();
|
|
||||||
j[prop.get_name()] = value.get<json>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JsonSerializer::save_dynamic_property(json& j,
|
|
||||||
const pclass::IDynamicProperty &prop) const
|
|
||||||
{
|
|
||||||
json property_value;
|
|
||||||
|
|
||||||
for (auto i = 0; i < prop.get_element_count(); ++i)
|
|
||||||
{
|
{
|
||||||
if (prop.get_type().get_kind() == pclass::Type::kind::CLASS)
|
if (prop.get_type().get_kind() == pclass::Type::kind::CLASS)
|
||||||
{
|
{
|
||||||
auto *other_object = prop.get_object(i);
|
auto *other_object = prop.get_object(i);
|
||||||
property_value.push_back(save_object(other_object));
|
if (prop.is_array())
|
||||||
|
j[prop.get_name()].push_back(save_object(other_object));
|
||||||
|
else
|
||||||
|
j[prop.get_name()] = save_object(other_object);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto value = prop.get_value(i).dereference<json>();
|
auto value = prop.get_value(i).as<json>();
|
||||||
property_value.push_back(value.get<json>());
|
if (prop.is_array())
|
||||||
|
j[prop.get_name()].push_back(value.get<json>());
|
||||||
|
else
|
||||||
|
j[prop.get_name()] = value.get<json>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
j[prop.get_name()] = property_value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonSerializer::load(std::unique_ptr<pclass::PropertyClass> &dest,
|
void JsonSerializer::load(std::unique_ptr<pclass::PropertyClass> &dest,
|
||||||
|
@ -159,42 +139,30 @@ namespace serialization
|
||||||
|
|
||||||
auto &property_j = j[prop.get_name()];
|
auto &property_j = j[prop.get_name()];
|
||||||
if (prop.is_dynamic())
|
if (prop.is_dynamic())
|
||||||
{
|
prop.set_element_count(property_j.size());
|
||||||
auto &dynamic_property =
|
|
||||||
dynamic_cast<pclass::IDynamicProperty &>(prop);
|
|
||||||
return load_dynamic_property(dynamic_property, j);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prop.get_type().get_kind() == pclass::Type::kind::CLASS)
|
for (std::size_t i = 0; i < prop.get_element_count(); ++i)
|
||||||
{
|
|
||||||
std::unique_ptr<pclass::PropertyClass> other_object = nullptr;
|
|
||||||
load_object(other_object, property_j);
|
|
||||||
prop.set_object(other_object);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
prop.set_value(
|
|
||||||
pclass::Value::make_reference<json>(property_j)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JsonSerializer::load_dynamic_property(
|
|
||||||
pclass::IDynamicProperty &prop, json &j) const
|
|
||||||
{
|
|
||||||
auto &property_j = j[prop.get_name()];
|
|
||||||
prop.set_element_count(property_j.size());
|
|
||||||
|
|
||||||
for (auto i = 0; i < prop.get_element_count(); ++i)
|
|
||||||
{
|
{
|
||||||
if (prop.get_type().get_kind() == pclass::Type::kind::CLASS)
|
if (prop.get_type().get_kind() == pclass::Type::kind::CLASS)
|
||||||
{
|
{
|
||||||
std::unique_ptr<pclass::PropertyClass> other_object = nullptr;
|
std::unique_ptr<pclass::PropertyClass> other_object = nullptr;
|
||||||
load_object(other_object, property_j.at(i));
|
if (prop.is_array())
|
||||||
|
load_object(other_object, property_j.at(i));
|
||||||
|
else
|
||||||
|
load_object(other_object, property_j);
|
||||||
prop.set_object(other_object, i);
|
prop.set_object(other_object, i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
prop.set_value(
|
{
|
||||||
pclass::Value::make_reference<json>(property_j.at(i)), i
|
if (prop.is_array())
|
||||||
);
|
prop.set_value(
|
||||||
|
pclass::Value::make_reference<json>(property_j.at(i)), i
|
||||||
|
);
|
||||||
|
else
|
||||||
|
prop.set_value(
|
||||||
|
pclass::Value::make_reference<json>(property_j), i
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue