etc: Combine IProperty with IDynamicProperty, and cleanup StaticProperty

This commit is contained in:
Joshua Scott 2018-12-20 15:39:31 +00:00
parent f3aa42578d
commit b5559834ac
11 changed files with 648 additions and 686 deletions

View File

@ -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;
};
} }
} }

View File

@ -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:

View File

@ -11,17 +11,13 @@ 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(), * Provides default implementations for static_object_helper.
* copy(), get_object() and set_object(), based on characteristics of type: ValueT.
*/ */
template < template <typename ValueT>
typename ValueT, struct default_static_object_helper
typename IsPointerEnable = void,
typename IsBaseEnable = void
>
struct value_object_helper
{ {
static ValueT construct(const Type &type) static ValueT construct(const Type &type)
{ {
@ -37,33 +33,18 @@ namespace pclass
return ValueT(prop.m_value); return ValueT(prop.m_value);
} }
static Value get_value(const StaticProperty<ValueT> &prop) static const PropertyClass *get_object(
const StaticProperty<ValueT> &prop, int index)
{ {
// Return a reference to the property's value // By default, assume that ValueT is not a
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 not derive from PropertyClass, and so, this property is not
// storing an object.
throw runtime_error( throw runtime_error(
"Tried calling get_object() on a property that does not store an object." "Tried calling get_object() on a property that does not store an object."
); );
} }
static void set_object(StaticProperty<ValueT> &prop, static void set_object(StaticProperty<ValueT> &prop,
std::unique_ptr<PropertyClass> &object) std::unique_ptr<PropertyClass> &object, int index)
{ {
// ValueT does not derive from PropertyClass, and so, this property is not
// storing an object.
throw runtime_error( throw runtime_error(
"Tried calling set_object() on a property that does not store an object." "Tried calling set_object() on a property that does not store an object."
); );
@ -71,70 +52,25 @@ namespace pclass
}; };
/** /**
* Specialization for when ValueT is: * Specialization for when ValueT is an explicitly-sized array.
* - A pointer; but * Removes construct() and copy() to stop the compiler complaining about
* - does not derive from PropertyClass * a function returning an array.
*
* This should:
* - Construct to a nullptr;
* - Copy construct to the same pointer as the original; and
* - Throw an exception when get_object() or set_object() is called.
*/ */
template <typename ValueT> template <typename ValueT, int N>
struct value_object_helper< struct default_static_object_helper<ValueT[N]>
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 const PropertyClass *get_object(
const StaticProperty<ValueT[N]> &prop, int index)
static ValueT construct(const Type &type)
{ {
// The default value of pointers is null // By default, assume that ValueT is not a
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 not derive from PropertyClass, and so, this property is not
// storing an object.
throw runtime_error( throw runtime_error(
"Tried calling get_object() on a property that does not store an object." "Tried calling get_object() on a property that does not store an object."
); );
} }
static void set_object(StaticProperty<ValueT> &prop, static void set_object(StaticProperty<ValueT[N]> &prop,
std::unique_ptr<PropertyClass> &object) std::unique_ptr<PropertyClass> &object, int index)
{ {
// ValueT does not derive from PropertyClass, and so, this property is not
// storing an object.
throw runtime_error( throw runtime_error(
"Tried calling set_object() on a property that does not store an object." "Tried calling set_object() on a property that does not store an object."
); );
@ -142,104 +78,75 @@ namespace pclass
}; };
/** /**
* Specialization for when ValueT is: * Provides default implementations of construct() and copy()
* - A pointer; and * for static_object_helper where ValueT is a pointer type.
* - 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> template <typename ValueT>
struct value_object_helper< struct 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)
static ValueT construct(const Type &type)
{ {
// The default value of pointers is null // The default value of pointers is null
return nullptr; return nullptr;
} }
static ValueT copy(const StaticProperty<ValueT> &prop) static ValueT *copy(const StaticProperty<ValueT *> &prop)
{ {
// The copy constructor for all pointers is to copy the pointer // The copy constructor for all pointers is to copy the pointer
// without creating a new copy of the object it's pointing to. // without creating a new copy of the object it's pointing to.
return prop.m_value; return prop.m_value;
} }
static Value get_value(const StaticProperty<ValueT> &prop) static const PropertyClass *get_object(
const StaticProperty<ValueT *> &prop, int index)
{ {
return Value::make_reference<nonpointer_type>(*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 void set_value(StaticProperty<ValueT> &prop, Value value) static void set_object(StaticProperty<ValueT *> &prop,
std::unique_ptr<PropertyClass> &object, int index)
{ {
prop.m_value = value throw runtime_error(
.dereference<nonpointer_type>() "Tried calling set_object() on a property that does not store an object."
.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());
} }
}; };
/**
* 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>
{
using default_static_object_helper<ValueT>::construct;
using default_static_object_helper<ValueT>::copy;
using default_static_object_helper<ValueT>::get_object;
using default_static_object_helper<ValueT>::set_object;
};
/** /**
* Specialization for when ValueT is: * Specialization for when ValueT is:
* - Not a pointer; and * - Not a pointer; but
* - does derive from PropertyClass * - 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> template <typename ValueT>
struct value_object_helper< struct static_object_helper<
ValueT, ValueT,
typename std::enable_if< typename std::enable_if<
!std::is_pointer<ValueT>::value std::is_base_of<PropertyClass, ValueT>::value
>::type,
typename std::enable_if<
std::is_base_of<
PropertyClass,
typename std::remove_pointer<ValueT>::type
>::value
>::type >::type
> >
: default_static_object_helper<ValueT>
{ {
using default_static_object_helper<ValueT>::copy;
static ValueT construct(const Type &type) static ValueT construct(const Type &type)
{ {
// Derivitives of PropertyClass cannot have a default constructor since // Derivitives of PropertyClass cannot have a default constructor since
@ -248,29 +155,8 @@ namespace pclass
return ValueT(type, type.get_type_system()); return ValueT(type, type.get_type_system());
} }
static ValueT copy(const StaticProperty<ValueT> &prop) static const PropertyClass *get_object(
{ const StaticProperty<ValueT> &prop, int index)
// 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, // ValueT does derive from PropertyClass, and we have an instance of ValueT,
// so we can cast down to a PropertyClass pointer. // so we can cast down to a PropertyClass pointer.
@ -278,7 +164,7 @@ namespace pclass
} }
static void set_object(StaticProperty<ValueT> &prop, static void set_object(StaticProperty<ValueT> &prop,
std::unique_ptr<PropertyClass> &object) std::unique_ptr<PropertyClass> &object, int index)
{ {
// Ensure that object is not nullptr // Ensure that object is not nullptr
if (!object) if (!object)
@ -294,27 +180,167 @@ namespace pclass
}; };
/** /**
* A helper utility that provides the right implementation of write() and read() * Specialization for when ValueT is:
* based on whether ValueT is a pointer. * - A pointer; but
* - does not derive from PropertyClass
*/ */
template < template <typename ValueT>
typename ValueT, struct static_object_helper<
typename IsPointerEnable = void ValueT *,
typename std::enable_if<
!std::is_base_of<PropertyClass, ValueT>::value
>::type
> >
struct value_rw_helper : pointer_static_object_helper<ValueT>
{ {
static void write(const StaticProperty<ValueT> &prop, BitStream &stream) using pointer_static_object_helper<ValueT>::construct;
using pointer_static_object_helper<ValueT>::copy;
using pointer_static_object_helper<ValueT>::get_object;
using pointer_static_object_helper<ValueT>::set_object;
};
/**
* Specialization for when ValueT is:
* - A pointer; and
* - does 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>
{ {
prop.get_type().write_to( using pointer_static_object_helper<ValueT>::construct;
stream, using pointer_static_object_helper<ValueT>::copy;
Value::make_reference<ValueT>(prop.m_value)
); 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 read(StaticProperty<ValueT> &prop, BitStream &stream) static void set_object(StaticProperty<ValueT *> &prop,
std::unique_ptr<PropertyClass> &object, int index)
{ {
Value value = prop.get_type().read_from(stream); // Ensure that object inherits the type of the property
prop.m_value = value.get<ValueT>(); 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]>
{
using default_static_object_helper<ValueT[N]>::get_object;
using default_static_object_helper<ValueT[N]>::set_object;
};
/**
* 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
>
{
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_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
>
{
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_object(StaticProperty<ValueT> &prop,
std::unique_ptr<PropertyClass> &object, const 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[index] = dynamic_cast<ValueT *>(object.release());
}
};
/**
* A helper utility that provides the right implementation of
* get_value() and set_value() based on whether ValueT is a pointer.
*/
template <typename ValueT>
struct static_value_helper
{
static Value get_value(const StaticProperty<ValueT> &prop, int index)
{
return Value::make_reference<ValueT>(prop.m_value);
}
static void set_value(StaticProperty<ValueT> &prop, Value value, int index)
{
prop.m_value = value.as<ValueT>().get<ValueT>();
} }
}; };
@ -326,111 +352,74 @@ namespace pclass
* rather than storing a pointer to a pointer. * rather than storing a pointer to a pointer.
*/ */
template <typename ValueT> template <typename ValueT>
struct value_rw_helper< struct static_value_helper<ValueT *>
ValueT,
typename std::enable_if<
std::is_pointer<ValueT>::value
>::type
>
{ {
using type = typename std::remove_pointer<ValueT>::type; static Value get_value(const StaticProperty<ValueT *> &prop, int index)
static void write(const StaticProperty<ValueT> &prop, BitStream &stream)
{ {
prop.get_type().write_to( return Value::make_reference<ValueT>(*prop.m_value);
stream,
Value::make_reference<type>(*prop.m_value)
);
} }
static void read(StaticProperty<ValueT> &prop, BitStream &stream) static void set_value(StaticProperty<ValueT *> &prop, Value value, int index)
{ {
Value value = prop.get_type().read_from(stream); prop.m_value = value.as<ValueT>().release<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 non-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) static Value get_value(const StaticProperty<ValueT[N]> &prop, const int index)
{ {
return value_object_helper<ValueT>::construct(type); 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>().get<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
/**
* Specialization for when ValueT is an explicitly-sized array
* of pointer values.
*/
template <typename ValueT, int N>
struct static_value_helper<ValueT *[N]>
{
static Value get_value(const StaticProperty<ValueT[N]> &prop, const int index)
{
return Value::make_reference<ValueT>(*prop.m_value[index]);
}
static void set_value(StaticProperty<ValueT[N]> &prop, Value value, const int index)
{
prop.m_value[index] = value.as<ValueT>().release<ValueT>();
}
};
}
/** /**
* 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];
};
} }
} }

View File

@ -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.
*/ */
@ -259,32 +246,38 @@ namespace pclass
} }
/** /**
* @tparam T * @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 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>();

View File

@ -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);
} }

View File

@ -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;
}; };
} }
} }

View File

@ -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;
}; };
} }
} }

View File

@ -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.");
} }
} }
} }

View File

@ -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);

View File

@ -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
// Write the value as normal (let the property deal with dereferencing)
prop.write_value_to(stream);
} }
else 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);
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,46 +348,17 @@ 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 =
dynamic_cast<pclass::IDynamicProperty &>(prop);
load_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)
{
// Read the object as a nested object
std::unique_ptr<pclass::PropertyClass> object = nullptr;
load_object(object, stream);
prop.set_object(object);
}
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>(); const auto element_count = stream.read<uint32_t>();
prop.set_element_count(element_count); prop.set_element_count(element_count);
}
// Load each of the elements for (auto i = 0; i < prop.get_element_count(); ++i)
for (uint16_t i = 0; i < element_count; i++)
{ {
// Is this a collection of pointers? if (prop.is_pointer() &&
if (prop.is_pointer()) prop.get_type().get_kind() == pclass::Type::kind::CLASS)
{
// 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 // Read the object as a nested object
std::unique_ptr<pclass::PropertyClass> object = nullptr; std::unique_ptr<pclass::PropertyClass> object = nullptr;
@ -427,11 +366,6 @@ namespace serialization
prop.set_object(object, i); prop.set_object(object, i);
} }
else 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);
} }
} }

View File

@ -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())
{
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)
{
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()); prop.set_element_count(property_j.size());
for (auto i = 0; i < prop.get_element_count(); ++i) for (std::size_t 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;
if (prop.is_array())
load_object(other_object, property_j.at(i)); 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
{
if (prop.is_array())
prop.set_value( prop.set_value(
pclass::Value::make_reference<json>(property_j.at(i)), i pclass::Value::make_reference<json>(property_j.at(i)), i
); );
else
prop.set_value(
pclass::Value::make_reference<json>(property_j), i
);
}
} }
} }
} }