mirror of https://github.com/SeanOMik/libki.git
pclass: Cleanup VectorProperty and fix build errors
This commit is contained in:
parent
2dad313885
commit
bab80d20c7
|
@ -1,5 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <string>
|
||||||
#include "ki/pclass/types/Type.h"
|
#include "ki/pclass/types/Type.h"
|
||||||
|
#include "ki/pclass/HashCalculator.h"
|
||||||
|
#include "ki/pclass/Value.h"
|
||||||
|
#include "ki/util/BitStream.h"
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
|
@ -42,8 +46,8 @@ namespace pclass
|
||||||
virtual const PropertyClass *get_object(std::size_t index = 0) const = 0;
|
virtual const PropertyClass *get_object(std::size_t index = 0) const = 0;
|
||||||
virtual void set_object(std::unique_ptr<PropertyClass> &object, std::size_t index = 0) = 0;
|
virtual void set_object(std::unique_ptr<PropertyClass> &object, std::size_t index = 0) = 0;
|
||||||
|
|
||||||
virtual void write_value_to(BitStream &stream, std::size_t index = 0) const = 0;
|
virtual void write_value_to(BitStream &stream, std::size_t index = 0) const;
|
||||||
virtual void read_value_from(BitStream &stream, std::size_t index = 0) = 0;
|
virtual void read_value_from(BitStream &stream, std::size_t index = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const PropertyClass *m_instance;
|
const PropertyClass *m_instance;
|
||||||
|
|
|
@ -78,8 +78,10 @@ namespace pclass
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides default implementations of construct() and copy()
|
* Provides default implementations of construct(), copy()
|
||||||
* for static_object_helper where ValueT is a pointer type.
|
* get_object(), and set_object() for static_object_helper where
|
||||||
|
* ValueT is a pointer type.
|
||||||
|
* @tparam ValueT The type of the value (as a non-pointer type).
|
||||||
*/
|
*/
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
struct pointer_static_object_helper
|
struct pointer_static_object_helper
|
||||||
|
@ -340,7 +342,8 @@ namespace pclass
|
||||||
|
|
||||||
static void set_value(StaticProperty<ValueT> &prop, Value value, int index)
|
static void set_value(StaticProperty<ValueT> &prop, Value value, int index)
|
||||||
{
|
{
|
||||||
prop.m_value = value.as<ValueT>().get<ValueT>();
|
Value casted_value = value.as<ValueT>();
|
||||||
|
prop.m_value = casted_value.get<ValueT>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -356,12 +359,15 @@ namespace pclass
|
||||||
{
|
{
|
||||||
static Value get_value(const StaticProperty<ValueT *> &prop, int index)
|
static Value get_value(const StaticProperty<ValueT *> &prop, int index)
|
||||||
{
|
{
|
||||||
|
if (prop.m_value == nullptr)
|
||||||
|
throw runtime_error("Called get_value() but value is nullptr.");
|
||||||
return Value::make_reference<ValueT>(*prop.m_value);
|
return Value::make_reference<ValueT>(*prop.m_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_value(StaticProperty<ValueT *> &prop, Value value, int index)
|
static void set_value(StaticProperty<ValueT *> &prop, Value value, int index)
|
||||||
{
|
{
|
||||||
prop.m_value = value.as<ValueT>().release<ValueT>();
|
Value casted_value = value.as<ValueT>();
|
||||||
|
prop.m_value = casted_value.release<ValueT>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -379,7 +385,8 @@ namespace pclass
|
||||||
|
|
||||||
static void set_value(StaticProperty<ValueT[N]> &prop, Value value, const int index)
|
static void set_value(StaticProperty<ValueT[N]> &prop, Value value, const int index)
|
||||||
{
|
{
|
||||||
prop.m_value[index] = value.as<ValueT>().get<ValueT>();
|
Value casted_value = value.as<ValueT>();
|
||||||
|
prop.m_value[index] = casted_value.get<ValueT>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -397,31 +404,26 @@ namespace pclass
|
||||||
|
|
||||||
static void set_value(StaticProperty<ValueT[N]> &prop, Value value, const int index)
|
static void set_value(StaticProperty<ValueT[N]> &prop, Value value, const int index)
|
||||||
{
|
{
|
||||||
prop.m_value[index] = value.as<ValueT>().release<ValueT>();
|
Value casted_value = value.as<ValueT>();
|
||||||
|
prop.m_value[index] = casted_value.release<ValueT>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Documentation
|
* Base type for StaticProperty.
|
||||||
|
* This is used to remove the amount of repeated code in specializations.
|
||||||
*/
|
*/
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
class IStaticProperty : public IProperty
|
class IStaticProperty : public IProperty
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using IProperty::IProperty;
|
||||||
|
|
||||||
// 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.
|
||||||
virtual IStaticProperty<ValueT> &operator=(const IStaticProperty<ValueT> &that) = delete;
|
virtual IStaticProperty<ValueT> &operator=(const IStaticProperty<ValueT> &that) = delete;
|
||||||
|
|
||||||
IStaticProperty(PropertyClass &object,
|
|
||||||
const std::string &name, const Type &type)
|
|
||||||
: IProperty(object, name, type)
|
|
||||||
{}
|
|
||||||
|
|
||||||
IStaticProperty(PropertyClass &object, const StaticProperty<ValueT> &that)
|
|
||||||
: IProperty(object, that)
|
|
||||||
{}
|
|
||||||
|
|
||||||
constexpr bool is_pointer() const override
|
constexpr bool is_pointer() const override
|
||||||
{
|
{
|
||||||
return std::is_pointer<ValueT>::value;
|
return std::is_pointer<ValueT>::value;
|
||||||
|
@ -436,20 +438,6 @@ namespace pclass
|
||||||
{
|
{
|
||||||
throw runtime_error("Tried to call set_element_count() on a property that is not dynamic.");
|
throw runtime_error("Tried to call set_element_count() on a property that is not dynamic.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_value_to(BitStream &stream, const std::size_t index) const override
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= get_element_count())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
get_type().write_to(stream, get_value(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
void read_value_from(BitStream &stream, const std::size_t index) override
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= get_element_count())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
set_value(get_type().read_from(stream), index);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -471,19 +459,19 @@ namespace pclass
|
||||||
|
|
||||||
StaticProperty(PropertyClass &object,
|
StaticProperty(PropertyClass &object,
|
||||||
const std::string &name, const Type &type)
|
const std::string &name, const Type &type)
|
||||||
: IStaticProperty(object, name, type)
|
: IStaticProperty<ValueT>(object, name, type)
|
||||||
, m_value(detail::static_object_helper<ValueT>::construct(type))
|
, m_value(detail::static_object_helper<ValueT>::construct(type))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
StaticProperty(PropertyClass &object,
|
StaticProperty(PropertyClass &object,
|
||||||
const std::string &name, const Type &type, ValueT value)
|
const std::string &name, const Type &type, ValueT value)
|
||||||
: IStaticProperty(object, name, type)
|
: IStaticProperty<ValueT>(object, name, type)
|
||||||
{
|
{
|
||||||
m_value = value;
|
m_value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
StaticProperty(PropertyClass &object, const StaticProperty<ValueT> &that)
|
StaticProperty(PropertyClass &object, const StaticProperty<ValueT> &that)
|
||||||
: IStaticProperty(object, that)
|
: IStaticProperty<ValueT>(object, that)
|
||||||
, m_value(detail::static_object_helper<ValueT>::copy(that))
|
, m_value(detail::static_object_helper<ValueT>::copy(that))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -576,14 +564,14 @@ namespace pclass
|
||||||
|
|
||||||
StaticProperty(PropertyClass &object,
|
StaticProperty(PropertyClass &object,
|
||||||
const std::string &name, const Type &type)
|
const std::string &name, const Type &type)
|
||||||
: IStaticProperty(object, name, type)
|
: IStaticProperty<ValueT[N]>(object, name, type)
|
||||||
{
|
{
|
||||||
for (auto i = 0; i < N; ++i)
|
for (auto i = 0; i < N; ++i)
|
||||||
m_value[i] = detail::static_object_helper<ValueT>::construct(type);
|
m_value[i] = detail::static_object_helper<ValueT>::construct(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
StaticProperty(PropertyClass &object, const StaticProperty<ValueT[N]> &that)
|
StaticProperty(PropertyClass &object, const StaticProperty<ValueT[N]> &that)
|
||||||
: IStaticProperty(object, that)
|
: IStaticProperty<ValueT[N]>(object, that)
|
||||||
{
|
{
|
||||||
for (auto i = 0; i < N; ++i)
|
for (auto i = 0; i < N; ++i)
|
||||||
m_value[i] = that.m_value[i];
|
m_value[i] = that.m_value[i];
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
#include "ki/pclass/Property.h"
|
#include "ki/pclass/Property.h"
|
||||||
#include "ki/util/exception.h"
|
#include "ki/util/exception.h"
|
||||||
|
|
||||||
|
@ -11,271 +12,121 @@ namespace pclass
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
class VectorProperty;
|
class VectorProperty;
|
||||||
|
|
||||||
/// @cond DOXYGEN_SKIP
|
namespace detail
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Provides default implementations for vector_object_helper.
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
struct default_vector_object_helper
|
||||||
|
{
|
||||||
|
static ValueT copy(VectorProperty<ValueT> &prop, const int index)
|
||||||
|
{
|
||||||
|
// In cases where ValueT is not a pointer, and does not derive from PropertyClass,
|
||||||
|
// just call the copy constructor.
|
||||||
|
return ValueT(prop.at(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PropertyClass *get_object(const VectorProperty<ValueT> &prop, const int index)
|
||||||
|
{
|
||||||
|
// ValueT does not derive from PropertyClass, and so, this property is not
|
||||||
|
// storing an object.
|
||||||
|
throw runtime_error(
|
||||||
|
"Tried calling get_object() on a property that does not store an object."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_object(VectorProperty<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.
|
||||||
|
throw runtime_error(
|
||||||
|
"Tried calling set_object() on a property that does not store an object."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides default implementations of copy()
|
||||||
|
* for static_object_helper where ValueT is a pointer type.
|
||||||
|
* @tparam ValueT The type of the value (as a non-pointer type).
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
struct pointer_vector_object_helper
|
||||||
|
{
|
||||||
|
static ValueT *copy(const VectorProperty<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 VectorProperty<ValueT *> &prop, const 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(VectorProperty<ValueT *> &prop,
|
||||||
|
std::unique_ptr<PropertyClass> &object, const 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 copy(),
|
* A helper utility that provides the right implementation of copy(),
|
||||||
* get_object() and set_object(), based on characteristics of type: ValueT.
|
* get_object() and set_object(), based on characteristics of type: ValueT.
|
||||||
*/
|
*/
|
||||||
template <
|
template <
|
||||||
typename ValueT,
|
typename ValueT,
|
||||||
typename IsPointerEnable = void,
|
typename Enable = void
|
||||||
typename IsBaseEnable = void
|
|
||||||
>
|
>
|
||||||
struct vector_value_object_helper
|
struct vector_object_helper : default_vector_object_helper<ValueT>
|
||||||
{
|
{
|
||||||
static ValueT copy(VectorProperty<ValueT> &prop, const int index)
|
using default_vector_object_helper<ValueT>::copy;
|
||||||
{
|
using default_vector_object_helper<ValueT>::get_object;
|
||||||
// Ensure index is within bounds
|
using default_vector_object_helper<ValueT>::set_object;
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
|
|
||||||
// In cases where ValueT is not a pointer, and does not derive from PropertyClass,
|
|
||||||
// just call the copy constructor.
|
|
||||||
return ValueT(prop.at(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Value get_value(const VectorProperty<ValueT> &prop, const int index)
|
|
||||||
{
|
|
||||||
// Ensure index is within bounds
|
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
return Value::make_reference<ValueT>(prop.at(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_value(VectorProperty<ValueT> &prop,
|
|
||||||
Value value, const int index)
|
|
||||||
{
|
|
||||||
prop.at(index) = value
|
|
||||||
.as<ValueT>()
|
|
||||||
.get<ValueT>();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const PropertyClass *get_object(const VectorProperty<ValueT> &prop, const int index)
|
|
||||||
{
|
|
||||||
// ValueT does not derive from PropertyClass, and so, this property is not
|
|
||||||
// storing an object.
|
|
||||||
throw runtime_error(
|
|
||||||
"Tried calling get_object() on a property that does not store an object."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_object(VectorProperty<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.
|
|
||||||
throw runtime_error(
|
|
||||||
"Tried calling set_object() on a property that does not store an object."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Specialization for when ValueT is:
|
||||||
|
* - Not a pointer; but
|
||||||
|
* - does derive from PropertyClass
|
||||||
*/
|
*/
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
struct vector_value_object_helper<
|
struct vector_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_vector_object_helper<ValueT>
|
||||||
{
|
{
|
||||||
using nonpointer_type = typename std::remove_pointer<ValueT>::type;
|
using default_vector_object_helper<ValueT>::copy;
|
||||||
|
|
||||||
static ValueT copy(VectorProperty<ValueT> &prop, const int index)
|
static const PropertyClass *get_object(
|
||||||
|
const VectorProperty<ValueT *> &prop, const int index)
|
||||||
{
|
{
|
||||||
// Ensure index is within bounds
|
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
|
|
||||||
// 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.at(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Value get_value(const VectorProperty<ValueT> &prop, const int index)
|
|
||||||
{
|
|
||||||
// Ensure index is within bounds
|
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
return Value::make_reference<nonpointer_type>(*prop.at(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_value(VectorProperty<ValueT> &prop,
|
|
||||||
Value value, const int index)
|
|
||||||
{
|
|
||||||
prop.at(index) = value
|
|
||||||
.as<nonpointer_type>()
|
|
||||||
.release<nonpointer_type>();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const PropertyClass *get_object(const VectorProperty<ValueT> &prop, const int index)
|
|
||||||
{
|
|
||||||
// ValueT does not derive from PropertyClass, and so, this property is not
|
|
||||||
// storing an object.
|
|
||||||
throw runtime_error(
|
|
||||||
"Tried calling get_object() on a property that does not store an object."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_object(VectorProperty<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.
|
|
||||||
throw runtime_error(
|
|
||||||
"Tried calling set_object() on a property that does not store an object."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
template <typename ValueT>
|
|
||||||
struct vector_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 copy(VectorProperty<ValueT> &prop, const int index)
|
|
||||||
{
|
|
||||||
// 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.at(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Value get_value(const VectorProperty<ValueT> &prop, const int index)
|
|
||||||
{
|
|
||||||
// Ensure index is within bounds
|
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
return Value::make_reference<nonpointer_type>(*prop.at(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_value(VectorProperty<ValueT> &prop,
|
|
||||||
Value value, const int index)
|
|
||||||
{
|
|
||||||
prop.at(index) = value
|
|
||||||
.as<nonpointer_type>()
|
|
||||||
.release<nonpointer_type>();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const PropertyClass *get_object(const VectorProperty<ValueT> &prop, const int index)
|
|
||||||
{
|
|
||||||
// Ensure index is within bounds
|
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
|
|
||||||
// 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<PropertyClass *>(prop.at(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_object(VectorProperty<ValueT> &prop,
|
|
||||||
std::unique_ptr<PropertyClass> &object, const int index)
|
|
||||||
{
|
|
||||||
// Ensure index is within bounds
|
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
|
|
||||||
// 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.at(index) = dynamic_cast<ValueT>(object.release());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
template <typename ValueT>
|
|
||||||
struct vector_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 copy(VectorProperty<ValueT> &prop, const int index)
|
|
||||||
{
|
|
||||||
// Ensure index is within bounds
|
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
|
|
||||||
// Derivitives of PropertyClass implement a clone method that returns
|
|
||||||
// a pointer to a copy.
|
|
||||||
ValueT *value_ptr = dynamic_cast<ValueT *>(prop.at(index).copy());
|
|
||||||
ValueT value = *value_ptr;
|
|
||||||
delete value_ptr;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Value get_value(const VectorProperty<ValueT> &prop, const int index)
|
|
||||||
{
|
|
||||||
// Ensure index is within bounds
|
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
return Value::make_reference<ValueT>(prop.at(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_value(VectorProperty<ValueT> &prop,
|
|
||||||
Value value, const int index)
|
|
||||||
{
|
|
||||||
prop.at(index) = value
|
|
||||||
.as<ValueT>()
|
|
||||||
.get<ValueT>();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const PropertyClass *get_object(const VectorProperty<ValueT> &prop, const int index)
|
|
||||||
{
|
|
||||||
// Ensure index is within bounds
|
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
|
|
||||||
// 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.
|
||||||
return dynamic_cast<const PropertyClass *>(&prop.at(index));
|
return dynamic_cast<const PropertyClass *>(&prop.at(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_object(VectorProperty<ValueT> &prop,
|
static void set_object(VectorProperty<ValueT *> &prop,
|
||||||
std::unique_ptr<PropertyClass> &object, const int index)
|
std::unique_ptr<PropertyClass> &object, const int index)
|
||||||
{
|
{
|
||||||
// Ensure index is within bounds
|
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
|
|
||||||
// Ensure that object is not nullptr
|
// Ensure that object is not nullptr
|
||||||
if (!object)
|
if (!object)
|
||||||
throw runtime_error("Value cannot be null.");
|
throw runtime_error("Value cannot be null.");
|
||||||
|
|
||||||
// Ensure that object is exactly the type of the property
|
// Ensure that object is exactly the type of the property.
|
||||||
assert_type_match(prop.get_type(), object->get_type());
|
assert_type_match(prop.get_type(), object->get_type());
|
||||||
|
|
||||||
// ValueT does derive from PropertyClass, but we don't store a pointer,
|
// ValueT does derive from PropertyClass, but we don't store a pointer,
|
||||||
|
@ -285,123 +136,111 @@ namespace pclass
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Specialization for when ValueT is:
|
||||||
*/
|
* - A pointer; but
|
||||||
template <
|
* - does not derive from PropertyClass
|
||||||
typename ValueT,
|
|
||||||
typename IsPointerEnable = void
|
|
||||||
>
|
|
||||||
struct vector_value_rw_helper
|
|
||||||
{
|
|
||||||
static void write_value_to(const VectorProperty<ValueT> &prop, BitStream &stream, const int index)
|
|
||||||
{
|
|
||||||
// Ensure index is within bounds
|
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
|
|
||||||
prop.get_type().write_to(
|
|
||||||
stream,
|
|
||||||
Value::make_reference<ValueT>(prop.at(index))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void read_value_from(VectorProperty<ValueT> &prop, BitStream &stream, const int index)
|
|
||||||
{
|
|
||||||
// Ensure index is within bounds
|
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
|
|
||||||
Value value = prop.get_type().read_from(stream);
|
|
||||||
prop.at(index) = value.get<ValueT>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
struct vector_value_rw_helper<
|
struct vector_object_helper<
|
||||||
ValueT,
|
ValueT *,
|
||||||
typename std::enable_if<std::is_pointer<ValueT>::value>::type
|
typename std::enable_if<
|
||||||
|
!std::is_base_of<PropertyClass, ValueT>::value
|
||||||
|
>::type
|
||||||
>
|
>
|
||||||
|
: pointer_vector_object_helper<ValueT>
|
||||||
{
|
{
|
||||||
using type = typename std::remove_pointer<ValueT>::type;
|
using pointer_vector_object_helper<ValueT>::copy;
|
||||||
|
using pointer_vector_object_helper<ValueT>::get_object;
|
||||||
|
using pointer_vector_object_helper<ValueT>::set_object;
|
||||||
|
};
|
||||||
|
|
||||||
static void write_value_to(const VectorProperty<ValueT> &prop, BitStream &stream, const int index)
|
/**
|
||||||
|
* Specialization for when ValueT is:
|
||||||
|
* - A pointer; and
|
||||||
|
* - does derive from PropertyClass
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
struct vector_object_helper<
|
||||||
|
ValueT *,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_base_of<PropertyClass, ValueT>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
|
: pointer_vector_object_helper<ValueT>
|
||||||
{
|
{
|
||||||
// Ensure index is within bounds
|
using pointer_vector_object_helper<ValueT>::copy;
|
||||||
if (index < 0 || index >= prop.size())
|
|
||||||
throw runtime_error("Index out of bounds.");
|
|
||||||
|
|
||||||
prop.get_type().write_to(
|
static const PropertyClass *get_object(
|
||||||
stream,
|
const VectorProperty<ValueT *> &prop, const int index)
|
||||||
Value::make_reference<type>(*prop.at(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.at(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_value_from(VectorProperty<ValueT> &prop, BitStream &stream, const int index)
|
static void set_object(VectorProperty<ValueT *> &prop,
|
||||||
|
std::unique_ptr<PropertyClass> &object, const int index)
|
||||||
{
|
{
|
||||||
// Ensure index is within bounds
|
// Ensure that object inherits the type of the property
|
||||||
if (index < 0 || index >= prop.size())
|
if (object)
|
||||||
throw runtime_error("Index out of bounds.");
|
assert_type_match(prop.get_type(), object->get_type(), true);
|
||||||
|
|
||||||
Value value = prop.get_type().read_from(stream);
|
// ValueT does derive from PropertyClass, and we have a pointer to an instance
|
||||||
ValueT &value_ref = prop.at(index);
|
// of PropertyClass, so cast the pointer up to a ValueT.
|
||||||
value_ref = value.release<type>();
|
prop.at(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
|
||||||
|
* for vector properties.
|
||||||
*/
|
*/
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
struct vector_value_helper
|
struct vector_value_helper
|
||||||
{
|
{
|
||||||
static ValueT copy(VectorProperty<ValueT> &prop, const int index)
|
static Value get_value(const VectorProperty<ValueT> &prop, const int index)
|
||||||
{
|
{
|
||||||
return vector_value_object_helper<ValueT>::copy(prop, index);
|
return Value::make_reference<ValueT>(prop.at(index));
|
||||||
}
|
|
||||||
|
|
||||||
static Value get_value(const VectorProperty<ValueT> &prop,
|
|
||||||
const int index)
|
|
||||||
{
|
|
||||||
return vector_value_object_helper<ValueT>::get_value(prop, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_value(VectorProperty<ValueT> &prop,
|
static void set_value(VectorProperty<ValueT> &prop,
|
||||||
Value value, const int index)
|
Value value, const int index)
|
||||||
{
|
{
|
||||||
vector_value_object_helper<ValueT>::set_value(prop, value, index);
|
Value casted_value = value.as<ValueT>();
|
||||||
}
|
prop.at(index) = casted_value.get<ValueT>();
|
||||||
|
|
||||||
static const PropertyClass *get_object(const VectorProperty<ValueT> &prop,
|
|
||||||
const int index)
|
|
||||||
{
|
|
||||||
return vector_value_object_helper<ValueT>::get_object(prop, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_object(VectorProperty<ValueT> &prop,
|
|
||||||
std::unique_ptr<PropertyClass> &object, const int index)
|
|
||||||
{
|
|
||||||
vector_value_object_helper<ValueT>::set_object(prop, object, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_value_to(const VectorProperty<ValueT> &prop,
|
|
||||||
BitStream &stream, const int index)
|
|
||||||
{
|
|
||||||
vector_value_rw_helper<ValueT>::write_value_to(prop, stream, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void read_value_from(VectorProperty<ValueT> &prop,
|
|
||||||
BitStream &stream, const int index)
|
|
||||||
{
|
|
||||||
vector_value_rw_helper<ValueT>::read_value_from(prop, stream, index);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/// @endcond
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 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 vector_value_helper<ValueT *>
|
||||||
|
{
|
||||||
|
static Value get_value(const VectorProperty<ValueT *> &prop, const int index)
|
||||||
|
{
|
||||||
|
ValueT *value_ptr = prop.at(index);
|
||||||
|
if (value_ptr == nullptr)
|
||||||
|
throw runtime_error("Called get_value() but value is nullptr.");
|
||||||
|
return Value::make_reference<ValueT>(*value_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_value(VectorProperty<ValueT *> &prop,
|
||||||
|
Value value, const int index)
|
||||||
|
{
|
||||||
|
Value casted_value = value.as<ValueT>();
|
||||||
|
prop.at(index) = casted_value.release<ValueT>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dynamically-sized array property.
|
||||||
*/
|
*/
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
class VectorProperty : public std::vector<ValueT>, public IProperty
|
class VectorProperty : public std::vector<ValueT>, public IProperty
|
||||||
|
@ -422,7 +261,7 @@ namespace pclass
|
||||||
{
|
{
|
||||||
// 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++)
|
||||||
this->push_back(vector_value_helper<ValueT>::copy(*this, i));
|
this->push_back(detail::vector_value_helper<ValueT>::copy(*this, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool is_pointer() const override
|
constexpr bool is_pointer() const override
|
||||||
|
@ -454,34 +293,28 @@ namespace pclass
|
||||||
{
|
{
|
||||||
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 detail::vector_value_helper<ValueT>::get_value(*this, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_value(Value value, std::size_t 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 detail::vector_value_helper<ValueT>::set_value(*this, value, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PropertyClass *get_object(const std::size_t index) const override
|
const PropertyClass *get_object(const std::size_t index) const override
|
||||||
{
|
{
|
||||||
return vector_value_helper<ValueT>::get_object(*this, index);
|
if (index < 0 || index >= this->size())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
return detail::vector_object_helper<ValueT>::get_object(*this, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_object(std::unique_ptr<PropertyClass> &object, std::size_t 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);
|
if (index < 0 || index >= this->size())
|
||||||
}
|
throw runtime_error("Index out of bounds.");
|
||||||
|
return detail::vector_object_helper<ValueT>::set_object(*this, object, index);
|
||||||
void write_value_to(BitStream &stream, const std::size_t index) const override
|
|
||||||
{
|
|
||||||
vector_value_helper<ValueT>::write_value_to(*this, stream, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void read_value_from(BitStream &stream, const std::size_t index) override
|
|
||||||
{
|
|
||||||
vector_value_helper<ValueT>::read_value_from(*this, stream, index);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,5 +80,19 @@ namespace pclass
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IProperty::write_value_to(BitStream& stream, const std::size_t index) const
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= get_element_count())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
get_type().write_to(stream, get_value(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
void IProperty::read_value_from(BitStream& stream, const std::size_t index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= get_element_count())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
set_value(get_type().read_from(stream), index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue