pclass: Improve Value casting and implement basic enum types

This commit is contained in:
Joshua Scott 2018-12-09 23:21:22 +00:00
parent 595b6167c0
commit 4872d1a2a4
12 changed files with 756 additions and 99 deletions

134
include/ki/pclass/Enum.h Normal file
View File

@ -0,0 +1,134 @@
#pragma once
#include "ki/pclass/types/EnumType.h"
#include "ki/pclass/types/PrimitiveType.h"
#include "ki/util/BitTypes.h"
namespace ki
{
namespace pclass
{
/**
* TODO: Documentation
*/
class IEnum
{
public:
explicit IEnum(const Type &type);
virtual ~IEnum() {}
const EnumType &get_type() const;
virtual void write_to(BitStream &stream) const = 0;
virtual void read_from(BitStream &stream) = 0;
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;
};
}
}

View File

@ -37,7 +37,7 @@ namespace pclass
PropertyList *m_list; PropertyList *m_list;
int m_index; int m_index;
explicit iterator(PropertyList &list, const int index = 0); explicit iterator(PropertyList &list, int index = 0);
}; };
/** /**
@ -59,7 +59,7 @@ namespace pclass
const PropertyList *m_list; const PropertyList *m_list;
int m_index; int m_index;
explicit const_iterator(const PropertyList &list, const int index = 0); explicit const_iterator(const PropertyList &list, int index = 0);
}; };
std::size_t get_property_count() const; std::size_t get_property_count() const;
@ -82,13 +82,12 @@ namespace pclass
iterator end(); iterator end();
const_iterator end() const; const_iterator end() const;
protected:
void add_property(IProperty &prop);
private: private:
std::vector<IProperty *> m_properties; std::vector<IProperty *> m_properties;
std::map<std::string, IProperty *> m_property_name_lookup; std::map<std::string, IProperty *> m_property_name_lookup;
std::map<hash_t, IProperty *> m_property_hash_lookup; std::map<hash_t, IProperty *> m_property_hash_lookup;
void add_property(IProperty &prop);
}; };
} }
} }

View File

@ -248,12 +248,12 @@ 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, prop.m_value); prop.get_type().write_to(stream, Value::make_reference(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(prop.m_value)); prop.get_type().read_from(stream, Value::make_reference(prop.m_value));
} }
}; };
@ -274,12 +274,12 @@ 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, *prop.m_value); prop.get_type().write_to(stream, Value::make_reference(*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(*prop.m_value)); prop.get_type().read_from(stream, Value::make_reference(*prop.m_value));
} }
}; };
@ -367,7 +367,7 @@ namespace pclass
Value get_value() const override Value get_value() const override
{ {
return m_value; return Value::make_reference(m_value);
} }
const PropertyClass *get_object() const override const PropertyClass *get_object() const override

View File

@ -50,13 +50,11 @@ namespace pclass
} }
template <typename EnumT> template <typename EnumT>
EnumType<EnumT> &define_enum(const std::string &name) CppEnumType<EnumT> &define_enum(const std::string &name)
{ {
/* auto *type = new CppEnumType<EnumT>(name, *this);
auto *type = new EnumType<EnumT>(name, this);
define_type(type); define_type(type);
return type; return *type;
*/
} }
template <typename ClassT> template <typename ClassT>

View File

@ -2,6 +2,7 @@
#include <utility> #include <utility>
#include <typeinfo> #include <typeinfo>
#include <sstream> #include <sstream>
#include <map>
#include "ki/util/exception.h" #include "ki/util/exception.h"
namespace ki namespace ki
@ -9,90 +10,194 @@ namespace ki
namespace pclass namespace pclass
{ {
class Value; class Value;
class PropertyClass;
class IEnum;
namespace detail namespace detail
{ {
template <typename SrcT> template <typename SrcT, typename DestT>
struct value_caster_helper; struct value_caster;
/** /**
* TODO: Documentation * A base class for Value casters.
* Provides a common interface for cast()
*/ */
struct value_caster_base struct value_caster_base
{ {
virtual ~value_caster_base() {} virtual ~value_caster_base() {}
virtual Value cast(const std::type_info &dst_type, Value &v) const = 0;
protected:
/** /**
* Provides a nice way for specialized casters to throw with a * @param[in] value The value being casted.
* consistent error when casting is not possible. * @returns A new Value holding a casted value.
* @throws ki::cast_error If the cast was unsuccessful.
*/ */
Value bad_cast(const std::type_info &src_type, const std::type_info &dst_type) const; virtual Value cast(const Value &value) const;
};
/**
* A base class for Value caster implementations.
* Provides a shortcut for throwing a cast_error.
*/
template <typename SrcT, typename DestT>
struct value_caster_impl : value_caster_base
{
protected:
static Value bad_cast();
};
/**
* A base class for Value deallocators.
* Provides a common interface for deallocate()
*/
struct value_deallocator_base
{
virtual ~value_deallocator_base() {}
/**
* Deallocate a Value-owned pointer.
* @param[in] ptr The pointer to deallocate.
*/
virtual void deallocate(void *ptr) const = 0;
}; };
/** /**
* TODO: Documentation * TODO: Documentation
*/ */
struct value_caster template <typename T>
struct value_deallocator : value_deallocator_base
{ {
// Allow Value to call the default constructor and make void deallocate(void *ptr) const override
{
// By default, now that we have the proper type, just delete it.
delete static_cast<T *>(ptr);
}
};
/**
* TODO: Documentation
*/
class ValueDeallocator
{
// Allow Value to call make<T>() and the default constructor
friend Value; friend Value;
public:
ValueDeallocator(ValueDeallocator &&that) noexcept;
ValueDeallocator &operator=(ValueDeallocator &&that) noexcept;
~ValueDeallocator();
/** /**
* @tparam DstT The cast destination type. * Deallocate a Value-owned pointer.
* @param[in] value The Value that is being casted to the destination type. * @param[in] ptr The pointer to deallocate.
* @returns A Value with a reference that has been casted to the destination type.
*/ */
template <typename DstT> void deallocate(void *ptr) const;
Value cast(const Value &value) const;
private: private:
value_caster_base *m_caster; value_deallocator_base *m_deallocator;
explicit value_caster(value_caster_base *caster = nullptr) ValueDeallocator();
{ explicit ValueDeallocator(value_deallocator_base *deallocator);
m_caster = caster;
}
/** template <typename T>
* @tparam SrcT static ValueDeallocator make()
*/
template <typename SrcT>
static value_caster make()
{ {
return value_caster(new value_caster_helper<SrcT>()); return ValueDeallocator(new value_deallocator<T>());
} }
}; };
} }
/**
* TODO: Documentation
*/
class ValueCaster
{
// Allow Value to call the default constructor and get<SrcT>()
friend Value;
public:
~ValueCaster();
/**
* Declare a run-time casting interface from SrcT to DestT.
* @tparam SrcT The cast source type.
* @tparam DestT the cast destination type.
*/
template <typename SrcT, typename DestT>
static void declare()
{
ValueCaster::get<SrcT>().add_caster<SrcT, DestT>();
}
/**
* @tparam SrcT The cast source type.
* @tparam DestT The cast destination type.
* @param[in] value The Value that is being casted to the destination type.
* @returns A Value with a reference to a DestT value/instance.
*/
template <typename SrcT, typename DestT>
static Value cast(const Value &value);
/**
* @tparam DestT The cast destination type.
* @param[in] src_type The std::type_info object of the source type.
* @param[in] value The Value that is being casted to the destination type.
* @returns A Value with a reference to a DestT value/instance.
*/
template <typename DestT>
static Value cast(const std::type_info &src_type, const Value &value);
/**
* @tparam DestT The cast destination type.
* @param[in] value The Value that is being casted to the destination type.
* @returns A Value with a reference to a DestT value/instance.
*/
template <typename DestT>
Value cast_value(const Value &value) const;
private:
/**
* A static lookup used to find appropriate casters at runtime.
* Contains SrcT -> Caster elements.
*/
static std::map<std::size_t, ValueCaster *> s_caster_lookup;
const std::type_info *m_src_type;
std::map<std::size_t, detail::value_caster_base *> m_casts;
ValueCaster();
explicit ValueCaster(const std::type_info &src_type);
/**
* @tparam SrcT The cast source type.
* @returns The ValueCaster instance responsible for casting values of type SrcT.
*/
template <typename SrcT>
static ValueCaster &get()
{
const auto &src_type = typeid(SrcT);
const auto src_type_hash = src_type.hash_code();
if (s_caster_lookup.find(src_type_hash) == s_caster_lookup.end())
s_caster_lookup[src_type_hash] = new ValueCaster(src_type);
return *s_caster_lookup[src_type_hash];
}
template <typename SrcT, typename DestT>
void add_caster()
{
const auto dest_type_hash = typeid(DestT).hash_code();
m_casts[dest_type_hash] = new detail::value_caster<SrcT, DestT>();
}
};
/** /**
* A wrapper around a void pointer that ensures type safety. * A wrapper around a void pointer that ensures type safety.
*/ */
class Value class Value
{ {
public: public:
template <typename T> Value(Value &&that) noexcept;
Value(T &value) Value &operator=(Value &&that) noexcept;
{ ~Value();
m_value_ptr = static_cast<void *>(&value);
m_type_hash = typeid(value).hash_code();
m_caster = detail::value_caster::make<T>();
}
template <typename T>
Value(const T &value)
{
m_value_ptr = const_cast<void *>(static_cast<const void *>(&value));
m_type_hash = typeid(value).hash_code();
m_caster = detail::value_caster::make<T>();
}
Value(Value &&o) noexcept
: m_value_ptr(std::move(o.m_value_ptr))
, m_type_hash(std::move(o.m_type_hash))
, m_caster(std::move(o.m_caster))
{}
/** /**
* @return Whether or not the value being held is of type T. * @return Whether or not the value being held is of type T.
@ -112,7 +217,7 @@ namespace pclass
{ {
// Do we need to attempt casting? // Do we need to attempt casting?
if (!is<T>()) if (!is<T>())
return m_caster.cast<T>(*this).get<T>(); return m_caster->cast_value<T>(*this).get<T>();
return *static_cast<T *>(m_value_ptr); return *static_cast<T *>(m_value_ptr);
} }
@ -124,42 +229,130 @@ namespace pclass
{ {
// Do we need to attempt casting? // Do we need to attempt casting?
if (!is<T>()) if (!is<T>())
return m_caster.cast<T>(*this).get<T>(); return m_caster->cast_value<T>(*this).get<T>();
return *static_cast<T *>(m_value_ptr); return *static_cast<T *>(m_value_ptr);
} }
/**
* @tparam T The type of value to hold.
* @param[in] value The initial value.
* @returns A new Value instance that owns it's value.
*/
template <typename T>
static Value make_value(T value)
{
auto *ptr = static_cast<void *>(new T(value));
auto val = Value(ptr, true);
val.construct<T>();
return val;
}
/**
* @tparam T The type of value to hold.
* @param[in] value The initial value.
* @returns A new Value instance that refers to a value it doesn't own.
*/
template <typename T>
static Value make_reference(T &value)
{
auto *ptr = static_cast<void *>(&value);
auto val = Value(ptr);
val.construct<T>();
return val;
}
/**
* @tparam T The type of value to hold.
* @param[in] value The initial value.
* @returns A new Value instance that refers to a value it doesn't own.
*/
template <typename T>
static Value make_reference(const T &value)
{
auto *ptr = const_cast<void *>(static_cast<const void *>(&value));
auto val = Value(ptr);
val.construct<T>();
return val;
}
private: private:
void *m_value_ptr; void *m_value_ptr;
bool m_ptr_is_owned;
std::size_t m_type_hash; std::size_t m_type_hash;
detail::value_caster m_caster; bool m_value_is_object;
bool m_value_is_enum;
ValueCaster *m_caster;
detail::ValueDeallocator m_deallocator;
explicit Value(void *value_ptr, bool owned = false);
/**
* Set values that depend on knowing T.
* @tparam T The type that is being held.
*/
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>();
}
}; };
template <typename DestT>
Value ValueCaster::cast(const std::type_info &src_type, const Value& value)
{
const auto it = s_caster_lookup.find(src_type.hash_code());
if (it != s_caster_lookup.end())
return it->second.cast<DestT>(value);
throw cast_error(src_type, typeid(DestT));
}
template <typename SrcT, typename DestT>
Value ValueCaster::cast(const Value& value)
{
ValueCaster::declare<SrcT, DestT>();
return ValueCaster::get<SrcT>().cast<DestT>(value);
}
template <typename DestT>
Value ValueCaster::cast_value(const Value& value) const
{
const auto it = m_casts.find(typeid(DestT).hash_code());
if (it != m_casts.end())
return it->second->cast(value);
throw cast_error(*m_src_type, typeid(DestT));
}
namespace detail namespace detail
{ {
inline Value value_caster_base::bad_cast( template <typename SrcT, typename DestT>
const std::type_info& src_type, const std::type_info& dst_type) const Value value_caster_impl<SrcT, DestT>::bad_cast()
{ {
std::ostringstream oss; throw cast_error(typeid(SrcT), typeid(DestT));
oss << "Cannot cast Value from " << src_type.name()
<< " to " << dst_type.name() << ".";
throw runtime_error(oss.str());
}
template <typename DstT>
Value value_caster::cast(const Value &value) const
{
return m_caster->cast(typeid(DstT), const_cast<Value &>(value));
} }
/** /**
* TODO: Documentation * TODO: Documentation
*/ */
template <typename SrcT> template <typename SrcT, typename DestT>
struct value_caster_helper : value_caster_base struct value_caster : value_caster_impl<SrcT, DestT>
{ {
Value cast(const std::type_info &dst_type, Value& value) const override Value cast(const Value &value) const override
{ {
return bad_cast(typeid(SrcT), dst_type); // By default, just attempt to static_cast from SrcT to DestT.
return static_cast<DestT>(value.get<SrcT>());
} }
}; };
} }

View File

@ -254,7 +254,7 @@ 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().write_to(stream, *prop.at(index)); prop.get_type().write_to(stream, Value::make_reference(*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 +263,7 @@ 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(*prop.at(index))); prop.get_type().read_from(stream, Value::make_reference(*prop.at(index)));
} }
}; };
@ -344,7 +344,7 @@ 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 this->at(index); return Value::make_reference(this->at(index));
} }
const PropertyClass *get_object(const int index) const override const PropertyClass *get_object(const int index) const override

