mirror of https://github.com/SeanOMik/libki.git
etc: Refactoring, documentation, and more tests
This commit is contained in:
parent
bab80d20c7
commit
4833f7fb76
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
|
@ -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;
|
|
@ -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(
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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>()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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"
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
@ -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
|
||||||
]
|
]
|
||||||
}
|
}
|
Binary file not shown.
Binary file not shown.
|
@ -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]}
|
Binary file not shown.
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue