From 4872d1a2a464b8dd2ef2ca72ce172c1e6a9a2169 Mon Sep 17 00:00:00 2001 From: Joshua Scott Date: Sun, 9 Dec 2018 23:21:22 +0000 Subject: [PATCH] pclass: Improve Value casting and implement basic enum types --- include/ki/pclass/Enum.h | 134 ++++++++++++ include/ki/pclass/PropertyList.h | 9 +- include/ki/pclass/StaticProperty.h | 10 +- include/ki/pclass/TypeSystem.h | 8 +- include/ki/pclass/Value.h | 327 +++++++++++++++++++++++------ include/ki/pclass/VectorProperty.h | 6 +- include/ki/pclass/types/EnumType.h | 79 +++++-- include/ki/util/exception.h | 24 ++- src/pclass/CMakeLists.txt | 3 + src/pclass/Enum.cpp | 9 + src/pclass/EnumType.cpp | 122 +++++++++++ src/pclass/Value.cpp | 124 +++++++++++ 12 files changed, 756 insertions(+), 99 deletions(-) create mode 100644 include/ki/pclass/Enum.h create mode 100644 src/pclass/Enum.cpp create mode 100644 src/pclass/EnumType.cpp create mode 100644 src/pclass/Value.cpp diff --git a/include/ki/pclass/Enum.h b/include/ki/pclass/Enum.h new file mode 100644 index 0000000..50adc36 --- /dev/null +++ b/include/ki/pclass/Enum.h @@ -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 + class Enum : public IEnum + { + // Make sure UnderlyingT is integral + static_assert( + is_integral::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::write_to(stream, m_value); + } + + void read_from(BitStream& stream) override + { + UnderlyingT value; + PrimitiveTypeReader::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 &rhs) const + { + return get_type() == &rhs.get_type() && + m_value == rhs.m_value; + } + + bool operator!=(const Enum &rhs) const + { + return !(*this == rhs); + } + + protected: + UnderlyingT m_value; + }; +} +} \ No newline at end of file diff --git a/include/ki/pclass/PropertyList.h b/include/ki/pclass/PropertyList.h index a0102f2..63e0524 100644 --- a/include/ki/pclass/PropertyList.h +++ b/include/ki/pclass/PropertyList.h @@ -37,7 +37,7 @@ namespace pclass PropertyList *m_list; 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; 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; @@ -82,13 +82,12 @@ namespace pclass iterator end(); const_iterator end() const; - protected: - void add_property(IProperty &prop); - private: std::vector m_properties; std::map m_property_name_lookup; std::map m_property_hash_lookup; + + void add_property(IProperty &prop); }; } } diff --git a/include/ki/pclass/StaticProperty.h b/include/ki/pclass/StaticProperty.h index 0d0e3dd..7963a85 100644 --- a/include/ki/pclass/StaticProperty.h +++ b/include/ki/pclass/StaticProperty.h @@ -248,12 +248,12 @@ namespace pclass { static void write(const StaticProperty &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 &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 &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 &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 { - return m_value; + return Value::make_reference(m_value); } const PropertyClass *get_object() const override diff --git a/include/ki/pclass/TypeSystem.h b/include/ki/pclass/TypeSystem.h index efc5824..a167ed1 100644 --- a/include/ki/pclass/TypeSystem.h +++ b/include/ki/pclass/TypeSystem.h @@ -50,13 +50,11 @@ namespace pclass } template - EnumType &define_enum(const std::string &name) + CppEnumType &define_enum(const std::string &name) { - /* - auto *type = new EnumType(name, this); + auto *type = new CppEnumType(name, *this); define_type(type); - return type; - */ + return *type; } template diff --git a/include/ki/pclass/Value.h b/include/ki/pclass/Value.h index b7e258a..a88da21 100644 --- a/include/ki/pclass/Value.h +++ b/include/ki/pclass/Value.h @@ -2,6 +2,7 @@ #include #include #include +#include #include "ki/util/exception.h" namespace ki @@ -9,90 +10,194 @@ namespace ki namespace pclass { class Value; + class PropertyClass; + class IEnum; namespace detail { - template - struct value_caster_helper; + template + struct value_caster; /** - * TODO: Documentation + * A base class for Value casters. + * Provides a common interface for cast() */ struct 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 - * consistent error when casting is not possible. + * @param[in] value The value being casted. + * @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 + 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 */ - struct value_caster + template + 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(ptr); + } + }; + + /** + * TODO: Documentation + */ + class ValueDeallocator + { + // Allow Value to call make() and the default constructor friend Value; + public: + ValueDeallocator(ValueDeallocator &&that) noexcept; + ValueDeallocator &operator=(ValueDeallocator &&that) noexcept; + ~ValueDeallocator(); + /** - * @tparam DstT The cast destination type. - * @param[in] value The Value that is being casted to the destination type. - * @returns A Value with a reference that has been casted to the destination type. + * Deallocate a Value-owned pointer. + * @param[in] ptr The pointer to deallocate. */ - template - Value cast(const Value &value) const; - + void deallocate(void *ptr) const; + private: - value_caster_base *m_caster; + value_deallocator_base *m_deallocator; - explicit value_caster(value_caster_base *caster = nullptr) - { - m_caster = caster; - } + ValueDeallocator(); + explicit ValueDeallocator(value_deallocator_base *deallocator); - /** - * @tparam SrcT - */ - template - static value_caster make() + template + static ValueDeallocator make() { - return value_caster(new value_caster_helper()); + return ValueDeallocator(new value_deallocator()); } }; } + /** + * TODO: Documentation + */ + class ValueCaster + { + // Allow Value to call the default constructor and get() + 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 + static void declare() + { + ValueCaster::get().add_caster(); + } + + /** + * @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 + 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 + 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 + 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 s_caster_lookup; + + const std::type_info *m_src_type; + std::map 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 + 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 + void add_caster() + { + const auto dest_type_hash = typeid(DestT).hash_code(); + m_casts[dest_type_hash] = new detail::value_caster(); + } + }; + /** * A wrapper around a void pointer that ensures type safety. */ class Value { public: - template - Value(T &value) - { - m_value_ptr = static_cast(&value); - m_type_hash = typeid(value).hash_code(); - m_caster = detail::value_caster::make(); - } - - template - Value(const T &value) - { - m_value_ptr = const_cast(static_cast(&value)); - m_type_hash = typeid(value).hash_code(); - m_caster = detail::value_caster::make(); - } - - 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)) - {} + Value(Value &&that) noexcept; + Value &operator=(Value &&that) noexcept; + ~Value(); /** * @return Whether or not the value being held is of type T. @@ -112,7 +217,7 @@ namespace pclass { // Do we need to attempt casting? if (!is()) - return m_caster.cast(*this).get(); + return m_caster->cast_value(*this).get(); return *static_cast(m_value_ptr); } @@ -124,42 +229,130 @@ namespace pclass { // Do we need to attempt casting? if (!is()) - return m_caster.cast(*this).get(); + return m_caster->cast_value(*this).get(); return *static_cast(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 + static Value make_value(T value) + { + auto *ptr = static_cast(new T(value)); + auto val = Value(ptr, true); + val.construct(); + 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 + static Value make_reference(T &value) + { + auto *ptr = static_cast(&value); + auto val = Value(ptr); + val.construct(); + 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 + static Value make_reference(const T &value) + { + auto *ptr = const_cast(static_cast(&value)); + auto val = Value(ptr); + val.construct(); + return val; + } + private: void *m_value_ptr; + bool m_ptr_is_owned; + 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 + void construct() + { + m_value_is_object = std::is_base_of< + PropertyClass, + typename std::decay::type + >::value; + m_value_is_enum = std::is_base_of< + IEnum, + typename std::decay::type + >::value; + + m_type_hash = typeid(T).hash_code(); + m_caster = &ValueCaster::get(); + m_deallocator = detail::ValueDeallocator::make(); + } }; + template + 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(value); + throw cast_error(src_type, typeid(DestT)); + } + + template + Value ValueCaster::cast(const Value& value) + { + ValueCaster::declare(); + return ValueCaster::get().cast(value); + } + + template + 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 { - inline Value value_caster_base::bad_cast( - const std::type_info& src_type, const std::type_info& dst_type) const + template + Value value_caster_impl::bad_cast() { - std::ostringstream oss; - oss << "Cannot cast Value from " << src_type.name() - << " to " << dst_type.name() << "."; - throw runtime_error(oss.str()); - } - - template - Value value_caster::cast(const Value &value) const - { - return m_caster->cast(typeid(DstT), const_cast(value)); + throw cast_error(typeid(SrcT), typeid(DestT)); } /** * TODO: Documentation */ - template - struct value_caster_helper : value_caster_base + template + struct value_caster : value_caster_impl { - 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(value.get()); } }; } diff --git a/include/ki/pclass/VectorProperty.h b/include/ki/pclass/VectorProperty.h index a44cd44..94dae5b 100644 --- a/include/ki/pclass/VectorProperty.h +++ b/include/ki/pclass/VectorProperty.h @@ -254,7 +254,7 @@ namespace pclass 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(*prop.at(index))); } static void read_value_from(VectorProperty &prop, BitStream &stream, const int index) @@ -263,7 +263,7 @@ namespace pclass if (index < 0 || index >= prop.size()) 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()) 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 diff --git a/include/ki/pclass/types/EnumType.h b/include/ki/pclass/types/EnumType.h index 40ed56b..ef06c5b 100644 --- a/include/ki/pclass/types/EnumType.h +++ b/include/ki/pclass/types/EnumType.h @@ -6,27 +6,80 @@ namespace ki { namespace pclass { + typedef uint64_t enum_value_t; + /** * TODO: Documentation */ - class EnumOption - { - private: - std::string m_name; - uint32_t m_value; - }; - - /** - * TODO: Documentation - */ - template class EnumType : public Type { - // Ensure that EnumT is an enum - static_assert(std::is_enum::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: 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 m_elements; + std::map m_element_name_lookup; + std::map m_element_value_lookup; + }; + + /** + * TODO: Documentation + */ + template + class CppEnumType : public Type + { + // Ensure that EnumT is an enum + static_assert(std::is_enum::value, "EnumT must be an enum!"); + using underlying_type = typename std::underlying_type::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::write_to( + stream, reinterpret_cast(value.get()) + ); + } + + void read_from(BitStream& stream, Value &value) const override + { + PrimitiveTypeReader::read_from( + stream, reinterpret_cast(value.get()) + ); + } }; } } diff --git a/include/ki/util/exception.h b/include/ki/util/exception.h index 2c240e4..96d6756 100644 --- a/include/ki/util/exception.h +++ b/include/ki/util/exception.h @@ -1,5 +1,7 @@ #pragma once #include +#include +#include namespace ki { @@ -9,4 +11,24 @@ namespace ki explicit runtime_error(const std::string &message) : std::runtime_error(message) {} }; -} \ No newline at end of file + + 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; + }; +} diff --git a/src/pclass/CMakeLists.txt b/src/pclass/CMakeLists.txt index dbc01e3..f1c295f 100644 --- a/src/pclass/CMakeLists.txt +++ b/src/pclass/CMakeLists.txt @@ -1,10 +1,13 @@ target_sources(${PROJECT_NAME} PRIVATE ${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/Property.cpp ${PROJECT_SOURCE_DIR}/src/pclass/PropertyClass.cpp ${PROJECT_SOURCE_DIR}/src/pclass/PropertyList.cpp ${PROJECT_SOURCE_DIR}/src/pclass/Type.cpp ${PROJECT_SOURCE_DIR}/src/pclass/TypeSystem.cpp + ${PROJECT_SOURCE_DIR}/src/pclass/Value.cpp ) \ No newline at end of file diff --git a/src/pclass/Enum.cpp b/src/pclass/Enum.cpp new file mode 100644 index 0000000..acc8e6e --- /dev/null +++ b/src/pclass/Enum.cpp @@ -0,0 +1,9 @@ +#include "ki/pclass/Enum.h" + +namespace ki +{ +namespace pclass +{ + // TODO: Runtime Enum implementation +} +} diff --git a/src/pclass/EnumType.cpp b/src/pclass/EnumType.cpp new file mode 100644 index 0000000..ce92a15 --- /dev/null +++ b/src/pclass/EnumType.cpp @@ -0,0 +1,122 @@ +#include "ki/pclass/types/EnumType.h" +#include "ki/util/exception.h" +#include + +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 + } +} +} diff --git a/src/pclass/Value.cpp b/src/pclass/Value.cpp new file mode 100644 index 0000000..9ce5b4c --- /dev/null +++ b/src/pclass/Value.cpp @@ -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 ValueCaster::s_caster_lookup = {}; +} +}