etc: Make Type::read_from return a Value instead of reading into one

This commit is contained in:
Joshua Scott 2018-12-10 21:26:34 +00:00
parent 28eee3699c
commit c61a723174
17 changed files with 373 additions and 304 deletions

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "ki/pclass/types/EnumType.h" #include "ki/pclass/types/EnumType.h"
#include "ki/pclass/types/PrimitiveType.h" #include "ki/pclass/types/PrimitiveType.h"
#include "ki/util/BitTypes.h"
namespace ki namespace ki
{ {
@ -10,125 +9,36 @@ namespace pclass
/** /**
* TODO: Documentation * TODO: Documentation
*/ */
class IEnum class Enum
{ {
public: public:
explicit IEnum(const Type &type); explicit Enum(const Type &type, enum_value_t value = 0);
virtual ~IEnum() {} explicit Enum(const Type &type, const std::string &element_name);
Enum &operator=(const Enum &that);
const EnumType &get_type() const; const EnumType &get_type() const;
virtual void write_to(BitStream &stream) const = 0; enum_value_t get_value() const;
virtual void read_from(BitStream &stream) = 0; 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: private:
EnumType *m_type; enum_value_t m_value;
}; const 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;
}; };
} }
} }

View File

@ -248,12 +248,16 @@ namespace pclass
{ {
static void write(const StaticProperty<ValueT> &prop, BitStream &stream) 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) 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 >::type
> >
{ {
using type = typename std::remove_pointer<ValueT>::type;
static void write(const StaticProperty<ValueT> &prop, BitStream &stream) 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) 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>();
} }
}; };

View File

@ -200,7 +200,17 @@ namespace pclass
~Value(); ~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> template <typename T>
bool is() const 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> template <typename T>
const T &get() const const T &get() const
{ {
// Do we need to attempt casting? // Make sure they requested the correct type
if (!is<T>()) 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 *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> template <typename T>
T &get() T &get()
{ {
// Do we need to attempt casting? // Make sure they requested the correct type
if (!is<T>()) 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 *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. * @tparam T The type of value to hold.
* @param[in] value The initial value. * @param[in] value The initial value.
@ -278,11 +331,7 @@ namespace pclass
private: private:
void *m_value_ptr; void *m_value_ptr;
bool m_ptr_is_owned; bool m_ptr_is_owned;
std::size_t m_type_hash; std::size_t m_type_hash;
bool m_value_is_object;
bool m_value_is_enum;
ValueCaster *m_caster; ValueCaster *m_caster;
detail::ValueDeallocator m_deallocator; detail::ValueDeallocator m_deallocator;
@ -295,15 +344,6 @@ namespace pclass
template <typename T> template <typename T>
void construct() 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_type_hash = typeid(T).hash_code();
m_caster = &ValueCaster::get<T>(); m_caster = &ValueCaster::get<T>();
m_deallocator = detail::ValueDeallocator::make<T>(); m_deallocator = detail::ValueDeallocator::make<T>();

View File

@ -227,7 +227,11 @@ namespace pclass
// Ensure index is within bounds // Ensure index is within bounds
if (index < 0 || index >= prop.size()) if (index < 0 || index >= prop.size())
throw runtime_error("Index out of bounds."); 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) static void read_value_from(VectorProperty<ValueT> &prop, BitStream &stream, const int index)
@ -235,7 +239,9 @@ namespace pclass
// Ensure index is within bounds // Ensure index is within bounds
if (index < 0 || index >= prop.size()) if (index < 0 || index >= prop.size())
throw runtime_error("Index out of bounds."); 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 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) static void write_value_to(const VectorProperty<ValueT> &prop, BitStream &stream, const int index)
{ {
// Ensure index is within bounds // Ensure index is within bounds
if (index < 0 || index >= prop.size()) if (index < 0 || index >= prop.size())
throw runtime_error("Index out of bounds."); 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) 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()) if (index < 0 || index >= prop.size())
throw runtime_error("Index out of bounds."); 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>();
} }
}; };

View File

@ -1,9 +1,9 @@
#pragma once #pragma once
#include <type_traits> #include <type_traits>
#include <string> #include <string>
#include "ki/pclass/Property.h"
#include "ki/pclass/types/Type.h" #include "ki/pclass/types/Type.h"
#include "ki/pclass/PropertyClass.h" #include "ki/pclass/PropertyClass.h"
#include "ki/pclass/Property.h"
namespace ki namespace ki
{ {
@ -19,14 +19,10 @@ namespace pclass
const Type *base_class, const TypeSystem &type_system); const Type *base_class, const TypeSystem &type_system);
virtual ~IClassType() {} 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; bool inherits(const Type &type) const;
protected: void write_to(BitStream &stream, Value value) const override = 0;
virtual const PropertyClass &get_object_from_value(const Value &value) const = 0; Value read_from(BitStream &stream) const override = 0;
virtual PropertyClass &get_object_from_value(Value &value) const = 0;
private: private:
const IClassType *m_base_class; const IClassType *m_base_class;
@ -44,21 +40,29 @@ namespace pclass
public: public:
ClassType(const std::string &name, ClassType(const std::string &name,
const Type *base_class, const TypeSystem &type_system) const Type *base_class, const TypeSystem &type_system)
: IClassType(name, base_class, type_system) {} : IClassType(name, base_class, type_system)
{}
PropertyClass *instantiate() const override PropertyClass *instantiate() const override
{ {
return new ClassT(*this, get_type_system()); 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);
} }
}; };
} }

View File

