mirror of https://github.com/SeanOMik/libki.git
etc: Make Type::read_from return a Value instead of reading into one
This commit is contained in:
parent
28eee3699c
commit
c61a723174
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
#include "ki/pclass/types/EnumType.h"
|
||||
#include "ki/pclass/types/PrimitiveType.h"
|
||||
#include "ki/util/BitTypes.h"
|
||||
|
||||
namespace ki
|
||||
{
|
||||
|
@ -10,125 +9,36 @@ namespace pclass
|
|||
/**
|
||||
* TODO: Documentation
|
||||
*/
|
||||
class IEnum
|
||||
class Enum
|
||||
{
|
||||
public:
|
||||
explicit IEnum(const Type &type);
|
||||
virtual ~IEnum() {}
|
||||
explicit Enum(const Type &type, enum_value_t value = 0);
|
||||
explicit Enum(const Type &type, const std::string &element_name);
|
||||
Enum &operator=(const Enum &that);
|
||||
|
||||
const EnumType &get_type() const;
|
||||
|
||||
virtual void write_to(BitStream &stream) const = 0;
|
||||
virtual void read_from(BitStream &stream) = 0;
|
||||
enum_value_t get_value() const;
|
||||
void set_value(enum_value_t value);
|
||||
void set_value(const std::string &element_name);
|
||||
|
||||
void write_to(BitStream& stream) const;
|
||||
void read_from(BitStream& stream);
|
||||
|
||||
operator enum_value_t() const;
|
||||
void operator=(enum_value_t value);
|
||||
bool operator==(const enum_value_t &rhs) const;
|
||||
|
||||
operator std::string() const;
|
||||
void operator=(const std::string &element_name);
|
||||
bool operator==(const std::string &rhs) const;
|
||||
|
||||
bool operator==(const Enum &rhs) const;
|
||||
bool operator!=(const Enum &rhs) const;
|
||||
|
||||
private:
|
||||
EnumType *m_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: Documentation
|
||||
*/
|
||||
template <typename UnderlyingT>
|
||||
class Enum : public IEnum
|
||||
{
|
||||
// Make sure UnderlyingT is integral
|
||||
static_assert(
|
||||
is_integral<UnderlyingT>::value,
|
||||
"The underlying type of an enum must be integral."
|
||||
);
|
||||
|
||||
public:
|
||||
explicit Enum(const Type &type, UnderlyingT value = 0)
|
||||
: IEnum(type)
|
||||
{
|
||||
set_value(value);
|
||||
}
|
||||
|
||||
explicit Enum(const Type &type, const std::string &element_name)
|
||||
: IEnum(type)
|
||||
{
|
||||
set_value(element_name);
|
||||
}
|
||||
|
||||
UnderlyingT get_value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
virtual void set_value(UnderlyingT value)
|
||||
{
|
||||
if (value != 0 && !get_type().has_element(value))
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Enum '" << get_type().get_name()
|
||||
<< "' has no element with value: " << value << ".";
|
||||
throw runtime_error(oss.str());
|
||||
}
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
void set_value(const std::string &element_name)
|
||||
{
|
||||
m_value = get_type().get_element(element_name).get_value();
|
||||
}
|
||||
|
||||
void write_to(BitStream& stream) const override
|
||||
{
|
||||
PrimitiveTypeWriter<UnderlyingT>::write_to(stream, m_value);
|
||||
}
|
||||
|
||||
void read_from(BitStream& stream) override
|
||||
{
|
||||
UnderlyingT value;
|
||||
PrimitiveTypeReader<UnderlyingT>::read_from(stream, value);
|
||||
set_value(value);
|
||||
}
|
||||
|
||||
operator UnderlyingT() const
|
||||
{
|
||||
return get_value();
|
||||
}
|
||||
|
||||
void operator=(UnderlyingT value)
|
||||
{
|
||||
set_value(value);
|
||||
}
|
||||
|
||||
bool operator==(const UnderlyingT &rhs) const
|
||||
{
|
||||
return m_value == rhs;
|
||||
}
|
||||
|
||||
operator std::string() const
|
||||
{
|
||||
return get_type().get_element(m_value);
|
||||
}
|
||||
|
||||
void operator=(const std::string &element_name)
|
||||
{
|
||||
set_value(element_name);
|
||||
}
|
||||
|
||||
bool operator==(const std::string &rhs) const
|
||||
{
|
||||
if (!get_type().has_element(rhs))
|
||||
return false;
|
||||
return m_value == get_type().get_element(rhs).get_value();
|
||||
}
|
||||
|
||||
bool operator==(const Enum<UnderlyingT> &rhs) const
|
||||
{
|
||||
return get_type() == &rhs.get_type() &&
|
||||
m_value == rhs.m_value;
|
||||
}
|
||||
|
||||
bool operator!=(const Enum<UnderlyingT> &rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
protected:
|
||||
UnderlyingT m_value;
|
||||
enum_value_t m_value;
|
||||
const EnumType *m_type;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -248,12 +248,16 @@ namespace pclass
|
|||
{
|
||||
static void write(const StaticProperty<ValueT> &prop, BitStream &stream)
|
||||
{
|
||||
prop.get_type().write_to(stream, Value::make_reference(prop.m_value));
|
||||
prop.get_type().write_to(
|
||||
stream,
|
||||
Value::make_reference<ValueT>(prop.m_value)
|
||||
);
|
||||
}
|
||||
|
||||
static void read(StaticProperty<ValueT> &prop, BitStream &stream)
|
||||
{
|
||||
prop.get_type().read_from(stream, Value::make_reference(prop.m_value));
|
||||
Value value = prop.get_type().read_from(stream);
|
||||
prop.m_value = value.get<ValueT>();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -272,14 +276,20 @@ namespace pclass
|
|||
>::type
|
||||
>
|
||||
{
|
||||
using type = typename std::remove_pointer<ValueT>::type;
|
||||
|
||||
static void write(const StaticProperty<ValueT> &prop, BitStream &stream)
|
||||
{
|
||||
prop.get_type().write_to(stream, Value::make_reference(*prop.m_value));
|
||||
prop.get_type().write_to(
|
||||
stream,
|
||||
Value::make_reference<type>(*prop.m_value)
|
||||
);
|
||||
}
|
||||
|
||||
static void read(StaticProperty<ValueT> &prop, BitStream &stream)
|
||||
{
|
||||
prop.get_type().read_from(stream, Value::make_reference(*prop.m_value));
|
||||
Value value = prop.get_type().read_from(stream);
|
||||
prop.m_value = value.take<type>();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -200,7 +200,17 @@ namespace pclass
|
|||
~Value();
|
||||
|
||||
/**
|
||||
* @return Whether or not the value being held is of type 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns Whether or not the value being held is of type T.
|
||||
*/
|
||||
template <typename T>
|
||||
bool is() const
|
||||
|
@ -210,29 +220,72 @@ namespace pclass
|
|||
}
|
||||
|
||||
/**
|
||||
* @return A reference to the value being held as the specified type.
|
||||
* @tparam T
|
||||
* @returns A new Value instance that owns it's value.
|
||||
*/
|
||||
template <typename T>
|
||||
Value dereference() const
|
||||
{
|
||||
// Do we need to attempt casting?
|
||||
if (!is<T>())
|
||||
return m_caster->cast_value<T>(*this);
|
||||
return Value::make_value<T>(*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
|
||||
{
|
||||
// Do we need to attempt casting?
|
||||
// Make sure they requested the correct type
|
||||
if (!is<T>())
|
||||
return m_caster->cast_value<T>(*this).get<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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A reference to the value being held as the specified type.
|
||||
* @tparam T The expected type.
|
||||
* @returns A reference to the value being held.
|
||||
* @throws ki::runtime_error If the expected type and the type of the value being held are not the same.
|
||||
*/
|
||||
template <typename T>
|
||||
T &get()
|
||||
{
|
||||
// Do we need to attempt casting?
|
||||
// Make sure they requested the correct type
|
||||
if (!is<T>())
|
||||
return m_caster->cast_value<T>(*this).get<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.
|
||||
* @returns A pointer to the value being held (that the caller takes ownership of).
|
||||
* @throws ki::runtime_error If the Value is a reference.
|
||||
* @throws ki::runtime_error If the expected type and the type of the value being held are not the same.
|
||||
*/
|
||||
template <typename T>
|
||||
T *take()
|
||||
{
|
||||
// Make sure this Value is not a reference
|
||||
if (is_reference())
|
||||
throw runtime_error("Cannot take ownership from a reference Value.");
|
||||
|
||||
// Make sure they requested the correct type
|
||||
if (!is<T>())
|
||||
throw runtime_error("Invalid call to Value::get<T>.");
|
||||
|
||||
// Give up the pointer (this Value becomes a reference)
|
||||
m_ptr_is_owned = false;
|
||||
return static_cast<T *>(m_value_ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tparam T The type of value to hold.
|
||||
* @param[in] value The initial value.
|
||||
|
@ -278,11 +331,7 @@ namespace pclass
|
|||
private:
|
||||
void *m_value_ptr;
|
||||
bool m_ptr_is_owned;
|
||||
|
||||
std::size_t m_type_hash;
|
||||
bool m_value_is_object;
|
||||
bool m_value_is_enum;
|
||||
|
||||
ValueCaster *m_caster;
|
||||
detail::ValueDeallocator m_deallocator;
|
||||
|
||||
|
@ -295,15 +344,6 @@ namespace pclass
|
|||
template <typename T>
|
||||
void construct()
|
||||
{
|
||||
m_value_is_object = std::is_base_of<
|
||||
PropertyClass,
|
||||
typename std::decay<T>::type
|
||||
>::value;
|
||||
m_value_is_enum = std::is_base_of<
|
||||
IEnum,
|
||||
typename std::decay<T>::type
|
||||
>::value;
|
||||
|
||||
m_type_hash = typeid(T).hash_code();
|
||||
m_caster = &ValueCaster::get<T>();
|
||||
m_deallocator = detail::ValueDeallocator::make<T>();
|
||||
|
|
|
@ -227,7 +227,11 @@ namespace pclass
|
|||
// Ensure index is within bounds
|
||||
if (index < 0 || index >= prop.size())
|
||||
throw runtime_error("Index out of bounds.");
|
||||
prop.get_type().write_to(stream, prop.at(index));
|
||||
|
||||
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)
|
||||
|
@ -235,7 +239,9 @@ namespace pclass
|
|||
// Ensure index is within bounds
|
||||
if (index < 0 || index >= prop.size())
|
||||
throw runtime_error("Index out of bounds.");
|
||||
prop.get_type().read_from(stream, Value(prop.at(index)));
|
||||
|
||||
Value value = prop.get_type().read_from(stream);
|
||||
prop.at(index) = value.get<ValueT>();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -248,13 +254,18 @@ namespace pclass
|
|||
typename std::enable_if<std::is_pointer<ValueT>::value>::type
|
||||
>
|
||||
{
|
||||
using type = typename std::remove_pointer<ValueT>::type;
|
||||
|
||||
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(*prop.at(index)));
|
||||
prop.get_type().write_to(
|
||||
stream,
|
||||
Value::make_reference<type>(*prop.at(index))
|
||||
);
|
||||
}
|
||||
|
||||
static void read_value_from(VectorProperty<ValueT> &prop, BitStream &stream, const int index)
|
||||
|
@ -263,7 +274,9 @@ namespace pclass
|
|||
if (index < 0 || index >= prop.size())
|
||||
throw runtime_error("Index out of bounds.");
|
||||
|
||||
prop.get_type().read_from(stream, Value::make_reference(*prop.at(index)));
|
||||
Value value = prop.get_type().read_from(stream);
|
||||
ValueT &value_ref = prop.at(index);
|
||||
value_ref = value.take<type>();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
#include "ki/pclass/Property.h"
|
||||
#include "ki/pclass/types/Type.h"
|
||||
#include "ki/pclass/PropertyClass.h"
|
||||
#include "ki/pclass/Property.h"
|
||||
|
||||
namespace ki
|
||||
{
|
||||
|
@ -19,14 +19,10 @@ namespace pclass
|
|||
const Type *base_class, const TypeSystem &type_system);
|
||||
virtual ~IClassType() {}
|
||||
|
||||
void write_to(BitStream &stream, const Value &value) const override;
|
||||
void read_from(BitStream &stream, Value &value) const override;
|
||||
|
||||
bool inherits(const Type &type) const;
|
||||
|
||||
protected:
|
||||
virtual const PropertyClass &get_object_from_value(const Value &value) const = 0;
|
||||
virtual PropertyClass &get_object_from_value(Value &value) const = 0;
|
||||
void write_to(BitStream &stream, Value value) const override = 0;
|
||||
Value read_from(BitStream &stream) const override = 0;
|
||||
|
||||
private:
|
||||
const IClassType *m_base_class;
|
||||
|
@ -44,21 +40,29 @@ namespace pclass
|
|||
public:
|
||||
ClassType(const std::string &name,
|
||||
const Type *base_class, const TypeSystem &type_system)
|
||||
: IClassType(name, base_class, type_system) {}
|
||||
: IClassType(name, base_class, type_system)
|
||||
{}
|
||||
|
||||
PropertyClass *instantiate() const override
|
||||
{
|
||||
return new ClassT(*this, get_type_system());
|
||||
}
|
||||
|
||||
const PropertyClass& get_object_from_value(const Value& value) const override
|
||||
void write_to(BitStream &stream, Value value) const override
|
||||
{
|
||||
return dynamic_cast<const PropertyClass &>(value.get<ClassT>());
|
||||
const auto &object = value.get<ClassT>();
|
||||
const auto &properties = object.get_properties();
|
||||
for (auto it = properties.begin(); it != properties.end(); ++it)
|
||||
it->write_value_to(stream);
|
||||
}
|
||||
|
||||
PropertyClass& get_object_from_value(Value& value) const override
|
||||
Value read_from(BitStream &stream) const override
|
||||
{
|
||||
return dynamic_cast<PropertyClass &>(value.get<ClassT>());
|
||||
auto object = ClassT(*this, get_type_system());
|
||||
auto &properties = object.get_properties();
|
||||
for (auto it = properties.begin(); it != properties.end(); ++it)
|
||||
it->read_value_from(stream);
|
||||
return Value::make_value<ClassT>(object);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace ki
|
|||
{
|
||||
namespace pclass
|
||||
{
|
||||
typedef uint64_t enum_value_t;
|
||||
typedef uint32_t enum_value_t;
|
||||
|
||||
/**
|
||||
* TODO: Documentation
|
||||
|
@ -42,8 +42,8 @@ namespace pclass
|
|||
|
||||
EnumType &add_element(const std::string &name, enum_value_t value);
|
||||
|
||||
void write_to(BitStream& stream, const Value& value) const override;
|
||||
void read_from(BitStream& stream, Value& value) const override;
|
||||
void write_to(BitStream &stream, Value value) const override;
|
||||
Value read_from(BitStream &stream) const override;
|
||||
|
||||
private:
|
||||
std::vector<Element *> m_elements;
|
||||
|
@ -68,17 +68,20 @@ namespace pclass
|
|||
m_kind = kind::ENUM;
|
||||
}
|
||||
|
||||
void write_to(BitStream& stream, const Value &value) const override
|
||||
void write_to(BitStream &stream, const Value value) const override
|
||||
{
|
||||
PrimitiveTypeWriter<underlying_type>::write_to(
|
||||
stream, reinterpret_cast<const underlying_type &>(value.get<EnumT>())
|
||||
);
|
||||
auto &enum_reference = value.get<EnumT>();
|
||||
auto &underlying_reference = reinterpret_cast<const underlying_type &>(enum_reference);
|
||||
detail::primitive_type_helper<underlying_type>::write_to(stream, underlying_reference);
|
||||
}
|
||||
|
||||
void read_from(BitStream& stream, Value &value) const override
|
||||
Value read_from(BitStream &stream) const override
|
||||
{
|
||||
PrimitiveTypeReader<underlying_type>::read_from(
|
||||
stream, reinterpret_cast<underlying_type &>(value.get<EnumT>())
|
||||
Value read_result =
|
||||
detail::primitive_type_helper<underlying_type>::read_from(stream);
|
||||
auto underlying_value = read_result.get<underlying_type>();
|
||||
return Value::make_value<EnumT>(
|
||||
static_cast<EnumT>(underlying_value)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
namespace ki
|
||||
{
|
||||
namespace pclass
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename ValueT>
|
||||
struct PrimitiveTypeWriter<
|
||||
struct primitive_type_helper<
|
||||
ValueT,
|
||||
typename std::enable_if<std::is_floating_point<ValueT>::value>::type
|
||||
>
|
||||
|
@ -21,27 +23,10 @@ namespace pclass
|
|||
stream.write<uint_type>(v, bitsizeof<ValueT>::value);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* An unsigned integer type with the same size as the floating point type
|
||||
* ValueT.
|
||||
*/
|
||||
using uint_type = typename bits<bitsizeof<ValueT>::value>::uint_type;
|
||||
};
|
||||
|
||||
template <typename ValueT>
|
||||
struct PrimitiveTypeReader<
|
||||
ValueT,
|
||||
typename std::enable_if<std::is_floating_point<ValueT>::value>::type
|
||||
>
|
||||
static Value read_from(BitStream &stream)
|
||||
{
|
||||
static void read_from(BitStream &stream, ValueT &value)
|
||||
{
|
||||
// Reinterpret the reference as a reference to an integer
|
||||
uint_type &v = *(
|
||||
reinterpret_cast<uint_type *>(&value)
|
||||
);
|
||||
v = stream.read<uint_type>(bitsizeof<ValueT>::value);
|
||||
uint_type uint_value = stream.read<uint_type>(bitsizeof<ValueT>::value);
|
||||
return Value::make_value<ValueT>(*reinterpret_cast<ValueT *>(&uint_value));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -53,3 +38,4 @@ namespace pclass
|
|||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
namespace ki
|
||||
{
|
||||
namespace pclass
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename ValueT>
|
||||
struct PrimitiveTypeWriter<
|
||||
struct primitive_type_helper<
|
||||
ValueT,
|
||||
typename std::enable_if<is_integral<ValueT>::value>::type
|
||||
>
|
||||
|
@ -16,18 +18,14 @@ namespace pclass
|
|||
{
|
||||
stream.write<ValueT>(value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueT>
|
||||
struct PrimitiveTypeReader<
|
||||
ValueT,
|
||||
typename std::enable_if<is_integral<ValueT>::value>::type
|
||||
>
|
||||
static Value read_from(BitStream &stream)
|
||||
{
|
||||
static void read_from(BitStream &stream, ValueT &value)
|
||||
{
|
||||
value = stream.read<ValueT>();
|
||||
return Value::make_value<ValueT>(
|
||||
stream.read<ValueT>()
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,38 +4,43 @@
|
|||
namespace ki
|
||||
{
|
||||
namespace pclass
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* TODO: Documentation
|
||||
*/
|
||||
template <typename ValueT, typename Enable = void>
|
||||
struct PrimitiveTypeWriter
|
||||
struct primitive_type_helper
|
||||
{
|
||||
/**
|
||||
* TODO: Documentation
|
||||
*/
|
||||
static void write_to(BitStream &stream, const ValueT &value)
|
||||
{
|
||||
// Provide a compiler error if this is not specialized
|
||||
static_assert(
|
||||
sizeof(ValueT) == 0,
|
||||
"Missing specialization of PrimitiveTypeWriter::write_to"
|
||||
"Missing specialization of primitive_type_writer::write_to"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: Documentation
|
||||
*/
|
||||
template <typename ValueT, typename Enable = void>
|
||||
struct PrimitiveTypeReader
|
||||
{
|
||||
static void read_from(BitStream &stream, ValueT &value)
|
||||
static Value read_from(BitStream &stream)
|
||||
{
|
||||
// Provide a compiler error if this is not specialized
|
||||
static_assert(
|
||||
sizeof(ValueT) == 0,
|
||||
"Missing specialization of PrimitiveTypeReader::read_from"
|
||||
);
|
||||
|
||||
// This should be impossible to reach.
|
||||
throw runtime_error("Missing specialization of PrimitiveTypeReader::read_from");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Documentation
|
||||
|
@ -50,11 +55,16 @@ namespace pclass
|
|||
m_kind = kind::PRIMITIVE;
|
||||
}
|
||||
|
||||
void write_to(BitStream &stream, const Value &value) const override
|
||||
void write_to(BitStream &stream, const Value value) const override
|
||||
{
|
||||
try
|
||||
{
|
||||
PrimitiveTypeWriter<ValueT>::write_to(stream, value.get<ValueT>());
|
||||
// Dereference the value to the correct type
|
||||
Value deref_value = value.dereference<ValueT>();
|
||||
detail::primitive_type_helper<ValueT>::write_to(
|
||||
stream,
|
||||
deref_value.get<ValueT>()
|
||||
);
|
||||
}
|
||||
catch (runtime_error &e)
|
||||
{
|
||||
|
@ -64,11 +74,11 @@ namespace pclass
|
|||
}
|
||||
}
|
||||
|
||||
void read_from(BitStream &stream, Value &value) const override
|
||||
Value read_from(BitStream &stream) const override
|
||||
{
|
||||
try
|
||||
{
|
||||
PrimitiveTypeReader<ValueT>::read_from(stream, value.get<ValueT>());
|
||||
return detail::primitive_type_helper<ValueT>::read_from(stream);
|
||||
}
|
||||
catch (runtime_error &e)
|
||||
{
|
||||
|
|
|
@ -4,13 +4,15 @@
|
|||
namespace ki
|
||||
{
|
||||
namespace pclass
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <
|
||||
typename _Elem,
|
||||
typename _Traits,
|
||||
typename _Alloc
|
||||
>
|
||||
struct PrimitiveTypeWriter<std::basic_string<_Elem, _Traits, _Alloc>>
|
||||
struct primitive_type_helper<std::basic_string<_Elem, _Traits, _Alloc>>
|
||||
{
|
||||
private:
|
||||
using type = std::basic_string<_Elem, _Traits, _Alloc>;
|
||||
|
@ -25,29 +27,21 @@ namespace pclass
|
|||
for (auto it = value.begin(); it != value.end(); ++it)
|
||||
stream.write<_Elem>(*it);
|
||||
}
|
||||
};
|
||||
|
||||
template <
|
||||
typename _Elem,
|
||||
typename _Traits,
|
||||
typename _Alloc
|
||||
>
|
||||
struct PrimitiveTypeReader<std::basic_string<_Elem, _Traits, _Alloc>>
|
||||
{
|
||||
private:
|
||||
using type = std::basic_string<_Elem, _Traits, _Alloc>;
|
||||
|
||||
public:
|
||||
static void read_from(BitStream &stream, type &value)
|
||||
static Value read_from(BitStream &stream)
|
||||
{
|
||||
// Read the length and create a new string with the correct capacity
|
||||
auto length = stream.read<uint16_t>();
|
||||
value = type(length, ' ');
|
||||
auto value = type(length, ' ');;
|
||||
|
||||
// Read each character into the string
|
||||
for (auto it = value.begin(); it != value.end(); ++it)
|
||||
*it = stream.read<_Elem>();
|
||||
|
||||
// Copy string value into the return value
|
||||
return Value::make_value<type>(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,8 +48,8 @@ namespace pclass
|
|||
const TypeSystem &get_type_system() const;
|
||||
|
||||
virtual PropertyClass *instantiate() const;
|
||||
virtual void write_to(BitStream &stream, const Value &value) const;
|
||||
virtual void read_from(BitStream &stream, Value &value) const;
|
||||
virtual void write_to(BitStream &stream, Value value) const;
|
||||
virtual Value read_from(BitStream &stream) const;
|
||||
|
||||
protected:
|
||||
kind m_kind;
|
||||
|
|
|
@ -28,22 +28,6 @@ namespace pclass
|
|||
m_base_class = nullptr;
|
||||
}
|
||||
|
||||
void IClassType::write_to(BitStream &stream, const Value &value) const
|
||||
{
|
||||
const auto &object = get_object_from_value(value);
|
||||
const auto &properties = object.get_properties();
|
||||
for (auto it = properties.begin(); it != properties.end(); ++it)
|
||||
it->write_value_to(stream);
|
||||
}
|
||||
|
||||
void IClassType::read_from(BitStream &stream, Value &value) const
|
||||
{
|
||||
auto &object = get_object_from_value(value);
|
||||
auto &properties = object.get_properties();
|
||||
for (auto it = properties.begin(); it != properties.end(); ++it)
|
||||
it->read_value_from(stream);
|
||||
}
|
||||
|
||||
bool IClassType::inherits(const Type &type) const
|
||||
{
|
||||
// Types do not technically inherit from themselves, but it is more useful
|
||||
|
|
|
@ -4,6 +4,116 @@ namespace ki
|
|||
{
|
||||
namespace pclass
|
||||
{
|
||||
// TODO: Runtime Enum implementation
|
||||
Enum::Enum(const Type &type, const enum_value_t value)
|
||||
{
|
||||
// Make sure the type we've been given is an enum type
|
||||
if (type.get_kind() != Type::kind::ENUM)
|
||||
throw runtime_error("Enum constructor was supplied with a non-enum type.");
|
||||
|
||||
m_type = &dynamic_cast<const EnumType &>(type);
|
||||
set_value(value);
|
||||
}
|
||||
|
||||
Enum::Enum(const Type &type, const std::string &element_name)
|
||||
{
|
||||
// Make sure the type we've been given is an enum type
|
||||
if (type.get_kind() != Type::kind::ENUM)
|
||||
throw runtime_error("Enum constructor was supplied with a non-enum type.");
|
||||
|
||||
m_type = &dynamic_cast<const EnumType &>(type);
|
||||
set_value(element_name);
|
||||
}
|
||||
|
||||
Enum& Enum::operator=(const Enum& that)
|
||||
{
|
||||
// Are the types the same?
|
||||
if (&get_type() != &that.get_type())
|
||||
throw runtime_error("Cannot change Enum type after it's constructed.");
|
||||
set_value(that.m_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const EnumType &Enum::get_type() const
|
||||
{
|
||||
return *m_type;
|
||||
}
|
||||
|
||||
enum_value_t Enum::get_value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void Enum::set_value(const enum_value_t value)
|
||||
{
|
||||
// Make sure the given value is valid for this enum type
|
||||
if (value != 0 && !get_type().has_element(value))
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Enum '" << get_type().get_name()
|
||||
<< "' has no element with value: " << value << ".";
|
||||
throw runtime_error(oss.str());
|
||||
}
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
void Enum::set_value(const std::string& element_name)
|
||||
{
|
||||
m_value = get_type().get_element(element_name).get_value();
|
||||
}
|
||||
|
||||
void Enum::write_to(BitStream& stream) const
|
||||
{
|
||||
detail::primitive_type_helper<enum_value_t>::write_to(stream, m_value);
|
||||
}
|
||||
|
||||
void Enum::read_from(BitStream& stream)
|
||||
{
|
||||
const auto value = detail::primitive_type_helper<enum_value_t>
|
||||
::read_from(stream).get<enum_value_t>();
|
||||
set_value(value);
|
||||
}
|
||||
|
||||
Enum::operator enum_value_t() const
|
||||
{
|
||||
return get_value();
|
||||
}
|
||||
|
||||
void Enum::operator=(const enum_value_t value)
|
||||
{
|
||||
set_value(value);
|
||||
}
|
||||
|
||||
bool Enum::operator==(const enum_value_t &rhs) const
|
||||
{
|
||||
return m_value == rhs;
|
||||
}
|
||||
|
||||
Enum::operator std::basic_string<char>() const
|
||||
{
|
||||
return get_type().get_element(m_value).get_name();
|
||||
}
|
||||
|
||||
void Enum::operator=(const std::string& element_name)
|
||||
{
|
||||
set_value(element_name);
|
||||
}
|
||||
|
||||
bool Enum::operator==(const std::string& rhs) const
|
||||
{
|
||||
if (!get_type().has_element(rhs))
|
||||
return false;
|
||||
return m_value == get_type().get_element(rhs).get_value();
|
||||
}
|
||||
|
||||
bool Enum::operator==(const Enum &rhs) const
|
||||
{
|
||||
return &get_type() == &rhs.get_type() &&
|
||||
m_value == rhs.m_value;
|
||||
}
|
||||
|
||||
bool Enum::operator!=(const Enum& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "ki/pclass/types/EnumType.h"
|
||||
#include "ki/util/exception.h"
|
||||
#include <sstream>
|
||||
#include "ki/pclass/Enum.h"
|
||||
|
||||
namespace ki
|
||||
{
|
||||
|
@ -109,14 +110,17 @@ namespace pclass
|
|||
return *this;
|
||||
}
|
||||
|
||||
void EnumType::write_to(BitStream& stream, const Value &value) const
|
||||
void EnumType::write_to(BitStream &stream, const Value value) const
|
||||
{
|
||||
// TODO: Extend Value to get IEnum values
|
||||
// Get an Enum reference and use it to write to the stream
|
||||
value.get<Enum>().write_to(stream);
|
||||
}
|
||||
|
||||
void EnumType::read_from(BitStream& stream, Value &value) const
|
||||
Value EnumType::read_from(BitStream &stream) const
|
||||
{
|
||||
// TODO: Extend Value to get IEnum values
|
||||
auto value = Enum(*this);
|
||||
value.read_from(stream);
|
||||
return Value::make_value<Enum>(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,14 +39,14 @@ namespace pclass
|
|||
return m_type_system;
|
||||
}
|
||||
|
||||
void Type::write_to(BitStream &stream, const Value& value) const
|
||||
void Type::write_to(BitStream &stream, Value value) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Type '" << m_name << "' does not implement Type::write_to.";
|
||||
throw runtime_error(oss.str());
|
||||
}
|
||||
|
||||
void Type::read_from(BitStream &stream, Value& value) const
|
||||
Value Type::read_from(BitStream &stream) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Type '" << m_name << "' does not implement Type::read_from.";
|
||||
|
|
|
@ -69,8 +69,6 @@ namespace pclass
|
|||
m_value_ptr = value_ptr;
|
||||
m_ptr_is_owned = owned;
|
||||
m_type_hash = 0;
|
||||
m_value_is_object = false;
|
||||
m_value_is_enum = false;
|
||||
m_caster = nullptr;
|
||||
m_deallocator = detail::ValueDeallocator();
|
||||
}
|
||||
|
@ -82,9 +80,6 @@ namespace pclass
|
|||
m_value_ptr = that.m_value_ptr;
|
||||
m_ptr_is_owned = that.m_ptr_is_owned;
|
||||
that.m_ptr_is_owned = false;
|
||||
|
||||
m_value_is_object = that.m_value_is_object;
|
||||
m_value_is_enum = that.m_value_is_enum;
|
||||
m_type_hash = that.m_type_hash;
|
||||
m_caster = that.m_caster;
|
||||
m_deallocator = std::move(that.m_deallocator);
|
||||
|
@ -101,9 +96,6 @@ namespace pclass
|
|||
m_value_ptr = that.m_value_ptr;
|
||||
m_ptr_is_owned = that.m_ptr_is_owned;
|
||||
that.m_ptr_is_owned = false;
|
||||
|
||||
m_value_is_object = that.m_value_is_object;
|
||||
m_value_is_enum = that.m_value_is_enum;
|
||||
m_type_hash = that.m_type_hash;
|
||||
m_caster = that.m_caster;
|
||||
m_deallocator = std::move(that.m_deallocator);
|
||||
|
|
|
@ -45,16 +45,22 @@ struct Vector3D
|
|||
|
||||
void write_to(BitStream &stream) const
|
||||
{
|
||||
pclass::PrimitiveTypeWriter<float>::write_to(stream, m_x);
|
||||
pclass::PrimitiveTypeWriter<float>::write_to(stream, m_y);
|
||||
pclass::PrimitiveTypeWriter<float>::write_to(stream, m_z);
|
||||
pclass::detail::primitive_type_helper<float>
|
||||
::write_to(stream, m_x);
|
||||
pclass::detail::primitive_type_helper<float>
|
||||
::write_to(stream, m_y);
|
||||
pclass::detail::primitive_type_helper<float>
|
||||
::write_to(stream, m_z);
|
||||
}
|
||||
|
||||
void read_from(BitStream &stream)
|
||||
{
|
||||
pclass::PrimitiveTypeReader<float>::read_from(stream, m_x);
|
||||
pclass::PrimitiveTypeReader<float>::read_from(stream, m_y);
|
||||
pclass::PrimitiveTypeReader<float>::read_from(stream, m_z);
|
||||
m_x = pclass::detail::primitive_type_helper<float>
|
||||
::read_from(stream).get<float>();
|
||||
m_y = pclass::detail::primitive_type_helper<float>
|
||||
::read_from(stream).get<float>();
|
||||
m_z = pclass::detail::primitive_type_helper<float>
|
||||
::read_from(stream).get<float>();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -63,29 +69,34 @@ private:
|
|||
float m_z;
|
||||
};
|
||||
|
||||
namespace ki
|
||||
{
|
||||
namespace pclass
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* Type Writer for custom primitive type (Vector3D).
|
||||
* Helper for custom primitive type (Vector3D).
|
||||
* Provides write_to and read_from implementations for PrimitiveType.
|
||||
*/
|
||||
template <>
|
||||
struct pclass::PrimitiveTypeWriter<Vector3D>
|
||||
struct primitive_type_helper<Vector3D>
|
||||
{
|
||||
static void write_to(BitStream &stream, const Vector3D &value)
|
||||
{
|
||||
value.write_to(stream);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Type Reader for custom primitive type (Vector3D).
|
||||
*/
|
||||
template <>
|
||||
struct pclass::PrimitiveTypeReader<Vector3D>
|
||||
{
|
||||
static void read_from(BitStream &stream, Vector3D &value)
|
||||
static Value read_from(BitStream &stream)
|
||||
{
|
||||
Vector3D value;
|
||||
value.read_from(stream);
|
||||
return Value::make_value<Vector3D>(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration used to test enum serialization.
|
||||
|
|
Loading…
Reference in New Issue