View File

@ -6,27 +6,80 @@ namespace ki
{ {
namespace pclass namespace pclass
{ {
typedef uint64_t enum_value_t;
/** /**
* TODO: Documentation * TODO: Documentation
*/ */
class EnumOption
{
private:
std::string m_name;
uint32_t m_value;
};
/**
* TODO: Documentation
*/
template <typename EnumT>
class EnumType : public Type class EnumType : public Type
{ {
// Ensure that EnumT is an enum /**
static_assert(std::is_enum<EnumT>::value, "EnumT must be an enum!"); * TODO: Documentation
*/
class Element
{
public:
explicit Element(const std::string &name, enum_value_t value);
std::string get_name() const;
enum_value_t get_value() const;
private:
std::string m_name;
enum_value_t m_value;
};
public: public:
EnumType(const std::string &name, const TypeSystem &type_system); EnumType(const std::string &name, const TypeSystem &type_system);
~EnumType();
bool has_element(const std::string &name) const;
bool has_element(enum_value_t value) const;
const Element &get_element(const std::string &name) const;
const Element &get_element(enum_value_t value) const;
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;
private:
std::vector<Element *> m_elements;
std::map<std::string, Element *> m_element_name_lookup;
std::map<enum_value_t, Element *> m_element_value_lookup;
};
/**
* TODO: Documentation
*/
template <typename EnumT>
class CppEnumType : public Type
{
// Ensure that EnumT is an enum
static_assert(std::is_enum<EnumT>::value, "EnumT must be an enum!");
using underlying_type = typename std::underlying_type<EnumT>::type;
public:
CppEnumType(const std::string &name, const TypeSystem &type_system)
: Type(name, type_system)
{
m_kind = kind::ENUM;
}
void write_to(BitStream& stream, const Value &value) const override
{
PrimitiveTypeWriter<underlying_type>::write_to(
stream, reinterpret_cast<const underlying_type &>(value.get<EnumT>())
);
}
void read_from(BitStream& stream, Value &value) const override
{
PrimitiveTypeReader<underlying_type>::read_from(
stream, reinterpret_cast<underlying_type &>(value.get<EnumT>())
);
}
}; };
} }
} }

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <stdexcept> #include <stdexcept>
#include <typeinfo>
#include <sstream>
namespace ki namespace ki
{ {
@ -9,4 +11,24 @@ namespace ki
explicit runtime_error(const std::string &message) explicit runtime_error(const std::string &message)
: std::runtime_error(message) {} : std::runtime_error(message) {}
}; };
}
class cast_error : public std::exception
{
public:
cast_error(const std::type_info &src_type, const std::type_info &dest_type)
{
std::ostringstream oss;
oss << "Cannot cast from " << src_type.name()
<< " to " << dest_type.name() << ".";
m_what = oss.str();
}
char const* what() const override
{
return m_what.c_str();
}
private:
std::string m_what;
};
}

View File

@ -1,10 +1,13 @@
target_sources(${PROJECT_NAME} target_sources(${PROJECT_NAME}
PRIVATE PRIVATE
${PROJECT_SOURCE_DIR}/src/pclass/ClassType.cpp ${PROJECT_SOURCE_DIR}/src/pclass/ClassType.cpp
${PROJECT_SOURCE_DIR}/src/pclass/Enum.cpp
${PROJECT_SOURCE_DIR}/src/pclass/EnumType.cpp
${PROJECT_SOURCE_DIR}/src/pclass/HashCalculator.cpp ${PROJECT_SOURCE_DIR}/src/pclass/HashCalculator.cpp
${PROJECT_SOURCE_DIR}/src/pclass/Property.cpp ${PROJECT_SOURCE_DIR}/src/pclass/Property.cpp
${PROJECT_SOURCE_DIR}/src/pclass/PropertyClass.cpp ${PROJECT_SOURCE_DIR}/src/pclass/PropertyClass.cpp
${PROJECT_SOURCE_DIR}/src/pclass/PropertyList.cpp ${PROJECT_SOURCE_DIR}/src/pclass/PropertyList.cpp
${PROJECT_SOURCE_DIR}/src/pclass/Type.cpp ${PROJECT_SOURCE_DIR}/src/pclass/Type.cpp
${PROJECT_SOURCE_DIR}/src/pclass/TypeSystem.cpp ${PROJECT_SOURCE_DIR}/src/pclass/TypeSystem.cpp
${PROJECT_SOURCE_DIR}/src/pclass/Value.cpp
) )