@ -7,7 +7,7 @@ namespace ki
{ {
namespace pclass namespace pclass
{ {
typedef uint64_t enum_value_t; typedef uint32_t enum_value_t;
/** /**
* TODO: Documentation * TODO: Documentation
@ -42,8 +42,8 @@ namespace pclass
EnumType &add_element(const std::string &name, enum_value_t value); EnumType &add_element(const std::string &name, enum_value_t value);
void write_to(BitStream& stream, const Value& value) const override; void write_to(BitStream &stream, Value value) const override;
void read_from(BitStream& stream, Value& value) const override; Value read_from(BitStream &stream) const override;
private: private:
std::vector<Element *> m_elements; std::vector<Element *> m_elements;
@ -68,17 +68,20 @@ namespace pclass
m_kind = kind::ENUM; 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( auto &enum_reference = value.get<EnumT>();
stream, reinterpret_cast<const underlying_type &>(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( Value read_result =
stream, reinterpret_cast<underlying_type &>(value.get<EnumT>()) 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)
); );
} }
}; };

View File

@ -5,9 +5,11 @@
namespace ki namespace ki
{ {
namespace pclass namespace pclass
{
namespace detail
{ {
template <typename ValueT> template <typename ValueT>
struct PrimitiveTypeWriter< struct primitive_type_helper<
ValueT, ValueT,
typename std::enable_if<std::is_floating_point<ValueT>::value>::type 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); stream.write<uint_type>(v, bitsizeof<ValueT>::value);
} }
private: static Value read_from(BitStream &stream)
/**
* 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 void read_from(BitStream &stream, ValueT &value) uint_type uint_value = stream.read<uint_type>(bitsizeof<ValueT>::value);
{ return Value::make_value<ValueT>(*reinterpret_cast<ValueT *>(&uint_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);
} }
private: private:
@ -53,3 +38,4 @@ namespace pclass
}; };
} }
} }
}

View File

@ -5,9 +5,11 @@
namespace ki namespace ki
{ {
namespace pclass namespace pclass
{
namespace detail
{ {
template <typename ValueT> template <typename ValueT>
struct PrimitiveTypeWriter< struct primitive_type_helper<
ValueT, ValueT,
typename std::enable_if<is_integral<ValueT>::value>::type typename std::enable_if<is_integral<ValueT>::value>::type
> >
@ -16,18 +18,14 @@ namespace pclass
{ {
stream.write<ValueT>(value); stream.write<ValueT>(value);
} }
};
template <typename ValueT> static Value read_from(BitStream &stream)
struct PrimitiveTypeReader<
ValueT,
typename std::enable_if<is_integral<ValueT>::value>::type
>
{ {
static void read_from(BitStream &stream, ValueT &value) return Value::make_value<ValueT>(
{ stream.read<ValueT>()
value = stream.read<ValueT>(); );
} }
}; };
} }
} }
}

View File

@ -5,37 +5,42 @@ namespace ki
{ {
namespace pclass namespace pclass
{ {
namespace detail
{
/** /**
* TODO: Documentation * TODO: Documentation
*/ */
template <typename ValueT, typename Enable = void> template <typename ValueT, typename Enable = void>
struct PrimitiveTypeWriter struct primitive_type_helper
{ {
/**
* TODO: Documentation
*/
static void write_to(BitStream &stream, const ValueT &value) static void write_to(BitStream &stream, const ValueT &value)
{ {
// Provide a compiler error if this is not specialized // Provide a compiler error if this is not specialized
static_assert( static_assert(
sizeof(ValueT) == 0, sizeof(ValueT) == 0,
"Missing specialization of PrimitiveTypeWriter::write_to" "Missing specialization of primitive_type_writer::write_to"
); );
} }
};
/** /**
* TODO: Documentation * TODO: Documentation
*/ */
template <typename ValueT, typename Enable = void> static Value read_from(BitStream &stream)
struct PrimitiveTypeReader
{
static void read_from(BitStream &stream, ValueT &value)
{ {
// Provide a compiler error if this is not specialized // Provide a compiler error if this is not specialized
static_assert( static_assert(
sizeof(ValueT) == 0, sizeof(ValueT) == 0,
"Missing specialization of PrimitiveTypeReader::read_from" "Missing specialization of PrimitiveTypeReader::read_from"
); );
// This should be impossible to reach.
throw runtime_error("Missing specialization of PrimitiveTypeReader::read_from");
} }
}; };
}
/** /**
* TODO: Documentation * TODO: Documentation
@ -50,11 +55,16 @@ namespace pclass
m_kind = kind::PRIMITIVE; 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 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) 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 try
{ {
PrimitiveTypeReader<ValueT>::read_from(stream, value.get<ValueT>()); return detail::primitive_type_helper<ValueT>::read_from(stream);
} }
catch (runtime_error &e) catch (runtime_error &e)
{ {

View File

@ -4,13 +4,15 @@
namespace ki namespace ki
{ {
namespace pclass namespace pclass
{
namespace detail
{ {
template < template <
typename _Elem, typename _Elem,
typename _Traits, typename _Traits,
typename _Alloc typename _Alloc
> >
struct PrimitiveTypeWriter<std::basic_string<_Elem, _Traits, _Alloc>> struct primitive_type_helper<std::basic_string<_Elem, _Traits, _Alloc>>
{ {
private: private:
using type = std::basic_string<_Elem, _Traits, _Alloc>; using type = std::basic_string<_Elem, _Traits, _Alloc>;
@ -25,29 +27,21 @@ namespace pclass
for (auto it = value.begin(); it != value.end(); ++it) for (auto it = value.begin(); it != value.end(); ++it)
stream.write<_Elem>(*it); stream.write<_Elem>(*it);
} }
};
template < static Value read_from(BitStream &stream)
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)
{ {
// Read the length and create a new string with the correct capacity // Read the length and create a new string with the correct capacity
auto length = stream.read<uint16_t>(); auto length = stream.read<uint16_t>();
value = type(length, ' '); auto value = type(length, ' ');;
// Read each character into the string // Read each character into the string
for (auto it = value.begin(); it != value.end(); ++it) for (auto it = value.begin(); it != value.end(); ++it)
*it = stream.read<_Elem>(); *it = stream.read<_Elem>();
// Copy string value into the return value
return Value::make_value<type>(value);
} }
}; };
} }
} }
}

View File

@ -48,8 +48,8 @@ namespace pclass
const TypeSystem &get_type_system() const; const TypeSystem &get_type_system() const;
virtual PropertyClass *instantiate() const; virtual PropertyClass *instantiate() const;
virtual void write_to(BitStream &stream, const Value &value) const; virtual void write_to(BitStream &stream, Value value) const;
virtual void read_from(BitStream &stream, Value &value) const; virtual Value read_from(BitStream &stream) const;
protected: protected:
kind m_kind; kind m_kind;

View File

@ -28,22 +28,6 @@ namespace pclass
m_base_class = nullptr; 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 bool IClassType::inherits(const Type &type) const
{ {
// Types do not technically inherit from themselves, but it is more useful // Types do not technically inherit from themselves, but it is more useful

View File

@ -4,6 +4,116 @@ namespace ki
{ {
namespace pclass 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);
}
} }
} }

View File

@ -1,6 +1,7 @@
#include "ki/pclass/types/EnumType.h" #include "ki/pclass/types/EnumType.h"
#include "ki/util/exception.h" #include "ki/util/exception.h"
#include <sstream> #include <sstream>
#include "ki/pclass/Enum.h"
namespace ki namespace ki
{ {
@ -109,14 +110,17 @@ namespace pclass
return *this; 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);
} }
} }
} }

View File

@ -39,14 +39,14 @@ namespace pclass
return m_type_system; 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; std::ostringstream oss;
oss << "Type '" << m_name << "' does not implement Type::write_to."; oss << "Type '" << m_name << "' does not implement Type::write_to.";
throw runtime_error(oss.str()); throw runtime_error(oss.str());
} }
void Type::read_from(BitStream &stream, Value& value) const Value Type::read_from(BitStream &stream) const
{ {
std::ostringstream oss; std::ostringstream oss;
oss << "Type '" << m_name << "' does not implement Type::read_from."; oss << "Type '" << m_name << "' does not implement Type::read_from.";

View File

@ -69,8 +69,6 @@ namespace pclass
m_value_ptr = value_ptr; m_value_ptr = value_ptr;
m_ptr_is_owned = owned; m_ptr_is_owned = owned;
m_type_hash = 0; m_type_hash = 0;
m_value_is_object = false;
m_value_is_enum = false;
m_caster = nullptr; m_caster = nullptr;
m_deallocator = detail::ValueDeallocator(); m_deallocator = detail::ValueDeallocator();
} }
@ -82,9 +80,6 @@ namespace pclass
m_value_ptr = that.m_value_ptr; m_value_ptr = that.m_value_ptr;
m_ptr_is_owned = that.m_ptr_is_owned; m_ptr_is_owned = that.m_ptr_is_owned;
that.m_ptr_is_owned = false; 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_type_hash = that.m_type_hash;
m_caster = that.m_caster; m_caster = that.m_caster;
m_deallocator = std::move(that.m_deallocator); m_deallocator = std::move(that.m_deallocator);
@ -101,9 +96,6 @@ namespace pclass
m_value_ptr = that.m_value_ptr; m_value_ptr = that.m_value_ptr;
m_ptr_is_owned = that.m_ptr_is_owned; m_ptr_is_owned = that.m_ptr_is_owned;
that.m_ptr_is_owned = false; 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_type_hash = that.m_type_hash;
m_caster = that.m_caster; m_caster = that.m_caster;
m_deallocator = std::move(that.m_deallocator); m_deallocator = std::move(that.m_deallocator);

View File

@ -45,16 +45,22 @@ struct Vector3D
void write_to(BitStream &stream) const void write_to(BitStream &stream) const
{ {
pclass::PrimitiveTypeWriter<float>::write_to(stream, m_x); pclass::detail::primitive_type_helper<float>
pclass::PrimitiveTypeWriter<float>::write_to(stream, m_y); ::write_to(stream, m_x);
pclass::PrimitiveTypeWriter<float>::write_to(stream, m_z); 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) void read_from(BitStream &stream)
{ {
pclass::PrimitiveTypeReader<float>::read_from(stream, m_x); m_x = pclass::detail::primitive_type_helper<float>
pclass::PrimitiveTypeReader<float>::read_from(stream, m_y); ::read_from(stream).get<float>();
pclass::PrimitiveTypeReader<float>::read_from(stream, m_z); 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: private:
@ -63,29 +69,34 @@ private:
float m_z; float m_z;
}; };
/** namespace ki
* Type Writer for custom primitive type (Vector3D).
*/
template <>
struct pclass::PrimitiveTypeWriter<Vector3D>
{ {
namespace pclass
{
namespace detail
{
/**
* Helper for custom primitive type (Vector3D).
* Provides write_to and read_from implementations for PrimitiveType.
*/
template <>
struct primitive_type_helper<Vector3D>
{
static void write_to(BitStream &stream, const Vector3D &value) static void write_to(BitStream &stream, const Vector3D &value)
{ {
value.write_to(stream); value.write_to(stream);
} }
};
/** static Value read_from(BitStream &stream)
* Type Reader for custom primitive type (Vector3D).
*/
template <>
struct pclass::PrimitiveTypeReader<Vector3D>
{
static void read_from(BitStream &stream, Vector3D &value)
{ {
Vector3D value;
value.read_from(stream); value.read_from(stream);
return Value::make_value<Vector3D>(value);
} }
}; };
}
}
}
/** /**
* Enumeration used to test enum serialization. * Enumeration used to test enum serialization.