etc: Refactoring, documentation, and more tests

This commit is contained in:
Joshua Scott 2019-01-01 20:54:57 +00:00
parent bab80d20c7
commit 4833f7fb76
36 changed files with 891 additions and 528 deletions

View File

@ -4,7 +4,7 @@
#include <json.hpp> #include <json.hpp>
#include "ki/pclass/Value.h" #include "ki/pclass/Value.h"
#include "ki/util/BitTypes.h" #include "ki/util/BitTypes.h"
#include "ki/pclass/types/EnumType.h" #include "ki/pclass/EnumType.h"
namespace ki namespace ki
{ {

View File

@ -3,7 +3,7 @@
#include <type_traits> #include <type_traits>
#include <string> #include <string>
#include "ki/pclass/Property.h" #include "ki/pclass/Property.h"
#include "ki/pclass/types/Type.h" #include "ki/pclass/Type.h"
#include "ki/pclass/PropertyClass.h" #include "ki/pclass/PropertyClass.h"
namespace ki namespace ki
@ -11,18 +11,22 @@ namespace ki
namespace pclass namespace pclass
{ {
/** /**
* TODO: Documentation * Base type for classes. Adds inheritance to Type.
*/ */
class IClassType : public Type class IClassType : public Type
{ {
public: public:
IClassType(const std::string &name, IClassType(const std::string &name,
const Type *base_class, const TypeSystem &type_system); const Type *base_class, const TypeSystem &type_system);
virtual ~IClassType() {} virtual ~IClassType() = default;
/**
* @param[in] type The ancestor type to check against.
* @returns True if this Type is a descendant of the given type. False otherwise.
*/
bool inherits(const Type &type) const; bool inherits(const Type &type) const;
void write_to(BitStream &stream, Value value) const override = 0; void write_to(BitStream &stream, Value &value) const override = 0;
Value read_from(BitStream &stream) const override = 0; Value read_from(BitStream &stream) const override = 0;
private: private:
@ -30,19 +34,27 @@ namespace pclass
}; };
/** /**
* TODO: Documentation * A user-defined structure.
* @tparam ClassT The compile-time user-defined class that the class represents.
*/ */
template <class ClassT> template <typename ClassT>
class ClassType : public IClassType class ClassType : public IClassType
{ {
// Ensure that ClassT inherits PropertyClass // Ensure that ClassT inherits PropertyClass
static_assert(std::is_base_of<PropertyClass, ClassT>::value, "ClassT must inherit PropertyClass!"); static_assert(std::is_base_of<PropertyClass, ClassT>::value, "ClassT must inherit PropertyClass!");
public: public:
// Do not allow copy construction or movement of types
ClassType(const ClassType<ClassT> &that) = delete;
ClassType &operator=(const ClassType<ClassT> &that) = delete;
ClassType(ClassType<ClassT> &&that) noexcept = delete;
ClassType &operator=(ClassType<ClassT> &&that) noexcept = delete;
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)
{} {}
~ClassType() = default;
std::unique_ptr<PropertyClass> instantiate() const override std::unique_ptr<PropertyClass> instantiate() const override
{ {
@ -52,7 +64,7 @@ namespace pclass
); );
} }
void write_to(BitStream &stream, Value value) const override void write_to(BitStream &stream, Value &value) const override
{ {
const auto &object = value.get<ClassT>(); const auto &object = value.get<ClassT>();
const auto &properties = object.get_properties(); const auto &properties = object.get_properties();

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "ki/pclass/types/EnumType.h" #include "ki/pclass/EnumType.h"
#include "ki/pclass/types/PrimitiveType.h" #include "ki/pclass/PrimitiveType.h"
namespace ki namespace ki
{ {

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <type_traits> #include <type_traits>
#include <unordered_map> #include <unordered_map>
#include "ki/pclass/types/Type.h" #include "ki/pclass/Type.h"
#include "ki/pclass/types/PrimitiveType.h" #include "ki/pclass/PrimitiveType.h"
namespace ki namespace ki
{ {
@ -32,6 +32,12 @@ namespace pclass
}; };
public: public:
// Do not allow copy construction or movement of types
EnumType(const EnumType &that) = delete;
EnumType &operator=(const EnumType &that) = delete;
EnumType(EnumType &&that) noexcept = delete;
EnumType &operator=(EnumType &&that) noexcept = delete;
EnumType(const std::string &name, const TypeSystem &type_system); EnumType(const std::string &name, const TypeSystem &type_system);
~EnumType(); ~EnumType();
@ -43,7 +49,7 @@ 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, Value value) const override; void write_to(BitStream &stream, Value &value) const override;
Value read_from(BitStream &stream) const override; Value read_from(BitStream &stream) const override;
private: private:
@ -66,10 +72,10 @@ namespace pclass
CppEnumType(const std::string &name, const TypeSystem &type_system) CppEnumType(const std::string &name, const TypeSystem &type_system)
: Type(name, type_system) : Type(name, type_system)
{ {
m_kind = kind::ENUM; m_kind = Kind::ENUM;
} }
void write_to(BitStream &stream, const Value value) const override void write_to(BitStream &stream, Value &value) const override
{ {
auto &enum_reference = value.get<EnumT>(); auto &enum_reference = value.get<EnumT>();
auto &underlying_reference = reinterpret_cast<const underlying_type &>(enum_reference); auto &underlying_reference = reinterpret_cast<const underlying_type &>(enum_reference);

View File

@ -13,10 +13,10 @@ namespace ki
/** /**
* A base class for type/property hash calculators. * A base class for type/property hash calculators.
*/ */
class HashCalculator class IHashCalculator
{ {
public: public:
virtual ~HashCalculator() {}; virtual ~IHashCalculator() {};
/** /**
* Calculate a type hash from the type's name. * Calculate a type hash from the type's name.
@ -35,7 +35,7 @@ namespace ki
* A hash calculator that uses the algorithms found and used in * A hash calculator that uses the algorithms found and used in
* Wizard101. * Wizard101.
*/ */
class WizardHashCalculator : public HashCalculator class WizardHashCalculator : public IHashCalculator
{ {
public: public:
hash_t calculate_type_hash(const std::string& name) const override; hash_t calculate_type_hash(const std::string& name) const override;

View File

@ -0,0 +1,189 @@
#pragma once
#include "ki/pclass/Type.h"
namespace ki
{
namespace pclass
{
namespace detail
{
/**
* Provides implementations to PrimitiveType<ValueT>::write_to,
* and PrimitiveType<ValueT>::read_from.
*/
template <typename ValueT, typename Enable = void>
struct primitive_type_helper
{
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 primitive_type_writer::write_to"
);
}
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");
}
};
/**
* Specialization of primitive_type_helper for integer types.
* This includes instantiations of ki::BitInteger<>.
*/
template <typename ValueT>
struct primitive_type_helper<
ValueT,
typename std::enable_if<is_integral<ValueT>::value>::type
>
{
static void write_to(BitStream &stream, const ValueT &value)
{
stream.write<ValueT>(value);
}
static Value read_from(BitStream &stream)
{
return Value::make_value<ValueT>(
stream.read<ValueT>()
);
}
};
/**
* Specialization of primitive_type_helper for floating point
* types.
*/
template <typename ValueT>
struct primitive_type_helper<
ValueT,
typename std::enable_if<std::is_floating_point<ValueT>::value>::type
>
{
static void write_to(BitStream &stream, const ValueT &value)
{
// Reinterpret the reference as a reference to an integer
const uint_type &v = *(
reinterpret_cast<const uint_type *>(&value)
);
stream.write<uint_type>(v, bitsizeof<ValueT>::value);
}
static Value read_from(BitStream &stream)
{
uint_type uint_value = stream.read<uint_type>(bitsizeof<ValueT>::value);
return Value::make_value<ValueT>(*reinterpret_cast<ValueT *>(&uint_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;
};
/**
* Specialization of primitive_type_helper for string types.
*/
template <
typename _Elem,
typename _Traits,
typename _Alloc
>
struct primitive_type_helper<std::basic_string<_Elem, _Traits, _Alloc>>
{
private:
using type = std::basic_string<_Elem, _Traits, _Alloc>;
public:
static void write_to(BitStream &stream, const type &value)
{
// Write the length as an unsigned short
stream.write<uint16_t>(value.length());
// Write each character as _Elem
for (auto it = value.begin(); it != value.end(); ++it)
stream.write<_Elem>(*it);
}
static Value read_from(BitStream &stream)
{
// Read the length and create a new string with the correct capacity
auto length = stream.read<uint16_t>();
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);
}
};
}
/**
* A basic data type that can be used to build more complex structures.
* @tparam ValueT The compile-time primitive type that the class represents.
*/
template <typename ValueT>
class PrimitiveType : public Type
{
public:
// Do not allow copy construction or movement of types
PrimitiveType(const PrimitiveType<ValueT> &that) = delete;
PrimitiveType &operator=(const PrimitiveType<ValueT> &that) = delete;
PrimitiveType(PrimitiveType<ValueT> &&that) noexcept = delete;
PrimitiveType &operator=(PrimitiveType<ValueT> &&that) noexcept = delete;
PrimitiveType(const std::string name, const TypeSystem &type_system)
: Type(name, type_system)
{
m_kind = Kind::PRIMITIVE;
}
~PrimitiveType() = default;
void write_to(BitStream &stream, Value &value) const override
{
try
{
Value deref_value = value.dereference<ValueT>();
detail::primitive_type_helper<ValueT>::write_to(
stream,
deref_value.get<ValueT>()
);
}
catch (runtime_error &e)
{
std::ostringstream oss;
oss << "Invalid call to Type::write_to -- " << e.what();
throw runtime_error(oss.str());
}
}
Value read_from(BitStream &stream) const override
{
try
{
return detail::primitive_type_helper<ValueT>::read_from(stream);
}
catch (runtime_error &e)
{
std::ostringstream oss;
oss << "Invalid call to Type::read_from -- " << e.what();
throw runtime_error(oss.str());
}
}
};
}
}

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <string> #include <string>
#include "ki/pclass/types/Type.h" #include "ki/pclass/Type.h"
#include "ki/pclass/HashCalculator.h" #include "ki/pclass/HashCalculator.h"
#include "ki/pclass/Value.h" #include "ki/pclass/Value.h"
#include "ki/util/BitStream.h" #include "ki/util/BitStream.h"
@ -12,7 +12,9 @@ namespace pclass
class PropertyClass; class PropertyClass;
/** /**
* TODO: Documentation * A base class for properties.
* Provides access to meta information such as name, and type
* of instance members, and a mechanism to get/set their values.
*/ */
class IProperty class IProperty
{ {
@ -26,27 +28,86 @@ namespace pclass
IProperty(PropertyClass &object, IProperty(PropertyClass &object,
const IProperty &that); const IProperty &that);
virtual ~IProperty() {} virtual ~IProperty() = default;
const PropertyClass &get_instance() const;
std::string get_name() const; std::string get_name() const;
hash_t get_name_hash() const; hash_t get_name_hash() const;
hash_t get_full_hash() const; hash_t get_full_hash() const;
const Type &get_type() const; const Type &get_type() const;
/**
* @returns A reference to the instance of PropertyClass that this property
* belongs to.
*/
const PropertyClass &get_instance() const;
/**
* @returns Whether or not the property's value type is a pointer.
*/
virtual bool is_pointer() const; virtual bool is_pointer() const;
/**
* @returns Whether or not the property's size is dynamic.
*/
virtual bool is_dynamic() const; virtual bool is_dynamic() const;
/**
* @returns Whether or not the property's value type is capable of
* holding more than one value.
*/
virtual bool is_array() const; virtual bool is_array() const;
/**
* @returns The number of values that the property is holding.
*/
virtual std::size_t get_element_count() const; virtual std::size_t get_element_count() const;
/**
* @param[in] size The new number of elements.
* @throws ki::runtime_error If the property is not dynamically sized.
*/
virtual void set_element_count(std::size_t size) = 0; virtual void set_element_count(std::size_t size) = 0;
/**
* @param[in] index The index of the element to retrieve the value from.
* @returns A reference to the value at the specified index, as a Value instance.
*/
virtual Value get_value(std::size_t index = 0) const = 0; virtual Value get_value(std::size_t index = 0) const = 0;
/**
* @param[in] value The new value.
* @param[in] index The index of the element to modify.
*/
virtual void set_value(Value value, std::size_t index = 0) = 0; virtual void set_value(Value value, std::size_t index = 0) = 0;
/**
* @param[in] index The index of the object element to retrieve.
* @returns A pointer to the instance of PropertyClass at the specified index.
* @throws ki::runtime_error If the property's value type is not an object,
* as in, it does not inherit PropertyClass.
*/
virtual const PropertyClass *get_object(std::size_t index = 0) const = 0; virtual const PropertyClass *get_object(std::size_t index = 0) const = 0;
/**
* @param[in] object A pointer to the new object value.
* @param[in] index The index of the object element to modify.
* @throws ki::runtime_error If the property's value type is not an object,
* as in, it does not inherit PropertyClass.
*/
virtual void set_object(std::unique_ptr<PropertyClass> &object, std::size_t index = 0) = 0; virtual void set_object(std::unique_ptr<PropertyClass> &object, std::size_t index = 0) = 0;
/**
* Write the value of this property's specified element to a BitStream.
* @param[in] stream The stream to write to.
* @param[in] index The index of the element to retrieve the value from
*/
virtual void write_value_to(BitStream &stream, std::size_t index = 0) const; virtual void write_value_to(BitStream &stream, std::size_t index = 0) const;
/**
* Read a value from a BitStream into the specified element of this property.
* @param[in] stream The stream to read from.
* @param[in] index The index of the element to read a value into.
*/
virtual void read_value_from(BitStream &stream, std::size_t index = 0); virtual void read_value_from(BitStream &stream, std::size_t index = 0);
private: private:

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include "ki/pclass/types/Type.h" #include "ki/pclass/Type.h"
#include "ki/pclass/PropertyList.h" #include "ki/pclass/PropertyList.h"
#define _KI_TYPE ki::pclass::Type #define _KI_TYPE ki::pclass::Type
@ -52,11 +52,10 @@ namespace ki
{ {
namespace pclass namespace pclass
{ {
template <typename ValueT>
class ClassType;
/** /**
* TODO: Documentation * A base class for all objects defined as ClassTypes by a
* TypeSystem instance. Provides a way to access a list of
* instance properties, as well as their values, at runtime.
*/ */
class PropertyClass class PropertyClass
{ {
@ -64,7 +63,7 @@ namespace pclass
public: public:
explicit PropertyClass(const Type &type, const TypeSystem &type_system); explicit PropertyClass(const Type &type, const TypeSystem &type_system);
virtual ~PropertyClass() {} virtual ~PropertyClass() = default;
PropertyClass(const PropertyClass &that); PropertyClass(const PropertyClass &that);
PropertyClass &operator=(const PropertyClass &that); PropertyClass &operator=(const PropertyClass &that);
@ -75,12 +74,11 @@ namespace pclass
virtual void on_created() const {} virtual void on_created() const {}
protected:
void add_property(IProperty &prop);
private: private:
const Type *m_type; const Type *m_type;
PropertyList m_properties; PropertyList m_properties;
void add_property(IProperty &prop);
}; };
} }
} }

View File

@ -11,16 +11,13 @@ namespace pclass
class IProperty; class IProperty;
/** /**
* TODO: Documentation * Manages property lookup on a PropertyClass instance.
*/ */
class PropertyList class PropertyList
{ {
friend PropertyClass; friend PropertyClass;
public: public:
/**
* TODO: Documentation
*/
class iterator class iterator
{ {
friend PropertyList; friend PropertyList;
@ -40,9 +37,6 @@ namespace pclass
explicit iterator(PropertyList &list, int index = 0); explicit iterator(PropertyList &list, int index = 0);
}; };
/**
* TODO: Documentation
*/
class const_iterator class const_iterator
{ {
friend PropertyList; friend PropertyList;
@ -62,18 +56,63 @@ namespace pclass
explicit const_iterator(const PropertyList &list, int index = 0); explicit const_iterator(const PropertyList &list, int index = 0);
}; };
/**
* @returns The number of properties in this list.
*/
std::size_t get_property_count() const; std::size_t get_property_count() const;
/**
* @param[in] name The name of the property to search for.
* @returns Whether or not a property with the given name exists.
*/
bool has_property(const std::string &name) const; bool has_property(const std::string &name) const;
/**
* @param[in] hash The full hash of the property to search for.
* @returns Whether or not a property with the given hash exists.
*/
bool has_property(hash_t hash) const; bool has_property(hash_t hash) const;
/**
* @param[in] index The index of the property to return.
* @returns The property at the specified index.
* @throw ki::runtime_error If the index is out of bounds.
*/
IProperty &get_property(int index); IProperty &get_property(int index);
/**
* @param[in] index The index of the property to return.
* @returns The property at the specified index.
* @throw ki::runtime_error If the specified index is out of bounds.
*/
const IProperty &get_property(int index) const; const IProperty &get_property(int index) const;
/**
* @param[in] name The name of the property to search for.
* @returns The property found with the specified name.
* @throw ki::runtime_error If no property exists with the specified name.
*/
IProperty &get_property(const std::string &name); IProperty &get_property(const std::string &name);
/**
* @param[in] name The name of the property to search for.
* @returns The property found with the specified name.
* @throw ki::runtime_error If no property exists with the specified name.
*/
const IProperty &get_property(const std::string &name) const; const IProperty &get_property(const std::string &name) const;
/**
* @param[in] hash The full hash of the property to search for.
* @returns The property found with the specified hash.
* @throw ki::runtime_error If no property exists with the specified hash.
*/
IProperty &get_property(hash_t hash); IProperty &get_property(hash_t hash);
/**
* @param[in] hash The full hash of the property to search for.
* @returns The property found with the specified hash.
* @throw ki::runtime_error If no property exists with the specified hash.
*/
const IProperty &get_property(hash_t hash) const; const IProperty &get_property(hash_t hash) const;
iterator begin(); iterator begin();

View File

@ -271,14 +271,14 @@ namespace pclass
> >
{ {
static const PropertyClass *get_object( static const PropertyClass *get_object(
const StaticProperty<ValueT> &prop, const int index) const StaticProperty<ValueT[N]> &prop, const int index)
{ {
// ValueT does derive from PropertyClass, and we have an instance of ValueT, // ValueT does derive from PropertyClass, and we have an instance of ValueT,
// so we can cast down to a PropertyClass pointer. // so we can cast down to a PropertyClass pointer.
return dynamic_cast<const PropertyClass *>(&prop.m_value[index]); return dynamic_cast<const PropertyClass *>(&prop.m_value[index]);
} }
static void set_object(StaticProperty<ValueT> &prop, static void set_object(StaticProperty<ValueT[N]> &prop,
std::unique_ptr<PropertyClass> &object, const int index) std::unique_ptr<PropertyClass> &object, const int index)
{ {
// Ensure that object is not nullptr // Ensure that object is not nullptr
@ -308,14 +308,14 @@ namespace pclass
> >
{ {
static const PropertyClass *get_object( static const PropertyClass *get_object(
const StaticProperty<ValueT> &prop, const int index) const StaticProperty<ValueT *[N]> &prop, const int index)
{ {
// ValueT does derive from PropertyClass, and we have an instance of ValueT, // ValueT does derive from PropertyClass, and we have an instance of ValueT,
// so we can cast down to a PropertyClass pointer. // so we can cast down to a PropertyClass pointer.
return dynamic_cast<const PropertyClass *>(prop.m_value[index]); return dynamic_cast<const PropertyClass *>(prop.m_value[index]);
} }
static void set_object(StaticProperty<ValueT> &prop, static void set_object(StaticProperty<ValueT *[N]> &prop,
std::unique_ptr<PropertyClass> &object, const int index) std::unique_ptr<PropertyClass> &object, const int index)
{ {
// Ensure that object inherits the type of the property // Ensure that object inherits the type of the property
@ -397,12 +397,12 @@ namespace pclass
template <typename ValueT, int N> template <typename ValueT, int N>
struct static_value_helper<ValueT *[N]> struct static_value_helper<ValueT *[N]>
{ {
static Value get_value(const StaticProperty<ValueT[N]> &prop, const int index) static Value get_value(const StaticProperty<ValueT *[N]> &prop, const int index)
{ {
return Value::make_reference<ValueT>(*prop.m_value[index]); return Value::make_reference<ValueT>(*prop.m_value[index]);
} }
static void set_value(StaticProperty<ValueT[N]> &prop, Value value, const int index) static void set_value(StaticProperty<ValueT *[N]> &prop, Value value, const int index)
{ {
Value casted_value = value.as<ValueT>(); Value casted_value = value.as<ValueT>();
prop.m_value[index] = casted_value.release<ValueT>(); prop.m_value[index] = casted_value.release<ValueT>();

View File

@ -19,12 +19,21 @@ namespace pclass
class Type class Type
{ {
public: public:
enum class kind // Do not allow copy construction or movement of types
Type(const Type &that) = delete;
Type &operator=(const Type &that) = delete;
Type(Type &&that) noexcept = delete;
Type &operator=(Type &&that) noexcept = delete;
/**
* An enum of Type kinds.
*/
enum class Kind
{ {
NONE, NONE,
/** /**
* A Type that contain pure, simple values. * A Type that contains pure, simple values.
*/ */
PRIMITIVE, PRIMITIVE,
@ -40,19 +49,39 @@ namespace pclass
}; };
Type(const std::string &name, const TypeSystem &type_system); Type(const std::string &name, const TypeSystem &type_system);
virtual ~Type() {} virtual ~Type() = default;
std::string get_name() const; const std::string &get_name() const;
hash_t get_hash() const; hash_t get_hash() const;
kind get_kind() const; Kind get_kind() const;
/**
* The TypeSystem used to define this Type instance.
*/
const TypeSystem &get_type_system() const; const TypeSystem &get_type_system() const;
/**
* Create an instance of the type being represented.
* @returns A pointer to a new PropertyClass instance.
*/
virtual std::unique_ptr<PropertyClass> instantiate() const; virtual std::unique_ptr<PropertyClass> instantiate() const;
virtual void write_to(BitStream &stream, Value value) const;
/**
* Write a value of this type to a BitStream.
* @param[in] stream The stream to write to.
* @param[in] value The value to write to the stream.
*/
virtual void write_to(BitStream &stream, Value &value) const;
/**
* Read a value of this type from a BitStream.
* @param stream[in] The stream to read from.
* @returns The value read from the stream.
*/
virtual Value read_from(BitStream &stream) const; virtual Value read_from(BitStream &stream) const;
protected: protected:
kind m_kind; Kind m_kind;
private: private:
std::string m_name; std::string m_name;

View File

@ -4,31 +4,62 @@
#include <json.hpp> #include <json.hpp>
#include "ki/pclass/HashCalculator.h" #include "ki/pclass/HashCalculator.h"
#include "ki/pclass/Casters.h" #include "ki/pclass/Casters.h"
#include "ki/pclass/types/Type.h" #include "ki/pclass/Type.h"
#include "ki/pclass/types/PrimitiveType.h" #include "ki/pclass/PrimitiveType.h"
#include "ki/pclass/types/ClassType.h" #include "ki/pclass/ClassType.h"
#include "ki/pclass/types/EnumType.h" #include "ki/pclass/EnumType.h"
#include "ki/util/unique.h"
namespace ki namespace ki
{ {
namespace pclass namespace pclass
{ {
/** /**
* TODO: Documentation * A class that provides run-time type definition and lookup.
*/ */
class TypeSystem class TypeSystem
{ {
public: public:
explicit TypeSystem(std::unique_ptr<HashCalculator> &hash_calculator); explicit TypeSystem(std::unique_ptr<IHashCalculator> &hash_calculator);
const HashCalculator &get_hash_calculator() const; /**
* @returns The IHashCalculator instance this TypeSystem uses to calculate
* type and property hashes.
*/
const IHashCalculator &get_hash_calculator() const;
/**
* @param[in] name The name of the type to search for.
* @returns Whether a type has been defined with the specified name.
*/
bool has_type(const std::string &name) const; bool has_type(const std::string &name) const;
/**
* @param[in] hash The hash of the type to search for.
* @returns Whether a type exists with the specified hash.
*/
bool has_type(hash_t hash) const; bool has_type(hash_t hash) const;
/**
* @param[in] name The name of the type to search for.
* @returns The Type instance defined with the specified name.
* @throws ki::runtime_error If a Type with the specified name could not be found.
*/
const Type &get_type(const std::string &name) const; const Type &get_type(const std::string &name) const;
/**
* @param[in] hash The hash of the type to search for.
* @returns The Type instance with the specified type hash.
* @throws ki::runtime_error If a Type with the specified hash could not be found.
*/
const Type &get_type(hash_t hash) const; const Type &get_type(hash_t hash) const;
/**
* Define a new primitive type.
* @tparam ValueT the compile-time primitive type to represent.
* @param[in] name The name of the primitive to define.
* @returns A reference to the newly defined PrimitiveType<ValueT>.
*/
template <typename ValueT> template <typename ValueT>
PrimitiveType<ValueT> &define_primitive(const std::string &name) PrimitiveType<ValueT> &define_primitive(const std::string &name)
{ {
@ -42,21 +73,45 @@ namespace pclass
return *type; return *type;
} }
/**
* Define a new class type.
* @tparam ClassT The compile-time class type to represent. Must inherit PropertyClass.
* @param[in] name The name of the class to define.
* @returns A reference to the newly defined ClassType<ClassT>.
*/
template <class ClassT> template <class ClassT>
ClassType<ClassT> &define_class(const std::string &name) ClassType<ClassT> &define_class(const std::string &name)
{ {
return define_class<ClassT>(name, nullptr); return define_class<ClassT>(name, nullptr);
} }
template <class ClassT> /**
* Define a new derived class type.
* @tparam ClassT The compile-time class type to represent.
* @param[in] name The name of the class to define.
* @param[in] base_class A reference to the Type instance of the base class. Must be an IClassType.
* @returns A reference to the newly defined ClassType<ClassT>.
*/
template <typename ClassT>
ClassType<ClassT> &define_class( ClassType<ClassT> &define_class(
const std::string &name, const Type &base_class) const std::string &name, const Type &base_class)
{ {
return define_class<ClassT>(name, &base_class); return define_class<ClassT>(name, &base_class);
} }
/**
* Define a new dynamic enum type.
* @param[in] name The name of the enum to define.
* @returns A reference to the newly defined EnumType.
*/
EnumType &define_enum(const std::string &name); EnumType &define_enum(const std::string &name);
/**
* Define a new static enum type.
* @tparam EnumT the compile-time enum type to represent.
* @param[in] name The name of the enum to define.
* @returns A reference to the newly defined CppEnumType<EnumT>.
*/
template <typename EnumT> template <typename EnumT>
CppEnumType<EnumT> &define_enum(const std::string &name) CppEnumType<EnumT> &define_enum(const std::string &name)
{ {
@ -70,6 +125,11 @@ namespace pclass
return *type; return *type;
} }
/**
* Create a new instance of a PropertyClass-derived class.
* @tparam ClassT The expected compile-time class.
* @param[in] name The name of the class type to instantiate.
*/
template <typename ClassT> template <typename ClassT>
std::unique_ptr<ClassT> instantiate(const std::string &name) const std::unique_ptr<ClassT> instantiate(const std::string &name) const
{ {
@ -87,7 +147,7 @@ namespace pclass
std::vector<std::unique_ptr<Type>> m_types; std::vector<std::unique_ptr<Type>> m_types;
std::unordered_map<std::string, Type *> m_type_name_lookup; std::unordered_map<std::string, Type *> m_type_name_lookup;
std::unordered_map<hash_t, Type *> m_type_hash_lookup; std::unordered_map<hash_t, Type *> m_type_hash_lookup;
std::unique_ptr<HashCalculator> m_hash_calculator; std::unique_ptr<IHashCalculator> m_hash_calculator;
template <class ClassT> template <class ClassT>
ClassType<ClassT> &define_class( ClassType<ClassT> &define_class(

View File

@ -26,7 +26,7 @@ namespace pclass
*/ */
struct value_caster_base struct value_caster_base
{ {
virtual ~value_caster_base() {} virtual ~value_caster_base() = default;
/** /**
* @param[in] value The value being casted. * @param[in] value The value being casted.
@ -51,7 +51,7 @@ namespace pclass
}; };
/** /**
* TODO: Documentation * Provides casting implementations to ValueCaster instances.
*/ */
template <typename SrcT, typename DestT, typename Enable> template <typename SrcT, typename DestT, typename Enable>
struct value_caster : value_caster_impl<SrcT, DestT> struct value_caster : value_caster_impl<SrcT, DestT>
@ -64,15 +64,15 @@ namespace pclass
}; };
/** /**
* A base class for Value deallocators. * A base class for Value de-allocators.
* Provides a common interface for deallocate() * Provides a common interface for deallocate()
*/ */
struct value_deallocator_base struct value_deallocator_base
{ {
virtual ~value_deallocator_base() {} virtual ~value_deallocator_base() = default;
/** /**
* Deallocate a Value-owned pointer. * De-allocate a Value-owned pointer.
* @param[in] ptr The pointer to deallocate. * @param[in] ptr The pointer to deallocate.
*/ */
virtual void deallocate(void *ptr) const = 0; virtual void deallocate(void *ptr) const = 0;
@ -84,7 +84,9 @@ namespace pclass
}; };
/** /**
* TODO: Documentation * Provides a deallocate() implementation to ValueDeallocator
* based on the type being de-allocated.
* @tparam T The type being de-allocated.
*/ */
template <typename T> template <typename T>
struct value_deallocator : value_deallocator_base struct value_deallocator : value_deallocator_base
@ -102,7 +104,8 @@ namespace pclass
}; };
/** /**
* TODO: Documentation * Provides Value with a way to safely delete the void pointer
* that has had it's type information "erased".
*/ */
class ValueDeallocator class ValueDeallocator
{ {
@ -110,9 +113,9 @@ namespace pclass
friend Value; friend Value;
public: public:
ValueDeallocator(ValueDeallocator &that); ValueDeallocator(const ValueDeallocator &that);
ValueDeallocator(ValueDeallocator &&that) noexcept; ValueDeallocator(ValueDeallocator &&that) noexcept;
ValueDeallocator &operator=(ValueDeallocator &that); ValueDeallocator &operator=(const ValueDeallocator &that);
ValueDeallocator &operator=(ValueDeallocator &&that) noexcept; ValueDeallocator &operator=(ValueDeallocator &&that) noexcept;
~ValueDeallocator(); ~ValueDeallocator();
@ -137,8 +140,8 @@ namespace pclass
} }
/** /**
* TODO: Documentation * Provides a way to perform casting on Value instances.
*/ */
class ValueCaster class ValueCaster
{ {
// Allow Value to call the default constructor and get<SrcT>() // Allow Value to call the default constructor and get<SrcT>()
@ -229,9 +232,9 @@ namespace pclass
class Value class Value
{ {
public: public:
Value(Value &that); Value(const Value &that);
Value(Value &&that) noexcept; Value(Value &&that) noexcept;
Value &operator=(Value &that); Value &operator=(const Value &that);
Value &operator=(Value &&that) noexcept; Value &operator=(Value &&that) noexcept;
~Value(); ~Value();
@ -351,7 +354,7 @@ namespace pclass
/** /**
* @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.
* @returns A new Value instance that refers to a value it doesn't own. * @returns A new Value instance that refers to a value it does not own.
*/ */
template <typename T> template <typename T>
static Value make_reference(T &value) static Value make_reference(T &value)

View File

@ -112,14 +112,14 @@ namespace pclass
using default_vector_object_helper<ValueT>::copy; using default_vector_object_helper<ValueT>::copy;
static const PropertyClass *get_object( static const PropertyClass *get_object(
const VectorProperty<ValueT *> &prop, const int index) const VectorProperty<ValueT> &prop, const int index)
{ {
// ValueT does derive from PropertyClass, and we have an instance of ValueT, // ValueT does derive from PropertyClass, and we have an instance of ValueT,
// so we can cast down to a PropertyClass pointer. // so we can cast down to a PropertyClass pointer.
return dynamic_cast<const PropertyClass *>(&prop.at(index)); return dynamic_cast<const PropertyClass *>(&prop.at(index));
} }
static void set_object(VectorProperty<ValueT *> &prop, static void set_object(VectorProperty<ValueT> &prop,
std::unique_ptr<PropertyClass> &object, const int index) std::unique_ptr<PropertyClass> &object, const int index)
{ {
// Ensure that object is not nullptr // Ensure that object is not nullptr

View File

@ -1,41 +0,0 @@
#pragma once
#include <type_traits>
#include "ki/util/BitTypes.h"
namespace ki
{
namespace pclass
{
namespace detail
{
template <typename ValueT>
struct primitive_type_helper<
ValueT,
typename std::enable_if<std::is_floating_point<ValueT>::value>::type
>
{
static void write_to(BitStream &stream, const ValueT &value)
{
// Reinterpret the reference as a reference to an integer
const uint_type &v = *(
reinterpret_cast<const uint_type *>(&value)
);
stream.write<uint_type>(v, bitsizeof<ValueT>::value);
}
static Value read_from(BitStream &stream)
{
uint_type uint_value = stream.read<uint_type>(bitsizeof<ValueT>::value);
return Value::make_value<ValueT>(*reinterpret_cast<ValueT *>(&uint_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;
};
}
}
}

View File

@ -1,31 +0,0 @@
#pragma once
#include <type_traits>
#include "ki/util/BitTypes.h"
namespace ki
{
namespace pclass
{
namespace detail
{
template <typename ValueT>
struct primitive_type_helper<
ValueT,
typename std::enable_if<is_integral<ValueT>::value>::type
>
{
static void write_to(BitStream &stream, const ValueT &value)
{
stream.write<ValueT>(value);
}
static Value read_from(BitStream &stream)
{
return Value::make_value<ValueT>(
stream.read<ValueT>()
);
}
};
}
}
}

View File

@ -1,97 +0,0 @@
#pragma once
#include "ki/pclass/types/Type.h"
namespace ki
{
namespace pclass
{
namespace detail
{
/**
* TODO: Documentation
*/
template <typename ValueT, typename Enable = void>
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 primitive_type_writer::write_to"
);
}
/**
* TODO: Documentation
*/
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
*/
template <typename ValueT>
class PrimitiveType : public Type
{
public:
PrimitiveType(const std::string name, const TypeSystem &type_system)
: Type(name, type_system)
{
m_kind = kind::PRIMITIVE;
}
void write_to(BitStream &stream, const Value value) const override
{
try
{
// 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)
{
std::ostringstream oss;
oss << "Invalid call to Type::write_to -- " << e.what();
throw runtime_error(oss.str());
}
}
Value read_from(BitStream &stream) const override
{
try
{
return detail::primitive_type_helper<ValueT>::read_from(stream);
}
catch (runtime_error &e)
{
std::ostringstream oss;
oss << "Invalid call to Type::read_from -- " << e.what();
throw runtime_error(oss.str());
}
}
};
}
}
// Include all template specializations
#include "ki/pclass/types/IntegralPrimitiveType.h"
#include "ki/pclass/types/FloatingPointPrimitiveType.h"
#include "ki/pclass/types/StringPrimitiveType.h"

View File

@ -1,51 +0,0 @@
#pragma once
#include <cstdint>
#include <string>
namespace ki
{
namespace pclass
{
namespace detail
{
/**
* primitive_type_helper specialization for string types.
*/
template <
typename _Elem,
typename _Traits,
typename _Alloc
>
struct primitive_type_helper<std::basic_string<_Elem, _Traits, _Alloc>>
{
private:
using type = std::basic_string<_Elem, _Traits, _Alloc>;
public:
static void write_to(BitStream &stream, const type &value)
{
// Write the length as an unsigned short
stream.write<uint16_t>(value.length());
// Write each character as _Elem
for (auto it = value.begin(); it != value.end(); ++it)
stream.write<_Elem>(*it);
}
static Value read_from(BitStream &stream)
{
// Read the length and create a new string with the correct capacity
auto length = stream.read<uint16_t>();
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);
}
};
}
}
}

View File

@ -1,4 +1,4 @@
#include "ki/pclass/types/ClassType.h" #include "ki/pclass/ClassType.h"
#include "ki/pclass/TypeSystem.h" #include "ki/pclass/TypeSystem.h"
#include "ki/util/exception.h" #include "ki/util/exception.h"
@ -7,16 +7,16 @@ namespace ki
namespace pclass namespace pclass
{ {
IClassType::IClassType(const std::string& name, IClassType::IClassType(const std::string& name,
const Type* base_class, const TypeSystem& type_system) const Type *base_class, const TypeSystem& type_system)
: Type(name, type_system) : Type(name, type_system)
{ {
m_kind = kind::CLASS; m_kind = Kind::CLASS;
// Have we been given a base class? // Have we been given a base class?
if (base_class) if (base_class)
{ {
// Make sure the base class is a class type // Make sure the base class is a class type
if (base_class->get_kind() != kind::CLASS) if (base_class->get_kind() != Kind::CLASS)
throw runtime_error("base_class must be a class type!"); throw runtime_error("base_class must be a class type!");
// Cast the base class up to a IClassType pointer // Cast the base class up to a IClassType pointer

View File

@ -7,7 +7,7 @@ namespace pclass
Enum::Enum(const Type &type, const enum_value_t value) Enum::Enum(const Type &type, const enum_value_t value)
{ {
// Make sure the type we've been given is an enum type // Make sure the type we've been given is an enum type
if (type.get_kind() != Type::kind::ENUM) if (type.get_kind() != Type::Kind::ENUM)
throw runtime_error("Enum constructor was supplied with a non-enum type."); throw runtime_error("Enum constructor was supplied with a non-enum type.");
m_type = &dynamic_cast<const EnumType &>(type); m_type = &dynamic_cast<const EnumType &>(type);
@ -17,14 +17,14 @@ namespace pclass
Enum::Enum(const Type &type, const std::string &element_name) Enum::Enum(const Type &type, const std::string &element_name)
{ {
// Make sure the type we've been given is an enum type // Make sure the type we've been given is an enum type
if (type.get_kind() != Type::kind::ENUM) if (type.get_kind() != Type::Kind::ENUM)
throw runtime_error("Enum constructor was supplied with a non-enum type."); throw runtime_error("Enum constructor was supplied with a non-enum type.");
m_type = &dynamic_cast<const EnumType &>(type); m_type = &dynamic_cast<const EnumType &>(type);
set_value(element_name); set_value(element_name);
} }
Enum& Enum::operator=(const Enum& that) Enum &Enum::operator=(const Enum& that)
{ {
// Are the types the same? // Are the types the same?
if (&get_type() != &that.get_type()) if (&get_type() != &that.get_type())

View File

@ -1,4 +1,4 @@
#include "ki/pclass/types/EnumType.h" #include "ki/pclass/EnumType.h"
#include "ki/util/exception.h" #include "ki/util/exception.h"
#include <sstream> #include <sstream>
#include "ki/pclass/Enum.h" #include "ki/pclass/Enum.h"
@ -7,7 +7,6 @@ namespace ki
{ {
namespace pclass namespace pclass
{ {
EnumType::Element::Element(const std::string &name, EnumType::Element::Element(const std::string &name,
const enum_value_t value) const enum_value_t value)
{ {
@ -29,7 +28,7 @@ namespace pclass
const TypeSystem &type_system) const TypeSystem &type_system)
: Type(name, type_system) : Type(name, type_system)
{ {
m_kind = kind::ENUM; m_kind = Kind::ENUM;
} }
EnumType::~EnumType() EnumType::~EnumType()
@ -110,7 +109,7 @@ namespace pclass
return *this; return *this;
} }
void EnumType::write_to(BitStream &stream, const Value value) const void EnumType::write_to(BitStream &stream, Value &value) const
{ {
// Get an Enum reference and use it to write to the stream // Get an Enum reference and use it to write to the stream
value.get<Enum>().write_to(stream); value.get<Enum>().write_to(stream);

View File

@ -85,7 +85,8 @@ namespace pclass
{ {
if (index < 0 || index >= get_element_count()) if (index < 0 || index >= get_element_count())
throw runtime_error("Index out of bounds."); throw runtime_error("Index out of bounds.");
get_type().write_to(stream, get_value(index)); auto ref_value = get_value(index);
get_type().write_to(stream, ref_value);
} }
void IProperty::read_value_from(BitStream& stream, const std::size_t index) void IProperty::read_value_from(BitStream& stream, const std::size_t index)

View File

@ -1,8 +1,7 @@
#include "ki/pclass/types/Type.h" #include "ki/pclass/Type.h"
#include "ki/pclass/types/ClassType.h" #include "ki/pclass/ClassType.h"
#include "ki/pclass/TypeSystem.h" #include "ki/pclass/TypeSystem.h"
#include "ki/util/exception.h" #include "ki/util/exception.h"
#include <stdexcept>
#include <sstream> #include <sstream>
namespace ki namespace ki
@ -16,10 +15,10 @@ namespace pclass
m_hash = m_type_system m_hash = m_type_system
.get_hash_calculator() .get_hash_calculator()
.calculate_type_hash(name); .calculate_type_hash(name);
m_kind = kind::NONE; m_kind = Kind::NONE;
} }
std::string Type::get_name() const const std::string &Type::get_name() const
{ {
return m_name; return m_name;
} }
@ -29,7 +28,7 @@ namespace pclass
return m_hash; return m_hash;
} }
Type::kind Type::get_kind() const Type::Kind Type::get_kind() const
{ {
return m_kind; return m_kind;
} }
@ -39,7 +38,7 @@ namespace pclass
return m_type_system; return m_type_system;
} }
void Type::write_to(BitStream &stream, 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.";
@ -68,7 +67,7 @@ namespace pclass
{ {
// Do the types match via inheritance? // Do the types match via inheritance?
if (allow_inheritance && if (allow_inheritance &&
expected.get_kind() == Type::kind::CLASS) expected.get_kind() == Type::Kind::CLASS)
{ {
const auto &actual_class = dynamic_cast<const IClassType &>(actual); const auto &actual_class = dynamic_cast<const IClassType &>(actual);
if (actual_class.inherits(expected)) if (actual_class.inherits(expected))

View File

@ -36,7 +36,7 @@ namespace pclass
template <> template <>
void define_bit_integer_primitive<0>(TypeSystem &type_system) {} void define_bit_integer_primitive<0>(TypeSystem &type_system) {}
TypeSystem::TypeSystem(std::unique_ptr<HashCalculator> &hash_calculator) TypeSystem::TypeSystem(std::unique_ptr<IHashCalculator> &hash_calculator)
{ {
m_hash_calculator = std::move(hash_calculator); m_hash_calculator = std::move(hash_calculator);
@ -48,6 +48,7 @@ namespace pclass
define_primitive<int8_t>("int8_t"); define_primitive<int8_t>("int8_t");
define_primitive<uint8_t>("uint8_t"); define_primitive<uint8_t>("uint8_t");
DEFINE_INTEGER_PRIMTIIVE(int16_t, uint16_t, "short"); DEFINE_INTEGER_PRIMTIIVE(int16_t, uint16_t, "short");
define_primitive<char16_t>("wchar_t");
DEFINE_INTEGER_PRIMTIIVE(int16_t, uint16_t, "__int16"); DEFINE_INTEGER_PRIMTIIVE(int16_t, uint16_t, "__int16");
define_primitive<int16_t>("int16_t"); define_primitive<int16_t>("int16_t");
define_primitive<uint16_t>("uint16_t"); define_primitive<uint16_t>("uint16_t");
@ -59,7 +60,6 @@ namespace pclass
DEFINE_INTEGER_PRIMTIIVE(int64_t, uint64_t, "__int64"); DEFINE_INTEGER_PRIMTIIVE(int64_t, uint64_t, "__int64");
define_primitive<int64_t>("int64_t"); define_primitive<int64_t>("int64_t");
define_primitive<uint64_t>("uint64_t"); define_primitive<uint64_t>("uint64_t");
define_primitive<uint64_t>("gid");
// Define bit-integer types // Define bit-integer types
define_bit_integer_primitive(*this); define_bit_integer_primitive(*this);
@ -78,11 +78,8 @@ namespace pclass
define_class<PropertyClass>("class PropertyClass"); define_class<PropertyClass>("class PropertyClass");
} }
const HashCalculator &TypeSystem::get_hash_calculator() const const IHashCalculator &TypeSystem::get_hash_calculator() const
{ {
// Make sure the hash calculator isn't null
if (m_hash_calculator == nullptr)
throw runtime_error("TypeSystem::get_hash_calculator() called but hash calculator is null.");
return *m_hash_calculator; return *m_hash_calculator;
} }
@ -143,7 +140,7 @@ namespace pclass
} }
// Does a type with this hash already exist? // Does a type with this hash already exist?
if (m_type_name_lookup.find(type->get_name()) != m_type_name_lookup.end()) if (m_type_hash_lookup.find(type->get_hash()) != m_type_hash_lookup.end())
{ {
// Throw an error // Throw an error
auto &other_type = get_type(type->get_hash()); auto &other_type = get_type(type->get_hash());

View File

@ -9,7 +9,7 @@ namespace pclass
namespace detail namespace detail
{ {
Value value_caster_base::cast(const Value &v) const Value value_caster_base::cast(const Value &value) const
{ {
throw runtime_error("Unimplemented cast."); throw runtime_error("Unimplemented cast.");
} }
@ -24,7 +24,7 @@ namespace pclass
m_deallocator = deallocator; m_deallocator = deallocator;
} }
ValueDeallocator::ValueDeallocator(ValueDeallocator &that) ValueDeallocator::ValueDeallocator(const ValueDeallocator &that)
{ {
m_deallocator = that.m_deallocator->copy(); m_deallocator = that.m_deallocator->copy();
} }
@ -35,7 +35,7 @@ namespace pclass
that.m_deallocator = nullptr; that.m_deallocator = nullptr;
} }
ValueDeallocator &ValueDeallocator::operator=(ValueDeallocator &that) ValueDeallocator &ValueDeallocator::operator=(const ValueDeallocator &that)
{ {
m_deallocator = that.m_deallocator->copy(); m_deallocator = that.m_deallocator->copy();
return *this; return *this;
@ -87,7 +87,7 @@ namespace pclass
m_deallocator = detail::ValueDeallocator(); m_deallocator = detail::ValueDeallocator();
} }
Value::Value(Value& that) Value::Value(const Value &that)
{ {
m_value_ptr = that.m_value_ptr; m_value_ptr = that.m_value_ptr;
m_ptr_is_owned = false; m_ptr_is_owned = false;
@ -108,7 +108,7 @@ namespace pclass
m_deallocator = std::move(that.m_deallocator); m_deallocator = std::move(that.m_deallocator);
} }
Value &Value::operator=(Value &that) Value &Value::operator=(const Value &that)
{ {
m_value_ptr = that.m_value_ptr; m_value_ptr = that.m_value_ptr;
m_ptr_is_owned = false; m_ptr_is_owned = false;

View File

@ -120,7 +120,7 @@ namespace serialization
if (object) if (object)
stream.write<uint32_t>(object->get_type().get_hash()); stream.write<uint32_t>(object->get_type().get_hash());
else else
stream.write<uint32_t>(NULL); stream.write<uint32_t>(0);
return object != nullptr; return object != nullptr;
} }
@ -183,7 +183,7 @@ namespace serialization
for (auto i = 0; i < prop.get_element_count(); ++i) for (auto i = 0; i < prop.get_element_count(); ++i)
{ {
if (prop.is_pointer() if (prop.is_pointer()
&& prop.get_type().get_kind() == pclass::Type::kind::CLASS) && prop.get_type().get_kind() == pclass::Type::Kind::CLASS)
{ {
// Write the value as a nested object // Write the value as a nested object
save_object(prop.get_object(i), stream); save_object(prop.get_object(i), stream);
@ -358,7 +358,7 @@ namespace serialization
for (auto i = 0; i < prop.get_element_count(); ++i) for (auto i = 0; i < prop.get_element_count(); ++i)
{ {
if (prop.is_pointer() && if (prop.is_pointer() &&
prop.get_type().get_kind() == pclass::Type::kind::CLASS) prop.get_type().get_kind() == pclass::Type::Kind::CLASS)
{ {
// Read the object as a nested object // Read the object as a nested object
std::unique_ptr<pclass::PropertyClass> object = nullptr; std::unique_ptr<pclass::PropertyClass> object = nullptr;

View File

@ -27,7 +27,7 @@ namespace serialization
{ {
// Add the object's meta information // Add the object's meta information
j["_pclass_meta"] = { j["_pclass_meta"] = {
{ "type_hash", object ? object->get_type().get_hash() : NULL } { "type_hash", object ? object->get_type().get_hash() : 0 }
}; };
return object != nullptr; return object != nullptr;
} }
@ -38,7 +38,6 @@ namespace serialization
if (!presave_object(j, object)) if (!presave_object(j, object))
return j; return j;
// Add the object's properties
auto &property_list = object->get_properties(); auto &property_list = object->get_properties();
for (auto it = property_list.begin(); for (auto it = property_list.begin();
it != property_list.end(); ++it) it != property_list.end(); ++it)
@ -55,7 +54,7 @@ namespace serialization
{ {
for (std::size_t i = 0; i < prop.get_element_count(); ++i) for (std::size_t i = 0; i < prop.get_element_count(); ++i)
{ {
if (prop.get_type().get_kind() == pclass::Type::kind::CLASS) if (prop.get_type().get_kind() == pclass::Type::Kind::CLASS)
{ {
auto *other_object = prop.get_object(i); auto *other_object = prop.get_object(i);
if (prop.is_array()) if (prop.is_array())
@ -124,6 +123,10 @@ namespace serialization
auto &prop = *it; auto &prop = *it;
load_property(prop, j); load_property(prop, j);
} }
// All properties on this object have been set, let the new
// instance react to this change
dest->on_created();
} }
void JsonSerializer::load_property( void JsonSerializer::load_property(
@ -143,7 +146,7 @@ namespace serialization
for (std::size_t i = 0; i < prop.get_element_count(); ++i) for (std::size_t i = 0; i < prop.get_element_count(); ++i)
{ {
if (prop.get_type().get_kind() == pclass::Type::kind::CLASS) if (prop.get_type().get_kind() == pclass::Type::Kind::CLASS)
{ {
std::unique_ptr<pclass::PropertyClass> other_object = nullptr; std::unique_ptr<pclass::PropertyClass> other_object = nullptr;
if (prop.is_array()) if (prop.is_array())

Binary file not shown.

View File

@ -2,7 +2,30 @@
"_pclass_meta": { "_pclass_meta": {
"type_hash": 2069042008 "type_hash": 2069042008
}, },
"collection": [ "float32": 3.1415927410125732,
"float64": 3.141592653589793,
"int16": 515,
"int24": 263430,
"int32": 117967114,
"int4": -6,
"int64": 796025588171149586,
"int8": 1,
"int_array": [
0,
1,
2,
3,
4
],
"int_ptr": 52,
"int_ptr_array": [
0,
1,
2,
3,
4
],
"int_ptr_vector": [
0, 0,
1, 1,
2, 2,
@ -104,27 +127,127 @@
98, 98,
99 99
], ],
"float32": 3.1415927410125732, "int_vector": [
"float64": 3.141592653589793, 0,
"int16": 515, 1,
"int24": 263430, 2,
"int32": 117967114, 3,
"int4": -6, 4,
"int64": 796025588171149586, 5,
"int8": 1, 6,
"int_ptr": 52, 7,
"not_null_object": { 8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
62,
63,
64,
65,
66,
67,
68,
69,
70,
71,
72,
73,
74,
75,
76,
77,
78,
79,
80,
81,
82,
83,
84,
85,
86,
87,
88,
89,
90,
91,
92,
93,
94,
95,
96,
97,
98,
99
],
"null_object_ptr": {
"_pclass_meta": {
"type_hash": 0
}
},
"object": {
"_pclass_meta": {
"type_hash": 1180894394
},
"extra_value": 20,
"m_kind": 2
},
"object_ptr": {
"_pclass_meta": { "_pclass_meta": {
"type_hash": 1181435066 "type_hash": 1181435066
}, },
"m_kind": 1 "m_kind": 1
}, },
"null_object": { "object_ptr_vector": [
"_pclass_meta": {
"type_hash": 0
}
},
"objects": [
{ {
"_pclass_meta": { "_pclass_meta": {
"type_hash": 1180894394 "type_hash": 1180894394
@ -139,108 +262,6 @@
"m_kind": 3 "m_kind": 3
} }
], ],
"ptr_collection": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
62,
63,
64,
65,
66,
67,
68,
69,
70,
71,
72,
73,
74,
75,
76,
77,
78,
79,
80,
81,
82,
83,
84,
85,
86,
87,
88,
89,
90,
91,
92,
93,
94,
95,
96,
97,
98,
99
],
"string": "This is a test value", "string": "This is a test value",
"uint16": 515, "uint16": 515,
"uint24": 263430, "uint24": 263430,
@ -248,38 +269,31 @@
"uint4": 5, "uint4": 5,
"uint64": 796025588171149586, "uint64": 796025588171149586,
"uint8": 1, "uint8": 1,
"value_object": {
"_pclass_meta": {
"type_hash": 1180894394
},
"extra_value": 20,
"m_kind": 2
},
"vector3d": { "vector3d": {
"x": 24.0, "x": 24.0,
"y": 61.0, "y": 61.0,
"z": 3.619999885559082 "z": 3.619999885559082
}, },
"wstring": [ "wstring": [
84, 7511,
104, 688,
105, 8305,
115, 738,
32, 32,
105, 8305,
115, 738,
32, 32,
97, 7491,
32, 32,
116, 7511,
101, 7497,
115, 738,
116, 7511,
32, 32,
118, 7515,
97, 7491,
108, 737,
117, 7512,
101 7497
] ]
} }

View File

@ -1 +1 @@
{"_pclass_meta":{"type_hash":2069042008},"collection":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99],"float32":3.1415927410125732,"float64":3.141592653589793,"int16":515,"int24":263430,"int32":117967114,"int4":-6,"int64":796025588171149586,"int8":1,"int_ptr":52,"not_null_object":{"_pclass_meta":{"type_hash":1181435066},"m_kind":1},"null_object":{"_pclass_meta":{"type_hash":0}},"objects":[{"_pclass_meta":{"type_hash":1180894394},"extra_value":10,"m_kind":2},{"_pclass_meta":{"type_hash":1180943546},"m_kind":3}],"ptr_collection":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99],"string":"This is a test value","uint16":515,"uint24":263430,"uint32":117967114,"uint4":5,"uint64":796025588171149586,"uint8":1,"value_object":{"_pclass_meta":{"type_hash":1180894394},"extra_value":20,"m_kind":2},"vector3d":{"x":24.0,"y":61.0,"z":3.619999885559082},"wstring":[84,104,105,115,32,105,115,32,97,32,116,101,115,116,32,118,97,108,117,101]} {"_pclass_meta":{"type_hash":2069042008},"float32":3.1415927410125732,"float64":3.141592653589793,"int16":515,"int24":263430,"int32":117967114,"int4":-6,"int64":796025588171149586,"int8":1,"int_array":[0,1,2,3,4],"int_ptr":52,"int_ptr_array":[0,1,2,3,4],"int_ptr_vector":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99],"int_vector":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99],"null_object_ptr":{"_pclass_meta":{"type_hash":0}},"object":{"_pclass_meta":{"type_hash":1180894394},"extra_value":20,"m_kind":2},"object_ptr":{"_pclass_meta":{"type_hash":1181435066},"m_kind":1},"object_ptr_vector":[{"_pclass_meta":{"type_hash":1180894394},"extra_value":10,"m_kind":2},{"_pclass_meta":{"type_hash":1180943546},"m_kind":3}],"string":"This is a test value","uint16":515,"uint24":263430,"uint32":117967114,"uint4":5,"uint64":796025588171149586,"uint8":1,"vector3d":{"x":24.0,"y":61.0,"z":3.619999885559082},"wstring":[7511,688,8305,738,32,8305,738,32,7491,32,7511,7497,738,7511,32,7515,7491,737,7512,7497]}

View File

@ -330,7 +330,7 @@ TEST_CASE("BitStream Functionality", "[bit-stream]")
SECTION("Copying memory in/out of the stream") SECTION("Copying memory in/out of the stream")
{ {
// Copy the string into the stream // Copy the string into the stream
char *str = "Hello, world!"; char str[] = "Hello, world!";
const auto size = bitsizeof<char>::value * (strlen(str) + 1); const auto size = bitsizeof<char>::value * (strlen(str) + 1);
bit_stream.write_copy(reinterpret_cast<uint8_t *>(str), size); bit_stream.write_copy(reinterpret_cast<uint8_t *>(str), size);

149
test/src/unit-pclass.cpp Normal file
View File

@ -0,0 +1,149 @@
#define CATCH_CONFIG_MAIN
#include <catch.hpp>
#include <memory>
#include "ki/pclass/TypeSystem.h"
#include "ki/pclass/HashCalculator.h"
using namespace ki;
PCLASS(TestClassTypeA)
{
public:
using PropertyClass::PropertyClass;
};
PCLASS(TestClassTypeB)
{
public:
using PropertyClass::PropertyClass;
};
TEST_CASE("TypeSystem and Type definition", "[pclass]")
{
std::unique_ptr<pclass::IHashCalculator> hash_calculator
= ki::make_unique<pclass::WizardHashCalculator>();
auto type_system = ki::make_unique<pclass::TypeSystem>(hash_calculator);
SECTION("Define class")
{
const auto class_name = "class TestClassTypeA";
const auto class_hash = type_system->get_hash_calculator()
.calculate_type_hash(class_name);
auto &defined_class = type_system->define_class<TestClassTypeA>(class_name);
REQUIRE(type_system->has_type(class_name));
REQUIRE(type_system->has_type(class_hash));
auto &retrieved_class_name = type_system->get_type(class_name);
auto &retrieved_class_hash = type_system->get_type(class_hash);
REQUIRE(&retrieved_class_name == &defined_class);
REQUIRE(&retrieved_class_hash == &defined_class);
}
SECTION("Define derived class")
{
const auto base_class_name = "class TestClassTypeA";
auto &base_class = type_system->define_class<TestClassTypeA>(base_class_name);
REQUIRE(type_system->has_type(base_class_name));
const auto derived_class_name = "class TestClassTypeB";
auto &derived_class = type_system->define_class<TestClassTypeB>(derived_class_name, base_class);
REQUIRE(type_system->has_type(derived_class_name));
}
SECTION("Define class with non-class ancestor")
{
try
{
// Attempt to define a type that inherits "int".
type_system->define_class<TestClassTypeA>(
"class TestClassTypeA", type_system->get_type("int")
);
FAIL();
}
catch (runtime_error &e)
{
SUCCEED();
}
}
SECTION("Get a type that does not exist by name")
{
try
{
auto &made_up_struct = type_system->get_type("struct MadeUp");
FAIL();
}
catch (runtime_error &e)
{
SUCCEED();
}
}
SECTION("Get a type that does not exist by hash")
{
try
{
auto &made_up_struct = type_system->get_type(0xDEADA55);
FAIL();
}
catch (runtime_error &e)
{
SUCCEED();
}
}
SECTION("Define type with the same name")
{
try
{
const auto class_name = "class TestClassTypeA";
type_system->define_class<TestClassTypeA>(class_name);
type_system->define_class<TestClassTypeA>(class_name);
FAIL();
}
catch (runtime_error &e)
{
SUCCEED();
}
}
SECTION("Define type with the same name")
{
try
{
const auto class_name = "class TestClassTypeA";
type_system->define_class<TestClassTypeA>(class_name);
type_system->define_class<TestClassTypeA>(class_name);
FAIL();
}
catch (runtime_error &e)
{
SUCCEED();
}
}
SECTION("Define type with the same hash")
{
try
{
type_system->define_class<TestClassTypeA>("a");
type_system->define_class<TestClassTypeA>("a ");
FAIL();
}
catch (runtime_error &e)
{
SUCCEED();
}
}
}
TEST_CASE("PropertyClass and PropertyList", "[pclass]")
{
// TODO: Test PropertyClass instances
}
TEST_CASE("Enums", "[pclass]")
{
// TODO: Test Enums
}

View File

@ -1,4 +1,4 @@
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include <cstdio> #include <cstdio>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
@ -10,6 +10,7 @@
#include <ki/pclass/VectorProperty.h> #include <ki/pclass/VectorProperty.h>
#include <ki/serialization/BinarySerializer.h> #include <ki/serialization/BinarySerializer.h>
#include <ki/serialization/JsonSerializer.h> #include <ki/serialization/JsonSerializer.h>
#include "ki/pclass/Enum.h"
using namespace ki; using namespace ki;
@ -42,11 +43,9 @@ struct Vector3D
bool operator==(const Vector3D &that) const bool operator==(const Vector3D &that) const
{ {
return ( return m_x == that.m_x &&
m_x == that.m_x, m_y == that.m_y &&
m_y == that.m_y, m_z == that.m_z;
m_z == that.m_z
);
} }
void write_to(BitStream &stream) const void write_to(BitStream &stream) const
@ -244,12 +243,14 @@ public:
INIT_PROPERTY(float64, "double") INIT_PROPERTY(float64, "double")
INIT_PROPERTY(vector3d, "struct Vector3D") INIT_PROPERTY(vector3d, "struct Vector3D")
INIT_PROPERTY(int_ptr, "int") INIT_PROPERTY(int_ptr, "int")
INIT_PROPERTY(value_object, "class NestedTestObjectA") INIT_PROPERTY(int_array, "int")
INIT_PROPERTY(not_null_object, "class NestedTestObject") INIT_PROPERTY(int_ptr_array, "int")
INIT_PROPERTY(null_object, "class NestedTestObject") INIT_PROPERTY(object, "class NestedTestObjectA")
INIT_PROPERTY(collection, "int") INIT_PROPERTY(object_ptr, "class NestedTestObject")
INIT_PROPERTY(ptr_collection, "int") INIT_PROPERTY(null_object_ptr, "class NestedTestObject")
INIT_PROPERTY(objects, "class NestedTestObject") INIT_PROPERTY(int_vector, "int")
INIT_PROPERTY(int_ptr_vector, "int")
INIT_PROPERTY(object_ptr_vector, "class NestedTestObject")
{} {}
// Test signed and unsigned integers with a bit length less than 8 // Test signed and unsigned integers with a bit length less than 8
@ -282,21 +283,27 @@ public:
// Test dereferencing when writing pointers to primitives // Test dereferencing when writing pointers to primitives
pclass::StaticProperty<int *> int_ptr; pclass::StaticProperty<int *> int_ptr;
// Test writing a single instance of another object // Test explicitly-sized array of primitives and pointers
pclass::StaticProperty<NestedTestObjectA> value_object; pclass::StaticProperty<int[5]> int_array;
pclass::StaticProperty<NestedTestObject *> not_null_object; pclass::StaticProperty<int *[5]> int_ptr_array;
pclass::StaticProperty<NestedTestObject *> null_object;
// Test writing a class type as a value
pclass::StaticProperty<NestedTestObjectA> object;
// Test writing a class type as a pointer
pclass::StaticProperty<NestedTestObject *> object_ptr;
pclass::StaticProperty<NestedTestObject *> null_object_ptr;
// Test writing collections of primitives // Test writing collections of primitives
pclass::VectorProperty<int> collection; pclass::VectorProperty<int> int_vector;
pclass::VectorProperty<int *> ptr_collection; pclass::VectorProperty<int *> int_ptr_vector;
// Test writing multiple instances of another object // Test writing multiple instances of another object
pclass::VectorProperty<NestedTestObject *> objects; pclass::VectorProperty<NestedTestObject *> object_ptr_vector;
}; };
// Setup a global TypeSystem instance // Setup a global TypeSystem instance
std::unique_ptr<pclass::HashCalculator> g_hash_calculator std::unique_ptr<pclass::IHashCalculator> g_hash_calculator
= ki::make_unique<pclass::WizardHashCalculator>(); = ki::make_unique<pclass::WizardHashCalculator>();
auto g_type_system = ki::make_unique<pclass::TypeSystem>(g_hash_calculator); auto g_type_system = ki::make_unique<pclass::TypeSystem>(g_hash_calculator);
bool g_types_defined = false; bool g_types_defined = false;
@ -338,13 +345,14 @@ void define_types()
#define EXPECTED_uint32 0x0708090A #define EXPECTED_uint32 0x0708090A
#define EXPECTED_uint64 0x0B0C0D0E0F101112 #define EXPECTED_uint64 0x0B0C0D0E0F101112
#define EXPECTED_string "This is a test value" #define EXPECTED_string "This is a test value"
#define EXPECTED_wstring u"This is a test value" #define EXPECTED_wstring u"\u1d57\u02b0\u2071\u02e2\u0020\u2071\u02e2\u0020\u1d43\u0020\u1d57\u1d49\u02e2\u1d57\u0020\u1d5b\u1d43\u02e1\u1d58\u1d49"
#define EXPECTED_float32 3.1415927410125732421875f #define EXPECTED_float32 3.1415927410125732421875f
#define EXPECTED_float64 3.141592653589793115997963468544185161590576171875 #define EXPECTED_float64 3.141592653589793115997963468544185161590576171875
#define EXPECTED_vector3d Vector3D(24.0f, 61.0f, 3.62f) #define EXPECTED_vector3d Vector3D(24.0f, 61.0f, 3.62f)
#define EXPECTED_int_ptr 52 #define EXPECTED_int_ptr 52
#define EXPECTED_value_object_extra_value 20 #define EXPECTED_value_object_extra_value 20
#define EXPECTED_collection_size 100 #define EXPECTED_int_array_size 5
#define EXPECTED_int_vector_size 100
#define SET_EXPECTED(object, identifier) object.identifier = EXPECTED_##identifier #define SET_EXPECTED(object, identifier) object.identifier = EXPECTED_##identifier
#define IS_EXPECTED(object, identifier) object.identifier.get() == EXPECTED_##identifier #define IS_EXPECTED(object, identifier) object.identifier.get() == EXPECTED_##identifier
@ -372,22 +380,29 @@ void configure_test_object(TestObject &object)
SET_EXPECTED(object, float64); SET_EXPECTED(object, float64);
SET_EXPECTED(object, vector3d); SET_EXPECTED(object, vector3d);
object.int_ptr = new int(EXPECTED_int_ptr); object.int_ptr = new int(EXPECTED_int_ptr);
// Configure the collection of integers // Configure the int array
for (auto i = 0; i < EXPECTED_collection_size; ++i) for (auto i = 0; i < EXPECTED_int_array_size; ++i)
{ {
object.collection.push_back(i); object.int_array[i] = i;
object.ptr_collection.push_back(new int(i)); object.int_ptr_array[i] = new int(i);
}
// Configure the int vector
for (auto i = 0; i < EXPECTED_int_vector_size; ++i)
{
object.int_vector.push_back(i);
object.int_ptr_vector.push_back(new int(i));
} }
// Configure nested objects // Configure nested objects
object.value_object.get().extra_value = EXPECTED_value_object_extra_value; object.object.get().extra_value = EXPECTED_value_object_extra_value;
object.not_null_object = g_type_system->instantiate<NestedTestObject>("class NestedTestObject").release(); object.object_ptr = g_type_system->instantiate<NestedTestObject>("class NestedTestObject").release();
object.null_object = nullptr; object.null_object_ptr = nullptr;
object.objects.push_back( object.object_ptr_vector.push_back(
g_type_system->instantiate<NestedTestObjectA>("class NestedTestObjectA").release() g_type_system->instantiate<NestedTestObjectA>("class NestedTestObjectA").release()
); );
object.objects.push_back( object.object_ptr_vector.push_back(
g_type_system->instantiate<NestedTestObjectB>("class NestedTestObjectB").release() g_type_system->instantiate<NestedTestObjectB>("class NestedTestObjectB").release()
); );
} }
@ -417,23 +432,32 @@ void validate_test_object(TestObject &object)
REQUIRE(IS_EXPECTED(object, vector3d)); REQUIRE(IS_EXPECTED(object, vector3d));
REQUIRE(*object.int_ptr == EXPECTED_int_ptr); REQUIRE(*object.int_ptr == EXPECTED_int_ptr);
// Validate both collections // Validate the int array
REQUIRE(object.collection.size() == EXPECTED_collection_size); REQUIRE(object.int_array.get_element_count() == EXPECTED_int_array_size);
REQUIRE(object.ptr_collection.size() == EXPECTED_collection_size); REQUIRE(object.int_ptr_array.get_element_count() == EXPECTED_int_array_size);
for (auto i = 0; i < EXPECTED_collection_size; i++) for (auto i = 0; i < EXPECTED_int_array_size; i++)
{ {
REQUIRE(object.collection[i] == i); REQUIRE(object.int_array[i] == i);
REQUIRE(*object.ptr_collection[i] == i); REQUIRE(*object.int_ptr_array[i] == i);
}
// Validate the int vector
REQUIRE(object.int_vector.size() == EXPECTED_int_vector_size);
REQUIRE(object.int_ptr_vector.size() == EXPECTED_int_vector_size);
for (auto i = 0; i < EXPECTED_int_vector_size; i++)
{
REQUIRE(object.int_vector[i] == i);
REQUIRE(*object.int_ptr_vector[i] == i);
} }
// Validate nested objects // Validate nested objects
REQUIRE(object.value_object.get().extra_value == EXPECTED_value_object_extra_value); REQUIRE(object.object.get().extra_value == EXPECTED_value_object_extra_value);
REQUIRE(object.not_null_object.get() != nullptr); REQUIRE(object.object_ptr.get() != nullptr);
REQUIRE(object.not_null_object.get()->get_kind() == NestedObjectKind::OBJECT); REQUIRE(object.object_ptr.get()->get_kind() == NestedObjectKind::OBJECT);
REQUIRE(object.null_object.get() == nullptr); REQUIRE(object.null_object_ptr.get() == nullptr);
REQUIRE(object.objects.size() == 2); REQUIRE(object.object_ptr_vector.size() == 2);
REQUIRE(object.objects[0]->get_kind() == NestedObjectKind::OBJECT_A); REQUIRE(object.object_ptr_vector[0]->get_kind() == NestedObjectKind::OBJECT_A);
REQUIRE(object.objects[1]->get_kind() == NestedObjectKind::OBJECT_B); REQUIRE(object.object_ptr_vector[1]->get_kind() == NestedObjectKind::OBJECT_B);
} }
/** /**
@ -580,7 +604,7 @@ TEST_CASE("Serialization tests", "[serialization]")
SECTION("Regular format without compression") SECTION("Regular format without compression")
{ {
serialization::BinarySerializer serializer( serialization::BinarySerializer serializer(
*g_type_system.get(), false, *g_type_system, false,
serialization::BinarySerializer::flags::NONE serialization::BinarySerializer::flags::NONE
); );
test_serializer(test_object, serializer, "regular"); test_serializer(test_object, serializer, "regular");
@ -588,7 +612,7 @@ TEST_CASE("Serialization tests", "[serialization]")
SECTION("File format without compression") SECTION("File format without compression")
{ {
serialization::BinarySerializer serializer( serialization::BinarySerializer serializer(
*g_type_system.get(), true, *g_type_system, true,
serialization::BinarySerializer::flags::WRITE_SERIALIZER_FLAGS serialization::BinarySerializer::flags::WRITE_SERIALIZER_FLAGS
); );
test_serializer(test_object, serializer, "file"); test_serializer(test_object, serializer, "file");
@ -596,7 +620,7 @@ TEST_CASE("Serialization tests", "[serialization]")
SECTION("Regular format with compression") SECTION("Regular format with compression")
{ {
serialization::BinarySerializer serializer( serialization::BinarySerializer serializer(
*g_type_system.get(), false, *g_type_system, false,
serialization::BinarySerializer::flags::COMPRESSED serialization::BinarySerializer::flags::COMPRESSED
); );
test_serializer(test_object, serializer, "regular_compressed"); test_serializer(test_object, serializer, "regular_compressed");
@ -604,7 +628,7 @@ TEST_CASE("Serialization tests", "[serialization]")
SECTION("File format with compression") SECTION("File format with compression")
{ {
serialization::BinarySerializer serializer( serialization::BinarySerializer serializer(
*g_type_system.get(), true, *g_type_system, true,
serialization::BinarySerializer::flags::WRITE_SERIALIZER_FLAGS | serialization::BinarySerializer::flags::WRITE_SERIALIZER_FLAGS |
serialization::BinarySerializer::flags::COMPRESSED serialization::BinarySerializer::flags::COMPRESSED
); );