9
src/pclass/Enum.cpp Normal file
View File

@ -0,0 +1,9 @@
#include "ki/pclass/Enum.h"
namespace ki
{
namespace pclass
{
// TODO: Runtime Enum implementation
}
}

122
src/pclass/EnumType.cpp Normal file
View File

@ -0,0 +1,122 @@
#include "ki/pclass/types/EnumType.h"
#include "ki/util/exception.h"
#include <sstream>
namespace ki
{
namespace pclass
{
EnumType::Element::Element(const std::string &name,
const enum_value_t value)
{
m_name = name;
m_value = value;
}
std::string EnumType::Element::get_name() const
{
return m_name;
}
enum_value_t EnumType::Element::get_value() const
{
return m_value;
}
EnumType::EnumType(const std::string &name,
const TypeSystem &type_system)
: Type(name, type_system)
{
m_kind = kind::ENUM;
}
EnumType::~EnumType()
{
for (auto it = m_elements.begin();
it != m_elements.end(); ++it)
{
delete *it;
}
}
bool EnumType::has_element(const std::string& name) const
{
return m_element_name_lookup.find(name) != m_element_name_lookup.end();
}
bool EnumType::has_element(const enum_value_t value) const
{
return m_element_value_lookup.find(value) != m_element_value_lookup.end();
}
const EnumType::Element& EnumType::get_element(const std::string& name) const
{
const auto &it = m_element_name_lookup.find(name);
if (it == m_element_name_lookup.end())
{
std::ostringstream oss;
oss << "No element called '" << name
<< "' exists in enum: '" << get_name() << "'.";
throw runtime_error(oss.str());
}
return *it->second;
}
const EnumType::Element& EnumType::get_element(const enum_value_t value) const
{
const auto &it = m_element_value_lookup.find(value);
if (it == m_element_value_lookup.end())
{
std::ostringstream oss;
oss << "No element with value " << value
<< " exists in enum: '" << get_name() << "'.";
throw runtime_error(oss.str());
}
return *it->second;
}
EnumType& EnumType::add_element(const std::string &name,
const enum_value_t value)
{
// Has an element already been added with this name?
if (has_element(name))
{
std::ostringstream oss;
oss << "Enum '" << get_name()
<< "' already has an element called '"
<< name << "'.";
throw runtime_error(oss.str());
}
// Has an element already been added with this value?
if (has_element(value))
{
std::ostringstream oss;
oss << "Enum '" << get_name()
<< "' already has an element with the value '"
<< value << "'.";
throw runtime_error(oss.str());
}
// Create the element and add it to our lookups
auto *element = new Element(name, value);
m_elements.push_back(element);
m_element_name_lookup[name] = element;
m_element_value_lookup[value] = element;
return *this;
}
void EnumType::write_to(BitStream& stream, const Value &value) const
{
// TODO: Extend Value to get IEnum values
}
void EnumType::read_from(BitStream& stream, Value &value) const
{
// TODO: Extend Value to get IEnum values
}
}
}

124
src/pclass/Value.cpp Normal file
View File

@ -0,0 +1,124 @@
#include "ki/pclass/Value.h"
namespace ki
{
namespace pclass
{
namespace detail
{
Value value_caster_base::cast(const Value& v) const
{
throw runtime_error("Unimplemented cast.");
}
ValueDeallocator::ValueDeallocator()
{
m_deallocator = nullptr;
}
ValueDeallocator::ValueDeallocator(value_deallocator_base *deallocator)
{
m_deallocator = deallocator;
}
ValueDeallocator::ValueDeallocator(ValueDeallocator &&that) noexcept
{
m_deallocator = that.m_deallocator;
that.m_deallocator = nullptr;
}
ValueDeallocator& ValueDeallocator::operator=(ValueDeallocator &&that) noexcept
{
m_deallocator = that.m_deallocator;
that.m_deallocator = nullptr;
return *this;
}
ValueDeallocator::~ValueDeallocator()
{
delete m_deallocator;
}
void ValueDeallocator::deallocate(void* ptr) const
{
m_deallocator->deallocate(ptr);
}
}
ValueCaster::ValueCaster()
{
m_src_type = nullptr;
}
ValueCaster::~ValueCaster()
{
for (auto it = m_casts.begin();
it != m_casts.end(); ++it)
{
delete it->second;
}
}
ValueCaster::ValueCaster(const std::type_info& src_type)
{
m_src_type = &src_type;
}
Value::Value(void *value_ptr, const bool owned)
{
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();
}
Value::Value(Value&& that) noexcept
{
// Move pointer to this Value object, and take ownership if
// the other Value previously owned it.
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);
}
Value &Value::operator=(Value&& that) noexcept
{
// If the current pointer is owned, deallocate it
if (m_ptr_is_owned)
m_deallocator.deallocate(m_value_ptr);
// Move pointer to this Value object, and take ownership if
// the other Value previously owned it.
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);
return *this;
}
Value::~Value()
{
if (m_value_ptr && m_ptr_is_owned)
m_deallocator.deallocate(m_value_ptr);
m_value_ptr = nullptr;
}
// Initialize the static lookup map
std::map<std::size_t, ValueCaster *> ValueCaster::s_caster_lookup = {};
}
}