pclass: Cleanup VectorProperty and fix build errors

This commit is contained in:
Joshua Scott 2018-12-21 01:20:52 +00:00
parent 2dad313885
commit bab80d20c7
4 changed files with 271 additions and 432 deletions

View File

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

View File

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

View File

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

View File

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