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 "ki/pclass/Value.h"
|
||||
#include "ki/util/BitTypes.h"
|
||||
#include "ki/pclass/types/EnumType.h"
|
||||
#include "ki/pclass/EnumType.h"
|
||||
|
||||
namespace ki
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <type_traits>
|
||||
#include <string>
|
||||
#include "ki/pclass/Property.h"
|
||||
#include "ki/pclass/types/Type.h"
|
||||
#include "ki/pclass/Type.h"
|
||||
#include "ki/pclass/PropertyClass.h"
|
||||
|
||||
namespace ki
|
||||
|
@ -11,18 +11,22 @@ namespace ki
|
|||
namespace pclass
|
||||
{
|
||||
/**
|
||||
* TODO: Documentation
|
||||
* Base type for classes. Adds inheritance to Type.
|
||||
*/
|
||||
class IClassType : public Type
|
||||
{
|
||||
public:
|
||||
IClassType(const std::string &name,
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
{
|
||||
// Ensure that ClassT inherits PropertyClass
|
||||
static_assert(std::is_base_of<PropertyClass, ClassT>::value, "ClassT must inherit PropertyClass!");
|
||||
|
||||
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,
|
||||
const Type *base_class, const TypeSystem &type_system)
|
||||
: IClassType(name, base_class, type_system)
|
||||
{}
|
||||
~ClassType() = default;
|
||||
|
||||
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 &properties = object.get_properties();
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
#include "ki/pclass/types/EnumType.h"
|
||||
#include "ki/pclass/types/PrimitiveType.h"
|
||||
#include "ki/pclass/EnumType.h"
|
||||
#include "ki/pclass/PrimitiveType.h"
|
||||
|
||||
namespace ki
|
||||
{
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include "ki/pclass/types/Type.h"
|
||||
#include "ki/pclass/types/PrimitiveType.h"
|
||||
#include "ki/pclass/Type.h"
|
||||
#include "ki/pclass/PrimitiveType.h"
|
||||
|
||||
namespace ki
|
||||
{
|
||||
|
@ -32,6 +32,12 @@ namespace pclass
|
|||
};
|
||||
|
||||
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();
|
||||
|
||||
|
@ -43,7 +49,7 @@ namespace pclass
|
|||
|
||||
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;
|
||||
|
||||
private:
|
||||
|
@ -66,10 +72,10 @@ namespace pclass
|
|||
CppEnumType(const std::string &name, const TypeSystem &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 &underlying_reference = reinterpret_cast<const underlying_type &>(enum_reference);
|
|
@ -13,10 +13,10 @@ namespace ki
|
|||
/**
|
||||
* A base class for type/property hash calculators.
|
||||
*/
|
||||
class HashCalculator
|
||||
class IHashCalculator
|
||||
{
|
||||
public:
|
||||
virtual ~HashCalculator() {};
|
||||
virtual ~IHashCalculator() {};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Wizard101.
|
||||
*/
|
||||
class WizardHashCalculator : public HashCalculator
|
||||
class WizardHashCalculator : public IHashCalculator
|
||||
{
|
||||
public:
|
||||
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
|
||||
#include <string>
|
||||
#include "ki/pclass/types/Type.h"
|
||||
#include "ki/pclass/Type.h"
|
||||
#include "ki/pclass/HashCalculator.h"
|
||||
#include "ki/pclass/Value.h"
|
||||
#include "ki/util/BitStream.h"
|
||||
|
@ -12,7 +12,9 @@ namespace pclass
|
|||
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
|
||||
{
|
||||
|
@ -26,27 +28,86 @@ namespace pclass
|
|||
IProperty(PropertyClass &object,
|
||||
const IProperty &that);
|
||||
|
||||
virtual ~IProperty() {}
|
||||
virtual ~IProperty() = default;
|
||||
|
||||
const PropertyClass &get_instance() const;
|
||||
std::string get_name() const;
|
||||
hash_t get_name_hash() const;
|
||||
hash_t get_full_hash() 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;
|
||||
|
||||
/**
|
||||
* @returns Whether or not the property's size is dynamic.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* @returns The number of values that the property is holding.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include "ki/pclass/types/Type.h"
|
||||
#include "ki/pclass/Type.h"
|
||||
#include "ki/pclass/PropertyList.h"
|
||||
|
||||
#define _KI_TYPE ki::pclass::Type
|
||||
|
@ -52,11 +52,10 @@ namespace ki
|
|||
{
|
||||
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
|
||||
{
|
||||
|
@ -64,7 +63,7 @@ namespace pclass
|
|||
|
||||
public:
|
||||
explicit PropertyClass(const Type &type, const TypeSystem &type_system);
|
||||
virtual ~PropertyClass() {}
|
||||
virtual ~PropertyClass() = default;
|
||||
|
||||
PropertyClass(const PropertyClass &that);
|
||||
PropertyClass &operator=(const PropertyClass &that);
|
||||
|
@ -75,12 +74,11 @@ namespace pclass
|
|||
|
||||
virtual void on_created() const {}
|
||||
|
||||
protected:
|
||||
void add_property(IProperty &prop);
|
||||
|
||||
private:
|
||||
const Type *m_type;
|
||||
PropertyList m_properties;
|
||||
|
||||
void add_property(IProperty &prop);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,16 +11,13 @@ namespace pclass
|
|||
class IProperty;
|
||||
|
||||
/**
|
||||
* TODO: Documentation
|
||||
* Manages property lookup on a PropertyClass instance.
|
||||
*/
|
||||
class PropertyList
|
||||
{
|
||||
friend PropertyClass;
|
||||
|
||||
public:
|
||||
/**
|
||||
* TODO: Documentation
|
||||
*/
|
||||
class iterator
|
||||
{
|
||||
friend PropertyList;
|
||||
|
@ -40,9 +37,6 @@ namespace pclass
|
|||
explicit iterator(PropertyList &list, int index = 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: Documentation
|
||||
*/
|
||||
class const_iterator
|
||||
{
|
||||
friend PropertyList;
|
||||
|
@ -62,18 +56,63 @@ namespace pclass
|
|||
explicit const_iterator(const PropertyList &list, int index = 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns The number of properties in this list.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
iterator begin();
|
||||
|
|
|
@ -271,14 +271,14 @@ namespace pclass
|
|||
>
|
||||
{
|
||||
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,
|
||||
// so we can cast down to a PropertyClass pointer.
|
||||
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)
|
||||
{
|
||||
// Ensure that object is not nullptr
|
||||
|
@ -308,14 +308,14 @@ namespace pclass
|
|||
>
|
||||
{
|
||||
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,
|
||||
// so we can cast down to a PropertyClass pointer.
|
||||
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)
|
||||
{
|
||||
// Ensure that object inherits the type of the property
|
||||
|
@ -397,12 +397,12 @@ namespace pclass
|
|||
template <typename ValueT, int 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]);
|
||||
}
|
||||
|
||||
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>();
|
||||
prop.m_value[index] = casted_value.release<ValueT>();
|
||||
|
|
|
@ -19,12 +19,21 @@ namespace pclass
|
|||
class Type
|
||||
{
|
||||
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,
|
||||
|
||||
/**
|
||||
* A Type that contain pure, simple values.
|
||||
* A Type that contains pure, simple values.
|
||||
*/
|
||||
PRIMITIVE,
|
||||
|
||||
|
@ -40,19 +49,39 @@ namespace pclass
|
|||
};
|
||||
|
||||
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;
|
||||
kind get_kind() const;
|
||||
Kind get_kind() const;
|
||||
|
||||
/**
|
||||
* The TypeSystem used to define this Type instance.
|
||||
*/
|
||||
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 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;
|
||||
|
||||
protected:
|
||||
kind m_kind;
|
||||
Kind m_kind;
|
||||
|
||||
private:
|
||||
std::string m_name;
|
|
@ -4,31 +4,62 @@
|
|||
#include <json.hpp>
|
||||
#include "ki/pclass/HashCalculator.h"
|
||||
#include "ki/pclass/Casters.h"
|
||||
#include "ki/pclass/types/Type.h"
|
||||
#include "ki/pclass/types/PrimitiveType.h"
|
||||
#include "ki/pclass/types/ClassType.h"
|
||||
#include "ki/pclass/types/EnumType.h"
|
||||
#include "ki/pclass/Type.h"
|
||||
#include "ki/pclass/PrimitiveType.h"
|
||||
#include "ki/pclass/ClassType.h"
|
||||
#include "ki/pclass/EnumType.h"
|
||||
#include "ki/util/unique.h"
|
||||
|
||||
namespace ki
|
||||
{
|
||||
namespace pclass
|
||||
{
|
||||
/**
|
||||
* TODO: Documentation
|
||||
* A class that provides run-time type definition and lookup.
|
||||
*/
|
||||
class TypeSystem
|
||||
{
|
||||
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;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* 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>
|
||||
PrimitiveType<ValueT> &define_primitive(const std::string &name)
|
||||
{
|
||||
|
@ -42,21 +73,45 @@ namespace pclass
|
|||
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>
|
||||
ClassType<ClassT> &define_class(const std::string &name)
|
||||
{
|
||||
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(
|
||||
const std::string &name, const Type &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);
|
||||
|
||||
/**
|
||||
* 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>
|
||||
CppEnumType<EnumT> &define_enum(const std::string &name)
|
||||
{
|
||||
|
@ -70,6 +125,11 @@ namespace pclass
|
|||
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>
|
||||
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::unordered_map<std::string, Type *> m_type_name_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>
|
||||
ClassType<ClassT> &define_class(
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace pclass
|
|||
*/
|
||||
struct value_caster_base
|
||||
{
|
||||
virtual ~value_caster_base() {}
|
||||
virtual ~value_caster_base() = default;
|
||||
|
||||
/**
|
||||
* @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>
|
||||
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()
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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>
|
||||
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
|
||||
{
|
||||
|
@ -110,9 +113,9 @@ namespace pclass
|
|||
friend Value;
|
||||
|
||||
public:
|
||||
ValueDeallocator(ValueDeallocator &that);
|
||||
ValueDeallocator(const ValueDeallocator &that);
|
||||
ValueDeallocator(ValueDeallocator &&that) noexcept;
|
||||
ValueDeallocator &operator=(ValueDeallocator &that);
|
||||
ValueDeallocator &operator=(const ValueDeallocator &that);
|
||||
ValueDeallocator &operator=(ValueDeallocator &&that) noexcept;
|
||||
~ValueDeallocator();
|
||||
|
||||
|
@ -137,7 +140,7 @@ namespace pclass
|
|||
}
|
||||
|
||||
/**
|
||||
* TODO: Documentation
|
||||
* Provides a way to perform casting on Value instances.
|
||||
*/
|
||||
class ValueCaster
|
||||
{
|
||||
|
@ -229,9 +232,9 @@ namespace pclass
|
|||
class Value
|
||||
{
|
||||
public:
|
||||
Value(Value &that);
|
||||
Value(const Value &that);
|
||||
Value(Value &&that) noexcept;
|
||||
Value &operator=(Value &that);
|
||||
Value &operator=(const Value &that);
|
||||
Value &operator=(Value &&that) noexcept;
|
||||
~Value();
|
||||
|
||||
|
@ -351,7 +354,7 @@ namespace pclass
|
|||
/**
|
||||
* @tparam T The type of value to hold.
|
||||
* @param[in] value The initial value.
|
||||
* @returns A new Value instance that refers to a value it doesn't own.
|
||||
* @returns A new Value instance that refers to a value it does not own.
|
||||
*/
|
||||
template <typename T>
|
||||
static Value make_reference(T &value)
|
||||
|
|
|
@ -112,14 +112,14 @@ namespace pclass
|
|||
using default_vector_object_helper<ValueT>::copy;
|
||||
|
||||
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,
|
||||
// so we can cast down to a PropertyClass pointer.
|
||||
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)
|
||||
{
|
||||
// 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/util/exception.h"
|
||||
|
||||
|
@ -10,13 +10,13 @@ namespace pclass
|
|||
const Type *base_class, const TypeSystem& type_system)
|
||||
: Type(name, type_system)
|
||||
{
|
||||
m_kind = kind::CLASS;
|
||||
m_kind = Kind::CLASS;
|
||||
|
||||
// Have we been given a base class?
|
||||
if (base_class)
|
||||
{
|
||||
// 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!");
|
||||
|
||||
// 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)
|
||||
{
|
||||
// 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.");
|
||||
|
||||
m_type = &dynamic_cast<const EnumType &>(type);
|
||||
|
@ -17,7 +17,7 @@ namespace pclass
|
|||
Enum::Enum(const Type &type, const std::string &element_name)
|
||||
{
|
||||
// Make sure the type we've been given is an enum type
|
||||
if (type.get_kind() != Type::kind::ENUM)
|
||||
if (type.get_kind() != Type::Kind::ENUM)
|
||||
throw runtime_error("Enum constructor was supplied with a non-enum type.");
|
||||
|
||||
m_type = &dynamic_cast<const EnumType &>(type);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "ki/pclass/types/EnumType.h"
|
||||
#include "ki/pclass/EnumType.h"
|
||||
#include "ki/util/exception.h"
|
||||
#include <sstream>
|
||||
#include "ki/pclass/Enum.h"
|
||||
|
@ -7,7 +7,6 @@ namespace ki
|
|||
{
|
||||
namespace pclass
|
||||
{
|
||||
|
||||
EnumType::Element::Element(const std::string &name,
|
||||
const enum_value_t value)
|
||||
{
|
||||
|
@ -29,7 +28,7 @@ namespace pclass
|
|||
const TypeSystem &type_system)
|
||||
: Type(name, type_system)
|
||||
{
|
||||
m_kind = kind::ENUM;
|
||||
m_kind = Kind::ENUM;
|
||||
}
|
||||
|
||||
EnumType::~EnumType()
|
||||
|
@ -110,7 +109,7 @@ namespace pclass
|
|||
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
|
||||
value.get<Enum>().write_to(stream);
|
||||
|
|
|
@ -85,7 +85,8 @@ namespace pclass
|
|||
{
|
||||
if (index < 0 || index >= get_element_count())
|
||||
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)
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#include "ki/pclass/types/Type.h"
|
||||
#include "ki/pclass/types/ClassType.h"
|
||||
#include "ki/pclass/Type.h"
|
||||
#include "ki/pclass/ClassType.h"
|
||||
#include "ki/pclass/TypeSystem.h"
|
||||
#include "ki/util/exception.h"
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
namespace ki
|
||||
|
@ -16,10 +15,10 @@ namespace pclass
|
|||
m_hash = m_type_system
|
||||
.get_hash_calculator()
|
||||
.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;
|
||||
}
|
||||
|
@ -29,7 +28,7 @@ namespace pclass
|
|||
return m_hash;
|
||||
}
|
||||
|
||||
Type::kind Type::get_kind() const
|
||||
Type::Kind Type::get_kind() const
|
||||
{
|
||||
return m_kind;
|
||||
}
|
||||
|
@ -39,7 +38,7 @@ namespace pclass
|
|||
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;
|
||||
oss << "Type '" << m_name << "' does not implement Type::write_to.";
|
||||
|
@ -68,7 +67,7 @@ namespace pclass
|
|||
{
|
||||
// Do the types match via 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);
|
||||
if (actual_class.inherits(expected))
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace pclass
|
|||
template <>
|
||||
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);
|
||||
|
||||
|
@ -48,6 +48,7 @@ namespace pclass
|
|||
define_primitive<int8_t>("int8_t");
|
||||
define_primitive<uint8_t>("uint8_t");
|
||||
DEFINE_INTEGER_PRIMTIIVE(int16_t, uint16_t, "short");
|
||||
define_primitive<char16_t>("wchar_t");
|
||||
DEFINE_INTEGER_PRIMTIIVE(int16_t, uint16_t, "__int16");
|
||||
define_primitive<int16_t>("int16_t");
|
||||
define_primitive<uint16_t>("uint16_t");
|
||||
|
@ -59,7 +60,6 @@ namespace pclass
|
|||
DEFINE_INTEGER_PRIMTIIVE(int64_t, uint64_t, "__int64");
|
||||
define_primitive<int64_t>("int64_t");
|
||||
define_primitive<uint64_t>("uint64_t");
|
||||
define_primitive<uint64_t>("gid");
|
||||
|
||||
// Define bit-integer types
|
||||
define_bit_integer_primitive(*this);
|
||||
|
@ -78,11 +78,8 @@ namespace pclass
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -143,7 +140,7 @@ namespace pclass
|
|||
}
|
||||
|
||||
// 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
|
||||
auto &other_type = get_type(type->get_hash());
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace pclass
|
|||
|
||||
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.");
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ namespace pclass
|
|||
m_deallocator = deallocator;
|
||||
}
|
||||
|
||||
ValueDeallocator::ValueDeallocator(ValueDeallocator &that)
|
||||
ValueDeallocator::ValueDeallocator(const ValueDeallocator &that)
|
||||
{
|
||||
m_deallocator = that.m_deallocator->copy();
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ namespace pclass
|
|||
that.m_deallocator = nullptr;
|
||||
}
|
||||
|
||||
ValueDeallocator &ValueDeallocator::operator=(ValueDeallocator &that)
|
||||
ValueDeallocator &ValueDeallocator::operator=(const ValueDeallocator &that)
|
||||
{
|
||||
m_deallocator = that.m_deallocator->copy();
|
||||
return *this;
|
||||
|
@ -87,7 +87,7 @@ namespace pclass
|
|||
m_deallocator = detail::ValueDeallocator();
|
||||
}
|
||||
|
||||
Value::Value(Value& that)
|
||||
Value::Value(const Value &that)
|
||||
{
|
||||
m_value_ptr = that.m_value_ptr;
|
||||
m_ptr_is_owned = false;
|
||||
|
@ -108,7 +108,7 @@ namespace pclass
|
|||
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_ptr_is_owned = false;
|
||||
|
|
|
@ -120,7 +120,7 @@ namespace serialization
|
|||
if (object)
|
||||
stream.write<uint32_t>(object->get_type().get_hash());
|
||||
else
|
||||
stream.write<uint32_t>(NULL);
|
||||
stream.write<uint32_t>(0);
|
||||
return object != nullptr;
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,7 @@ namespace serialization
|
|||
for (auto i = 0; i < prop.get_element_count(); ++i)
|
||||
{
|
||||
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
|
||||
save_object(prop.get_object(i), stream);
|
||||
|
@ -358,7 +358,7 @@ namespace serialization
|
|||
for (auto i = 0; i < prop.get_element_count(); ++i)
|
||||
{
|
||||
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
|
||||
std::unique_ptr<pclass::PropertyClass> object = nullptr;
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace serialization
|
|||
{
|
||||
// Add the object's meta information
|
||||
j["_pclass_meta"] = {
|
||||
{ "type_hash", object ? object->get_type().get_hash() : NULL }
|
||||
{ "type_hash", object ? object->get_type().get_hash() : 0 }
|
||||
};
|
||||
return object != nullptr;
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ namespace serialization
|
|||
if (!presave_object(j, object))
|
||||
return j;
|
||||
|
||||
// Add the object's properties
|
||||
auto &property_list = object->get_properties();
|
||||
for (auto it = property_list.begin();
|
||||
it != property_list.end(); ++it)
|
||||
|
@ -55,7 +54,7 @@ namespace serialization
|
|||
{
|
||||
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);
|
||||
if (prop.is_array())
|
||||
|
@ -124,6 +123,10 @@ namespace serialization
|
|||
auto &prop = *it;
|
||||
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(
|
||||
|
@ -143,7 +146,7 @@ namespace serialization
|
|||
|
||||
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;
|
||||
if (prop.is_array())
|
||||
|
|
Binary file not shown.
|
@ -2,7 +2,30 @@
|
|||
"_pclass_meta": {
|
||||
"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,
|
||||
1,
|
||||
2,
|
||||
|
@ -104,27 +127,127 @@
|
|||
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": {
|
||||
"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
|
||||
},
|
||||
"null_object": {
|
||||
"_pclass_meta": {
|
||||
"type_hash": 0
|
||||
}
|
||||
},
|
||||
"objects": [
|
||||
"object_ptr_vector": [
|
||||
{
|
||||
"_pclass_meta": {
|
||||
"type_hash": 1180894394
|
||||
|
@ -139,108 +262,6 @@
|
|||
"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,
|
||||
|
@ -248,38 +269,31 @@
|
|||
"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,
|
||||
7511,
|
||||
688,
|
||||
8305,
|
||||
738,
|
||||
32,
|
||||
105,
|
||||
115,
|
||||
8305,
|
||||
738,
|
||||
32,
|
||||
97,
|
||||
7491,
|
||||
32,
|
||||
116,
|
||||
101,
|
||||
115,
|
||||
116,
|
||||
7511,
|
||||
7497,
|
||||
738,
|
||||
7511,
|
||||
32,
|
||||
118,
|
||||
97,
|
||||
108,
|
||||
117,
|
||||
101
|
||||
7515,
|
||||
7491,
|
||||
737,
|
||||
7512,
|
||||
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")
|
||||
{
|
||||
// Copy the string into the stream
|
||||
char *str = "Hello, world!";
|
||||
char str[] = "Hello, world!";
|
||||
const auto size = bitsizeof<char>::value * (strlen(str) + 1);
|
||||
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 <cstdint>
|
||||
#include <string>
|
||||
|
@ -10,6 +10,7 @@
|
|||
#include <ki/pclass/VectorProperty.h>
|
||||
#include <ki/serialization/BinarySerializer.h>
|
||||
#include <ki/serialization/JsonSerializer.h>
|
||||
#include "ki/pclass/Enum.h"
|
||||
|
||||
using namespace ki;
|
||||
|
||||
|
@ -42,11 +43,9 @@ struct Vector3D
|
|||
|
||||
bool operator==(const Vector3D &that) const
|
||||
{
|
||||
return (
|
||||
m_x == that.m_x,
|
||||
m_y == that.m_y,
|
||||
m_z == that.m_z
|
||||
);
|
||||
return m_x == that.m_x &&
|
||||
m_y == that.m_y &&
|
||||
m_z == that.m_z;
|
||||
}
|
||||
|
||||
void write_to(BitStream &stream) const
|
||||
|
@ -244,12 +243,14 @@ public:
|
|||
INIT_PROPERTY(float64, "double")
|
||||
INIT_PROPERTY(vector3d, "struct Vector3D")
|
||||
INIT_PROPERTY(int_ptr, "int")
|
||||
INIT_PROPERTY(value_object, "class NestedTestObjectA")
|
||||
INIT_PROPERTY(not_null_object, "class NestedTestObject")
|
||||
INIT_PROPERTY(null_object, "class NestedTestObject")
|
||||
INIT_PROPERTY(collection, "int")
|
||||
INIT_PROPERTY(ptr_collection, "int")
|
||||
INIT_PROPERTY(objects, "class NestedTestObject")
|
||||
INIT_PROPERTY(int_array, "int")
|
||||
INIT_PROPERTY(int_ptr_array, "int")
|
||||
INIT_PROPERTY(object, "class NestedTestObjectA")
|
||||
INIT_PROPERTY(object_ptr, "class NestedTestObject")
|
||||
INIT_PROPERTY(null_object_ptr, "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
|
||||
|
@ -282,21 +283,27 @@ public:
|
|||
// Test dereferencing when writing pointers to primitives
|
||||
pclass::StaticProperty<int *> int_ptr;
|
||||
|
||||
// Test writing a single instance of another object
|
||||
pclass::StaticProperty<NestedTestObjectA> value_object;
|
||||
pclass::StaticProperty<NestedTestObject *> not_null_object;
|
||||
pclass::StaticProperty<NestedTestObject *> null_object;
|
||||
// Test explicitly-sized array of primitives and pointers
|
||||
pclass::StaticProperty<int[5]> int_array;
|
||||
pclass::StaticProperty<int *[5]> int_ptr_array;
|
||||
|
||||
// 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
|
||||
pclass::VectorProperty<int> collection;
|
||||
pclass::VectorProperty<int *> ptr_collection;
|
||||
pclass::VectorProperty<int> int_vector;
|
||||
pclass::VectorProperty<int *> int_ptr_vector;
|
||||
|
||||
// Test writing multiple instances of another object
|
||||
pclass::VectorProperty<NestedTestObject *> objects;
|
||||
pclass::VectorProperty<NestedTestObject *> object_ptr_vector;
|
||||
};
|
||||
|
||||
// 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>();
|
||||
auto g_type_system = ki::make_unique<pclass::TypeSystem>(g_hash_calculator);
|
||||
bool g_types_defined = false;
|
||||
|
@ -338,13 +345,14 @@ void define_types()
|
|||
#define EXPECTED_uint32 0x0708090A
|
||||
#define EXPECTED_uint64 0x0B0C0D0E0F101112
|
||||
#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_float64 3.141592653589793115997963468544185161590576171875
|
||||
#define EXPECTED_vector3d Vector3D(24.0f, 61.0f, 3.62f)
|
||||
#define EXPECTED_int_ptr 52
|
||||
#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 IS_EXPECTED(object, identifier) object.identifier.get() == EXPECTED_##identifier
|
||||
|
||||
|
@ -373,21 +381,28 @@ void configure_test_object(TestObject &object)
|
|||
SET_EXPECTED(object, vector3d);
|
||||
object.int_ptr = new int(EXPECTED_int_ptr);
|
||||
|
||||
// Configure the collection of integers
|
||||
for (auto i = 0; i < EXPECTED_collection_size; ++i)
|
||||
// Configure the int array
|
||||
for (auto i = 0; i < EXPECTED_int_array_size; ++i)
|
||||
{
|
||||
object.collection.push_back(i);
|
||||
object.ptr_collection.push_back(new int(i));
|
||||
object.int_array[i] = 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
|
||||
object.value_object.get().extra_value = EXPECTED_value_object_extra_value;
|
||||
object.not_null_object = g_type_system->instantiate<NestedTestObject>("class NestedTestObject").release();
|
||||
object.null_object = nullptr;
|
||||
object.objects.push_back(
|
||||
object.object.get().extra_value = EXPECTED_value_object_extra_value;
|
||||
object.object_ptr = g_type_system->instantiate<NestedTestObject>("class NestedTestObject").release();
|
||||
object.null_object_ptr = nullptr;
|
||||
object.object_ptr_vector.push_back(
|
||||
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()
|
||||
);
|
||||
}
|
||||
|
@ -417,23 +432,32 @@ void validate_test_object(TestObject &object)
|
|||
REQUIRE(IS_EXPECTED(object, vector3d));
|
||||
REQUIRE(*object.int_ptr == EXPECTED_int_ptr);
|
||||
|
||||
// Validate both collections
|
||||
REQUIRE(object.collection.size() == EXPECTED_collection_size);
|
||||
REQUIRE(object.ptr_collection.size() == EXPECTED_collection_size);
|
||||
for (auto i = 0; i < EXPECTED_collection_size; i++)
|
||||
// Validate the int array
|
||||
REQUIRE(object.int_array.get_element_count() == EXPECTED_int_array_size);
|
||||
REQUIRE(object.int_ptr_array.get_element_count() == EXPECTED_int_array_size);
|
||||
for (auto i = 0; i < EXPECTED_int_array_size; i++)
|
||||
{
|
||||
REQUIRE(object.collection[i] == i);
|
||||
REQUIRE(*object.ptr_collection[i] == i);
|
||||
REQUIRE(object.int_array[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
|
||||
REQUIRE(object.value_object.get().extra_value == EXPECTED_value_object_extra_value);
|
||||
REQUIRE(object.not_null_object.get() != nullptr);
|
||||
REQUIRE(object.not_null_object.get()->get_kind() == NestedObjectKind::OBJECT);
|
||||
REQUIRE(object.null_object.get() == nullptr);
|
||||
REQUIRE(object.objects.size() == 2);
|
||||
REQUIRE(object.objects[0]->get_kind() == NestedObjectKind::OBJECT_A);
|
||||
REQUIRE(object.objects[1]->get_kind() == NestedObjectKind::OBJECT_B);
|
||||
REQUIRE(object.object.get().extra_value == EXPECTED_value_object_extra_value);
|
||||
REQUIRE(object.object_ptr.get() != nullptr);
|
||||
REQUIRE(object.object_ptr.get()->get_kind() == NestedObjectKind::OBJECT);
|
||||
REQUIRE(object.null_object_ptr.get() == nullptr);
|
||||
REQUIRE(object.object_ptr_vector.size() == 2);
|
||||
REQUIRE(object.object_ptr_vector[0]->get_kind() == NestedObjectKind::OBJECT_A);
|
||||
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")
|
||||
{
|
||||
serialization::BinarySerializer serializer(
|
||||
*g_type_system.get(), false,
|
||||
*g_type_system, false,
|
||||
serialization::BinarySerializer::flags::NONE
|
||||
);
|
||||
test_serializer(test_object, serializer, "regular");
|
||||
|
@ -588,7 +612,7 @@ TEST_CASE("Serialization tests", "[serialization]")
|
|||
SECTION("File format without compression")
|
||||
{
|
||||
serialization::BinarySerializer serializer(
|
||||
*g_type_system.get(), true,
|
||||
*g_type_system, true,
|
||||
serialization::BinarySerializer::flags::WRITE_SERIALIZER_FLAGS
|
||||
);
|
||||
test_serializer(test_object, serializer, "file");
|
||||
|
@ -596,7 +620,7 @@ TEST_CASE("Serialization tests", "[serialization]")
|
|||
SECTION("Regular format with compression")
|
||||
{
|
||||
serialization::BinarySerializer serializer(
|
||||
*g_type_system.get(), false,
|
||||
*g_type_system, false,
|
||||
serialization::BinarySerializer::flags::COMPRESSED
|
||||
);
|
||||
test_serializer(test_object, serializer, "regular_compressed");
|
||||
|
@ -604,7 +628,7 @@ TEST_CASE("Serialization tests", "[serialization]")
|
|||
SECTION("File format with compression")
|
||||
{
|
||||
serialization::BinarySerializer serializer(
|
||||
*g_type_system.get(), true,
|
||||
*g_type_system, true,
|
||||
serialization::BinarySerializer::flags::WRITE_SERIALIZER_FLAGS |
|
||||
serialization::BinarySerializer::flags::COMPRESSED
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue