mirror of https://github.com/SeanOMik/libki.git
pclass: Implement string primitives and class types
This commit is contained in:
parent
25d371b49f
commit
48aba1f0df
|
@ -25,11 +25,10 @@ namespace ki
|
||||||
virtual hash_t calculate_type_hash(const std::string &name) const = 0;
|
virtual hash_t calculate_type_hash(const std::string &name) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate a property hash from the property's name and type.
|
* Calculate a property hash from the property's name.
|
||||||
* @param name The name of the property.
|
* @param name The name of the property.
|
||||||
* @param type_hash The hash of the property's type.
|
|
||||||
*/
|
*/
|
||||||
virtual hash_t calculate_property_hash(const std::string& name, const hash_t type_hash) const = 0;
|
virtual hash_t calculate_property_hash(const std::string& name) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,7 +39,7 @@ namespace ki
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
hash_t calculate_type_hash(const std::string& name) const override;
|
hash_t calculate_type_hash(const std::string& name) const override;
|
||||||
hash_t calculate_property_hash(const std::string& name, const hash_t type_hash) const override;
|
hash_t calculate_property_hash(const std::string& name) const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
#pragma once
|
||||||
|
#include "ki/pclass/types/Type.h"
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
class PropertyClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
class PropertyBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PropertyBase(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type);
|
||||||
|
virtual ~PropertyBase() { }
|
||||||
|
|
||||||
|
std::string get_name() const;
|
||||||
|
hash_t get_name_hash() const;
|
||||||
|
hash_t get_full_hash() const;
|
||||||
|
const Type &get_type() const;
|
||||||
|
|
||||||
|
virtual bool is_pointer() const;
|
||||||
|
virtual bool is_dynamic() const;
|
||||||
|
|
||||||
|
virtual Value get_value() const = 0;
|
||||||
|
virtual const PropertyClass *get_object() const = 0;
|
||||||
|
|
||||||
|
virtual void write_value_to(BitStream &stream) const = 0;
|
||||||
|
virtual void read_value_from(BitStream &stream) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
hash_t m_name_hash;
|
||||||
|
hash_t m_full_hash;
|
||||||
|
const Type *m_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
class DynamicPropertyBase : public PropertyBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DynamicPropertyBase(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type);
|
||||||
|
virtual ~DynamicPropertyBase() {}
|
||||||
|
|
||||||
|
bool is_dynamic() const override;
|
||||||
|
virtual std::size_t get_element_count() const = 0;
|
||||||
|
|
||||||
|
Value get_value() const final override;
|
||||||
|
const PropertyClass *get_object() const final override;
|
||||||
|
void write_value_to(BitStream &stream) const final override;
|
||||||
|
void read_value_from(BitStream &stream) final override;
|
||||||
|
|
||||||
|
virtual Value get_value(int index) const = 0;
|
||||||
|
virtual const PropertyClass *get_object(int index) const = 0;
|
||||||
|
virtual void write_value_to(BitStream &stream, int index) const = 0;
|
||||||
|
virtual void read_value_from(BitStream &stream, int index) = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,24 +1,60 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "ki/pclass/types/Type.h"
|
||||||
|
#include "ki/pclass/PropertyList.h"
|
||||||
|
|
||||||
|
#define _KI_TYPE ki::pclass::Type
|
||||||
|
#define _KI_TYPE_SYSTEM ki::pclass::TypeSystem
|
||||||
|
#define _KI_PCLASS ki::pclass::PropertyClass
|
||||||
|
|
||||||
|
#define _KI_PCLASS_CONSTRUCTOR(derived) \
|
||||||
|
explicit derived(const _KI_TYPE &type, const _KI_TYPE_SYSTEM &type_system)
|
||||||
|
|
||||||
|
#define _KI_PCLASS_CONSTRUCT_BASE(base) \
|
||||||
|
: base(type, type_system)
|
||||||
|
|
||||||
|
#define DERIVED_PCLASS(derived, base) class derived : public base
|
||||||
|
#define PCLASS(n) DERIVED_PCLASS(n, _KI_PCLASS)
|
||||||
|
|
||||||
|
#define PCLASS_CONSTRUCTOR(derived) \
|
||||||
|
_KI_PCLASS_CONSTRUCTOR(derived) \
|
||||||
|
_KI_PCLASS_CONSTRUCT_BASE(_KI_PCLASS)
|
||||||
|
|
||||||
|
#define DERIVED_PCLASS_CONSTRUCTOR(derived, base) \
|
||||||
|
_KI_PCLASS_CONSTRUCTOR(derived) \
|
||||||
|
_KI_PCLASS_CONSTRUCT_BASE(base)
|
||||||
|
|
||||||
|
#define TYPE(n) type_system.get_type(n)
|
||||||
|
|
||||||
|
#define INIT_PROPERTY(identifier, type) \
|
||||||
|
, identifier(*this, #identifier, TYPE(type))
|
||||||
|
|
||||||
|
#define INIT_PROPERTY_VALUE(identifier, type, value) \
|
||||||
|
, identifier(*this, #identifier, TYPE(type), value)
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
namespace pclass
|
namespace pclass
|
||||||
{
|
{
|
||||||
class Type;
|
template <typename ValueT>
|
||||||
|
class ClassType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Documentation
|
* TODO: Documentation
|
||||||
*/
|
*/
|
||||||
class PropertyClass
|
class PropertyClass
|
||||||
{
|
{
|
||||||
explicit PropertyClass(const Type &type) : m_type(type) {}
|
public:
|
||||||
virtual ~PropertyClass() {};
|
explicit PropertyClass(const Type &type, const TypeSystem &type_system);
|
||||||
|
virtual ~PropertyClass();
|
||||||
|
|
||||||
const Type &get_type();
|
const Type &get_type() const;
|
||||||
|
|
||||||
|
PropertyList &get_properties();
|
||||||
|
const PropertyList &get_properties() const;
|
||||||
|
|
||||||
virtual void on_created();
|
|
||||||
private:
|
private:
|
||||||
const Type &m_type;
|
const Type *m_type;
|
||||||
|
PropertyList *m_properties;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include "ki/pclass/HashCalculator.h"
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
class PropertyBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
class PropertyList
|
||||||
|
{
|
||||||
|
friend PropertyBase;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using const_iterator = std::vector<PropertyBase *>::const_iterator;
|
||||||
|
|
||||||
|
std::size_t get_property_count() const;
|
||||||
|
|
||||||
|
bool has_property(const std::string &name) const;
|
||||||
|
bool has_property(hash_t hash) const;
|
||||||
|
|
||||||
|
const PropertyBase &get_property(int index) const;
|
||||||
|
const PropertyBase &get_property(const std::string &name) const;
|
||||||
|
const PropertyBase &get_property(hash_t hash) const;
|
||||||
|
|
||||||
|
const_iterator begin() const;
|
||||||
|
const_iterator end() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void add_property(PropertyBase *prop);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<PropertyBase *> m_properties;
|
||||||
|
std::map<std::string, PropertyBase *> m_property_name_lookup;
|
||||||
|
std::map<hash_t, PropertyBase *> m_property_hash_lookup;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,307 @@
|
||||||
|
#pragma once
|
||||||
|
#include "ki/pclass/Property.h"
|
||||||
|
#include "ki/util/exception.h"
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
// Forward declare StaticProperty<ValueT> for our helpers
|
||||||
|
template <typename ValueT>
|
||||||
|
class StaticProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper utility that provides the right implementation of construct()
|
||||||
|
* and get_object() based on characteristics of type: ValueT.
|
||||||
|
*/
|
||||||
|
template <
|
||||||
|
typename ValueT,
|
||||||
|
typename IsPointerEnable = void,
|
||||||
|
typename IsBaseEnable = void
|
||||||
|
>
|
||||||
|
struct value_object_helper
|
||||||
|
{
|
||||||
|
static ValueT construct(const Type &type)
|
||||||
|
{
|
||||||
|
// In cases where ValueT is not a pointer, and does not derive from PropertyClass,
|
||||||
|
// just call the default constructor.
|
||||||
|
return ValueT();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PropertyClass *get_object(const StaticProperty<ValueT> &prop)
|
||||||
|
{
|
||||||
|
// ValueT does not derive from PropertyClass, and so, this property is not
|
||||||
|
// storing an object.
|
||||||
|
throw runtime_error(
|
||||||
|
"Tried calling get_object() on a property that does not store an object."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialization for when ValueT is:
|
||||||
|
* - A pointer; but
|
||||||
|
* - does not derive from PropertyClass
|
||||||
|
*
|
||||||
|
* This should construct to a nullptr, and throw an exception
|
||||||
|
* when get_object()is called.
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
struct value_object_helper<
|
||||||
|
ValueT,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_pointer<ValueT>::value
|
||||||
|
>::type,
|
||||||
|
typename std::enable_if<
|
||||||
|
!std::is_base_of<
|
||||||
|
PropertyClass,
|
||||||
|
typename std::remove_pointer<ValueT>::type
|
||||||
|
>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
|
{
|
||||||
|
static ValueT construct(const Type &type)
|
||||||
|
{
|
||||||
|
// The default value of pointers is null
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PropertyClass *get_object(const StaticProperty<ValueT> &prop)
|
||||||
|
{
|
||||||
|
// ValueT does not derive from PropertyClass, and so, this property is not
|
||||||
|
// storing an object.
|
||||||
|
throw runtime_error(
|
||||||
|
"Tried calling get_object() on a property that does not store an object."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialization for when ValueT is:
|
||||||
|
* - A pointer; and
|
||||||
|
* - does derive from PropertyClass
|
||||||
|
*
|
||||||
|
* This should construct to a nullptr, and return a pointer to
|
||||||
|
* a ValueT instance (as a PropertyClass *) when get_object() is called.
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
struct value_object_helper<
|
||||||
|
ValueT,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_pointer<ValueT>::value
|
||||||
|
>::type,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_base_of<
|
||||||
|
PropertyClass,
|
||||||
|
typename std::remove_pointer<ValueT>::type
|
||||||
|
>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
|
{
|
||||||
|
static ValueT construct(const Type &type)
|
||||||
|
{
|
||||||
|
// The default value of pointers is null
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PropertyClass *get_object(const StaticProperty<ValueT> &prop)
|
||||||
|
{
|
||||||
|
// ValueT does derive from PropertyClass, and we have a pointer to an instance
|
||||||
|
// of ValueT, so we can cast down to a PropertyClass pointer.
|
||||||
|
return dynamic_cast<const PropertyClass *>(prop.m_value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialization for when ValueT is:
|
||||||
|
* - Not a pointer; and
|
||||||
|
* - does derive from PropertyClass
|
||||||
|
*
|
||||||
|
* This should construct an instance of ValueT by passing the property
|
||||||
|
* type and the type's type system, and return a pointer to a ValueT
|
||||||
|
* instance (as a PropertyClass *) when get_object() is called.
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
struct value_object_helper<
|
||||||
|
ValueT,
|
||||||
|
typename std::enable_if<
|
||||||
|
!std::is_pointer<ValueT>::value
|
||||||
|
>::type,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_base_of<
|
||||||
|
PropertyClass,
|
||||||
|
typename std::remove_pointer<ValueT>::type
|
||||||
|
>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
|
{
|
||||||
|
static ValueT construct(const Type &type)
|
||||||
|
{
|
||||||
|
// Derivitives of PropertyClass cannot have a default constructor since
|
||||||
|
// they require their Type and TypeSystem, so we need to pass these
|
||||||
|
// along from what the StaticProperty constructor has been given.
|
||||||
|
return ValueT(type, type.get_type_system());
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PropertyClass *get_object(const StaticProperty<ValueT> &prop)
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper utility that provides the right implementation of write() and read()
|
||||||
|
* based on whether ValueT is a pointer.
|
||||||
|
*/
|
||||||
|
template <
|
||||||
|
typename ValueT,
|
||||||
|
typename IsPointerEnable = void
|
||||||
|
>
|
||||||
|
struct value_rw_helper
|
||||||
|
{
|
||||||
|
static void write(const StaticProperty<ValueT> &prop, BitStream &stream)
|
||||||
|
{
|
||||||
|
prop.get_type().write_to(stream, prop.m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read(StaticProperty<ValueT> &prop, BitStream &stream)
|
||||||
|
{
|
||||||
|
prop.get_type().read_from(stream, Value(prop.m_value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialization for when ValueT is a pointer.
|
||||||
|
*
|
||||||
|
* Dereference the pointer before creating Value instances.
|
||||||
|
* This is so that the Value stores a pointer to a ValueT instance,
|
||||||
|
* rather than storing a pointer to a pointer.
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
struct value_rw_helper<
|
||||||
|
ValueT,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_pointer<ValueT>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
|
{
|
||||||
|
static void write(const StaticProperty<ValueT> &prop, BitStream &stream)
|
||||||
|
{
|
||||||
|
prop.get_type().write_to(stream, *prop.m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read(StaticProperty<ValueT> &prop, BitStream &stream)
|
||||||
|
{
|
||||||
|
prop.get_type().read_from(stream, Value(*prop.m_value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper utility that combines functions provided by value_object_helper
|
||||||
|
* and value_rw_helper into a single type.
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
struct value_helper
|
||||||
|
{
|
||||||
|
static ValueT construct(const Type &type)
|
||||||
|
{
|
||||||
|
return value_object_helper<ValueT>::construct(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PropertyClass *get_object(const StaticProperty<ValueT> &prop)
|
||||||
|
{
|
||||||
|
return value_object_helper<ValueT>::get_object(prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write(const StaticProperty<ValueT> &prop, BitStream &stream)
|
||||||
|
{
|
||||||
|
value_rw_helper<ValueT>::write(prop, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read(StaticProperty<ValueT> &prop, BitStream &stream)
|
||||||
|
{
|
||||||
|
value_rw_helper<ValueT>::read(prop, stream);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
class StaticProperty : public PropertyBase
|
||||||
|
{
|
||||||
|
// Allow helper utilities access to m_value
|
||||||
|
friend value_object_helper<ValueT>;
|
||||||
|
friend value_rw_helper<ValueT>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StaticProperty(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type)
|
||||||
|
: PropertyBase(object, name, type)
|
||||||
|
, m_value(value_helper<ValueT>::construct(type))
|
||||||
|
{}
|
||||||
|
|
||||||
|
StaticProperty(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type, ValueT value)
|
||||||
|
: PropertyBase(object, name, type)
|
||||||
|
{
|
||||||
|
m_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_dynamic() const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_pointer() const override
|
||||||
|
{
|
||||||
|
return std::is_pointer<ValueT>::value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_value_to(BitStream &stream) const override
|
||||||
|
{
|
||||||
|
value_helper<ValueT>::write(*this, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_value_from(BitStream &stream) override
|
||||||
|
{
|
||||||
|
value_helper<ValueT>::read(*this, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
const PropertyClass *get_object() const override
|
||||||
|
{
|
||||||
|
return value_helper<ValueT>::get_object(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueT &get()
|
||||||
|
{
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value get_value() const override
|
||||||
|
{
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator ValueT &() const
|
||||||
|
{
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueT *operator&() const
|
||||||
|
{
|
||||||
|
return &m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(const ValueT &value)
|
||||||
|
{
|
||||||
|
m_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ValueT m_value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "Type.h"
|
#include "ki/pclass/HashCalculator.h"
|
||||||
#include "PrimitiveType.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"
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
|
@ -14,52 +17,61 @@ namespace pclass
|
||||||
class TypeSystem
|
class TypeSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* @return A singleton instance of TypeSystem with all C++ primitives defined.
|
|
||||||
*/
|
|
||||||
static TypeSystem &get_singleton();
|
|
||||||
|
|
||||||
explicit TypeSystem(HashCalculator *hash_calculator);
|
explicit TypeSystem(HashCalculator *hash_calculator);
|
||||||
~TypeSystem();
|
~TypeSystem();
|
||||||
|
|
||||||
|
const HashCalculator &get_hash_calculator() const;
|
||||||
void set_hash_calculator(HashCalculator *hash_calculator);
|
void set_hash_calculator(HashCalculator *hash_calculator);
|
||||||
|
|
||||||
Type &get_type(const std::string &name) const;
|
bool has_type(const std::string &name) const;
|
||||||
Type &get_type(hash_t hash) const;
|
bool has_type(hash_t hash) const;
|
||||||
|
|
||||||
|
const Type &get_type(const std::string &name) const;
|
||||||
|
const Type &get_type(hash_t hash) const;
|
||||||
|
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
Type &define_primitive(const std::string &name)
|
PrimitiveType<ValueT> &define_primitive(const std::string &name)
|
||||||
{
|
{
|
||||||
auto hash = m_hash_calculator->calculate_type_hash(name);
|
auto *type = new PrimitiveType<ValueT>(name, *this);
|
||||||
auto *type = new PrimitiveType<ValueT>(name, hash);
|
|
||||||
define_type(type);
|
define_type(type);
|
||||||
return *type;
|
return *type;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ClassT>
|
template <class ClassT>
|
||||||
Type &define_class(const std::string &name)
|
ClassType<ClassT> &define_class(
|
||||||
|
const std::string &name, const Type *base_class = nullptr)
|
||||||
{
|
{
|
||||||
// Ensure that ClassT inherits PropertyClass
|
// If the caller does not specify a base class, automatically make
|
||||||
static_assert(std::is_base_of<PropertyClass, ClassT>::value, "ClassT must inherit PropertyClass!");
|
// ki::pclass::PropertyClass the base class (if it has been defined)
|
||||||
|
if (base_class == nullptr && has_type("class PropertyClass"))
|
||||||
|
base_class = &get_type("class PropertyClass");
|
||||||
|
|
||||||
// TODO: Create class types
|
auto *type = new ClassType<ClassT>(name, base_class, *this);
|
||||||
|
define_type(type);
|
||||||
|
return *type;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename EnumT>
|
template <typename EnumT>
|
||||||
Type &define_enum(const std::string &name)
|
EnumType<EnumT> *define_enum(const std::string &name)
|
||||||
{
|
{
|
||||||
// Ensure that EnumT is an enum
|
/*
|
||||||
static_assert(std::is_enum<EnumT>::value, "EnumT must be an enum!");
|
auto *type = new EnumType<EnumT>(name, this);
|
||||||
|
define_type(type);
|
||||||
|
return type;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Create enum types
|
template <typename ClassT>
|
||||||
|
ClassT *instantiate(const std::string &name) const
|
||||||
|
{
|
||||||
|
const auto &type = get_type(name);
|
||||||
|
return dynamic_cast<ClassT *>(type.instantiate());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void define_type(Type *type);
|
void define_type(Type *type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static TypeSystem *s_instance;
|
|
||||||
|
|
||||||
TypeList m_types;
|
TypeList m_types;
|
||||||
TypeNameMap m_type_name_lookup;
|
TypeNameMap m_type_name_lookup;
|
||||||
TypeHashMap m_type_hash_lookup;
|
TypeHashMap m_type_hash_lookup;
|
||||||
|
|
|
@ -16,7 +16,14 @@ namespace pclass
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Value(T &value)
|
Value(T &value)
|
||||||
{
|
{
|
||||||
m_value_ptr = value;
|
m_value_ptr = static_cast<void *>(&value);
|
||||||
|
m_type_hash = typeid(value).hash_code();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Value(const T &value)
|
||||||
|
{
|
||||||
|
m_value_ptr = const_cast<void *>(static_cast<const void *>(&value));
|
||||||
m_type_hash = typeid(value).hash_code();
|
m_type_hash = typeid(value).hash_code();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +51,7 @@ namespace pclass
|
||||||
// Make sure that this is allowed
|
// Make sure that this is allowed
|
||||||
if (!is<T>())
|
if (!is<T>())
|
||||||
throw std::runtime_error("Type mismatch in Value::get<T>() call.");
|
throw std::runtime_error("Type mismatch in Value::get<T>() call.");
|
||||||
return *(T *)m_value_ptr;
|
return *static_cast<T *>(m_value_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,7 +63,7 @@ namespace pclass
|
||||||
// Make sure that this is allowed
|
// Make sure that this is allowed
|
||||||
if (!is<T>())
|
if (!is<T>())
|
||||||
throw std::runtime_error("Type mismatch in Value::get<T>() call.");
|
throw std::runtime_error("Type mismatch in Value::get<T>() call.");
|
||||||
return *(T *)m_value_ptr;
|
return *static_cast<T *>(m_value_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
#include "ki/pclass/Property.h"
|
||||||
|
#include "ki/util/exception.h"
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
template <typename ValueT>
|
||||||
|
class VectorPropertyBase : public std::vector<ValueT>, public DynamicPropertyBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VectorPropertyBase(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type)
|
||||||
|
: DynamicPropertyBase(object, name, type) { }
|
||||||
|
|
||||||
|
std::size_t get_element_count() const override
|
||||||
|
{
|
||||||
|
return this->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Value get_value(int index) const override
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= this->size())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
return this->at(index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ValueT, typename Enable = void>
|
||||||
|
class VectorPropertyBase2 : public VectorPropertyBase<ValueT>
|
||||||
|
{
|
||||||
|
VectorPropertyBase2(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type)
|
||||||
|
: VectorPropertyBase<ValueT>(object, name, type) { }
|
||||||
|
|
||||||
|
constexpr bool is_pointer() const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_value_to(BitStream &stream, const int index) const override
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= this->size())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
this->get_type().write_to(stream, this->at(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_value_from(BitStream &stream, const int index) override
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= this->size())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
this->get_type().read_from(stream, this->at(index));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ValueT>
|
||||||
|
class VectorPropertyBase2<
|
||||||
|
ValueT,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_pointer<ValueT>::value
|
||||||
|
>::type
|
||||||
|
> : public VectorPropertyBase<ValueT>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VectorPropertyBase2(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type)
|
||||||
|
: VectorPropertyBase<ValueT>(object, name, type) { }
|
||||||
|
|
||||||
|
constexpr bool is_pointer() const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_value_to(BitStream &stream, const int index) const override
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= this->size())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
this->get_type().write_to(stream, *this->at(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_value_from(BitStream &stream, const int index) override
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= this->size())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
this->get_type().read_from(stream, Value(*this->at(index)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename ValueT,
|
||||||
|
typename _IsBaseEnable = void,
|
||||||
|
typename _IsPointerEnable = void
|
||||||
|
>
|
||||||
|
class VectorProperty : public VectorPropertyBase2<ValueT>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VectorProperty(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type)
|
||||||
|
: VectorPropertyBase2<ValueT>(object, name, type) { }
|
||||||
|
|
||||||
|
const PropertyClass *get_object(const int index) const override
|
||||||
|
{
|
||||||
|
// We aren't holding an object at all, whoever called this is mistaken.
|
||||||
|
throw runtime_error(
|
||||||
|
"Tried calling get_object(index) on a property that does not store an object."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ValueT>
|
||||||
|
class VectorProperty<
|
||||||
|
ValueT,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_base_of<
|
||||||
|
PropertyClass,
|
||||||
|
typename std::remove_pointer<ValueT>::type
|
||||||
|
>::value
|
||||||
|
>::type,
|
||||||
|
typename std::enable_if<
|
||||||
|
!std::is_pointer<ValueT>::value
|
||||||
|
>::type
|
||||||
|
> : public VectorPropertyBase2<ValueT>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VectorProperty(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type)
|
||||||
|
: VectorPropertyBase2<ValueT>(object, name, type) { }
|
||||||
|
|
||||||
|
const PropertyClass *get_object(const int index) const override
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= this->size())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
return dynamic_cast<PropertyClass *>(&this->at(index));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ValueT>
|
||||||
|
class VectorProperty<
|
||||||
|
ValueT,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_base_of<
|
||||||
|
PropertyClass,
|
||||||
|
typename std::remove_pointer<ValueT>::type
|
||||||
|
>::value
|
||||||
|
>::type,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_pointer<ValueT>::value
|
||||||
|
>::type
|
||||||
|
> : public VectorPropertyBase2<ValueT>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VectorProperty(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type)
|
||||||
|
: VectorPropertyBase2<ValueT>(object, name, type) { }
|
||||||
|
|
||||||
|
const PropertyClass *get_object(const int index) const override
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= this->size())
|
||||||
|
throw runtime_error("Index out of bounds.");
|
||||||
|
return dynamic_cast<PropertyClass *>(this->at(index));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
#pragma once
|
||||||
|
#include <type_traits>
|
||||||
|
#include <string>
|
||||||
|
#include "ki/pclass/Property.h"
|
||||||
|
#include "ki/pclass/types/Type.h"
|
||||||
|
#include "ki/pclass/PropertyClass.h"
|
||||||
|
#include "ki/util/exception.h"
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
class ClassTypeBase : public Type
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ClassTypeBase(const std::string &name,
|
||||||
|
const Type *base_class, const TypeSystem &type_system);
|
||||||
|
virtual ~ClassTypeBase() {}
|
||||||
|
|
||||||
|
bool inherits(const Type &type) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const ClassTypeBase *m_base_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
template <class ClassT>
|
||||||
|
class ClassType : public ClassTypeBase
|
||||||
|
{
|
||||||
|
// Ensure that ClassT inherits PropertyClass
|
||||||
|
static_assert(std::is_base_of<PropertyClass, ClassT>::value, "ClassT must inherit PropertyClass!");
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClassType(const std::string &name,
|
||||||
|
const Type *base_class, const TypeSystem &type_system)
|
||||||
|
: ClassTypeBase(name, base_class, type_system) {}
|
||||||
|
|
||||||
|
PropertyClass *instantiate() const override
|
||||||
|
{
|
||||||
|
return new ClassT(*this, get_type_system());
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_to(BitStream &stream, const Value &value) const override
|
||||||
|
{
|
||||||
|
const auto &object = dynamic_cast<const PropertyClass &>(value.get<ClassT>());
|
||||||
|
const auto &properties = object.get_properties();
|
||||||
|
for (auto it = properties.begin(); it != properties.end(); ++it)
|
||||||
|
(*it)->write_value_to(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_from(BitStream &stream, Value &value) const override
|
||||||
|
{
|
||||||
|
auto &object = dynamic_cast<PropertyClass &>(value.get<ClassT>());
|
||||||
|
auto &properties = object.get_properties();
|
||||||
|
for (auto it = properties.begin(); it != properties.end(); ++it)
|
||||||
|
(*it)->read_value_from(stream);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
#include <type_traits>
|
||||||
|
#include "ki/pclass/types/Type.h"
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
class EnumOption
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
uint32_t m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
template <typename EnumT>
|
||||||
|
class EnumType : public Type
|
||||||
|
{
|
||||||
|
// Ensure that EnumT is an enum
|
||||||
|
static_assert(std::is_enum<EnumT>::value, "EnumT must be an enum!");
|
||||||
|
|
||||||
|
public:
|
||||||
|
EnumType(std::string name, hash_t hash, TypeSystem *type_system);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,48 +4,52 @@
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
namespace pclass
|
namespace pclass
|
||||||
|
{
|
||||||
|
template <typename ValueT>
|
||||||
|
struct PrimitiveTypeWriter<
|
||||||
|
ValueT,
|
||||||
|
typename std::enable_if<std::is_floating_point<ValueT>::value>::type
|
||||||
|
>
|
||||||
{
|
{
|
||||||
template <typename ValueT>
|
static void write_to(BitStream &stream, const ValueT &value)
|
||||||
struct PrimitiveTypeWriter<
|
|
||||||
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 the reference as a reference to an integer
|
reinterpret_cast<const uint_type *>(&value)
|
||||||
const uint_type &v = *((const uint_type *)&value);
|
);
|
||||||
stream.write<uint_type>(v, bitsizeof<ValueT>::value);
|
stream.write<uint_type>(v, bitsizeof<ValueT>::value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* An unsigned integer type with the same size as the floating point type
|
* An unsigned integer type with the same size as the floating point type
|
||||||
* ValueT.
|
* ValueT.
|
||||||
*/
|
*/
|
||||||
using uint_type = typename bits<bitsizeof<ValueT>::value>::uint_type;
|
using uint_type = typename bits<bitsizeof<ValueT>::value>::uint_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
struct PrimitiveTypeReader<
|
struct PrimitiveTypeReader<
|
||||||
ValueT,
|
ValueT,
|
||||||
typename std::enable_if<std::is_floating_point<ValueT>::value>::type
|
typename std::enable_if<std::is_floating_point<ValueT>::value>::type
|
||||||
>
|
>
|
||||||
|
{
|
||||||
|
static void read_from(BitStream &stream, ValueT &value)
|
||||||
{
|
{
|
||||||
static void read_from(BitStream &stream, ValueT &value)
|
// Reinterpret the reference as a reference to an integer
|
||||||
{
|
uint_type &v = *(
|
||||||
// Reinterpret the reference as a reference to an integer
|
reinterpret_cast<uint_type *>(&value)
|
||||||
uint_type &v = *((uint_type *)&value);
|
);
|
||||||
v = stream.read<uint_type>(bitsizeof<ValueT>::value);
|
v = stream.read<uint_type>(bitsizeof<ValueT>::value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* An unsigned integer type with the same size as the floating point type
|
* An unsigned integer type with the same size as the floating point type
|
||||||
* ValueT.
|
* ValueT.
|
||||||
*/
|
*/
|
||||||
using uint_type = typename bits<bitsizeof<ValueT>::value>::uint_type;
|
using uint_type = typename bits<bitsizeof<ValueT>::value>::uint_type;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace pclass
|
||||||
{
|
{
|
||||||
static void write_to(BitStream &stream, const ValueT &value)
|
static void write_to(BitStream &stream, const ValueT &value)
|
||||||
{
|
{
|
||||||
stream.write<ValueT>(value, bitsizeof<ValueT>::value);
|
stream.write<ValueT>(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ namespace pclass
|
||||||
{
|
{
|
||||||
static void read_from(BitStream &stream, ValueT &value)
|
static void read_from(BitStream &stream, ValueT &value)
|
||||||
{
|
{
|
||||||
value = stream.read<ValueT>(bitsizeof<ValueT>::value);
|
value = stream.read<ValueT>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "ki/pclass/Type.h"
|
#include "ki/pclass/types/Type.h"
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
|
@ -44,8 +44,8 @@ namespace pclass
|
||||||
class PrimitiveType : public Type
|
class PrimitiveType : public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PrimitiveType(const std::string name, const hash_t hash)
|
PrimitiveType(const std::string name, const TypeSystem &type_system)
|
||||||
: Type(name, hash)
|
: Type(name, type_system)
|
||||||
{
|
{
|
||||||
m_kind = kind::PRIMITIVE;
|
m_kind = kind::PRIMITIVE;
|
||||||
}
|
}
|
||||||
|
@ -69,4 +69,5 @@ namespace pclass
|
||||||
|
|
||||||
// Include all template specializations
|
// Include all template specializations
|
||||||
#include "ki/pclass/types/IntegralPrimitiveType.h"
|
#include "ki/pclass/types/IntegralPrimitiveType.h"
|
||||||
#include "ki/pclass/types/FloatingPointPrimitiveType.h"
|
#include "ki/pclass/types/FloatingPointPrimitiveType.h"
|
||||||
|
#include "ki/pclass/types/StringPrimitiveType.h"
|
|
@ -0,0 +1,53 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
template <
|
||||||
|
typename _Elem,
|
||||||
|
typename _Traits,
|
||||||
|
typename _Alloc
|
||||||
|
>
|
||||||
|
struct PrimitiveTypeWriter<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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename _Elem,
|
||||||
|
typename _Traits,
|
||||||
|
typename _Alloc
|
||||||
|
>
|
||||||
|
struct PrimitiveTypeReader<std::basic_string<_Elem, _Traits, _Alloc>>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using type = std::basic_string<_Elem, _Traits, _Alloc>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void read_from(BitStream &stream, type &value)
|
||||||
|
{
|
||||||
|
// Read the length and create a new string with the correct capacity
|
||||||
|
auto length = stream.read<uint16_t>();
|
||||||
|
value = type(length, ' ');
|
||||||
|
|
||||||
|
// Read each character into the string
|
||||||
|
for (auto it = value.begin(); it != value.end(); ++it)
|
||||||
|
*it = stream.read<_Elem>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,42 +4,53 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "ki/pclass/HashCalculator.h"
|
#include "ki/pclass/HashCalculator.h"
|
||||||
#include "ki/pclass/Value.h"
|
#include "ki/pclass/Value.h"
|
||||||
#include "ki/pclass/PropertyClass.h"
|
|
||||||
#include "ki/util/BitStream.h"
|
#include "ki/util/BitStream.h"
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
namespace pclass
|
namespace pclass
|
||||||
{
|
{
|
||||||
|
class PropertyClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Documentation
|
* A base class for classes that represent a Type.
|
||||||
*/
|
*/
|
||||||
class Type
|
class Type
|
||||||
{
|
{
|
||||||
friend class TypeSystem;
|
friend class TypeSystem;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* TODO: Documentation
|
|
||||||
*/
|
|
||||||
enum class kind
|
enum class kind
|
||||||
{
|
{
|
||||||
NONE,
|
NONE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Type that contain pure, simple values.
|
||||||
|
*/
|
||||||
PRIMITIVE,
|
PRIMITIVE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A user-defined Type.
|
||||||
|
*/
|
||||||
CLASS,
|
CLASS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data type consisting of a set of named values.
|
||||||
|
*/
|
||||||
ENUM
|
ENUM
|
||||||
};
|
};
|
||||||
|
|
||||||
Type(std::string name, hash_t hash);
|
Type(const std::string &name, const TypeSystem &type_system);
|
||||||
virtual ~Type() {};
|
virtual ~Type() { }
|
||||||
|
|
||||||
std::string get_name() const;
|
std::string get_name() const;
|
||||||
hash_t get_hash() const;
|
hash_t get_hash() const;
|
||||||
kind get_kind() const;
|
kind get_kind() const;
|
||||||
|
const TypeSystem &get_type_system() const;
|
||||||
|
|
||||||
virtual PropertyClass *instantiate() const;
|
virtual PropertyClass *instantiate() const;
|
||||||
virtual void write_to(BitStream &stream, const Value &value) const = 0;
|
virtual void write_to(BitStream &stream, const Value &value) const;
|
||||||
virtual void read_from(BitStream &stream, Value &value) const = 0;
|
virtual void read_from(BitStream &stream, Value &value) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
kind m_kind;
|
kind m_kind;
|
||||||
|
@ -47,8 +58,13 @@ namespace pclass
|
||||||
private:
|
private:
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
hash_t m_hash;
|
hash_t m_hash;
|
||||||
|
const TypeSystem &m_type_system;
|
||||||
|
|
||||||
void set_hash(hash_t hash);
|
/**
|
||||||
|
* Called by a TypeSystem instance when it's HashCalculator
|
||||||
|
* is changed.
|
||||||
|
*/
|
||||||
|
virtual void update_hash();
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Type *> TypeList;
|
typedef std::vector<Type *> TypeList;
|
|
@ -0,0 +1,68 @@
|
||||||
|
#pragma once
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#define MAKE_FLAGS_ENUM(n) \
|
||||||
|
template <> \
|
||||||
|
struct ki::is_flags_enum<n> : std::true_type {}
|
||||||
|
|
||||||
|
#define SET_FLAG(v, f) v |= f
|
||||||
|
#define UNSET_FLAG(v, f) v &= ~f
|
||||||
|
#define FLAG_IS_SET(v, f) (v & f) == f
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
template <typename EnumT>
|
||||||
|
struct is_flags_enum : std::false_type {};
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename EnumT,
|
||||||
|
typename = typename std::enable_if<is_flags_enum<EnumT>::value>::type
|
||||||
|
>
|
||||||
|
constexpr EnumT operator|(EnumT lhs, EnumT rhs)
|
||||||
|
{
|
||||||
|
using type = typename std::underlying_type<EnumT>::type;
|
||||||
|
return static_cast<EnumT>(
|
||||||
|
static_cast<type>(lhs) | static_cast<type>(rhs)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename EnumT,
|
||||||
|
typename = typename std::enable_if<is_flags_enum<EnumT>::value>::type
|
||||||
|
>
|
||||||
|
constexpr EnumT operator&(EnumT lhs, EnumT rhs)
|
||||||
|
{
|
||||||
|
using type = typename std::underlying_type<EnumT>::type;
|
||||||
|
return static_cast<EnumT>(
|
||||||
|
static_cast<type>(lhs) & static_cast<type>(rhs)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename EnumT,
|
||||||
|
typename = typename std::enable_if<is_flags_enum<EnumT>::value>::type
|
||||||
|
>
|
||||||
|
constexpr EnumT operator~(EnumT lhs)
|
||||||
|
{
|
||||||
|
using type = typename std::underlying_type<EnumT>::type;
|
||||||
|
return static_cast<EnumT>(~static_cast<type>(lhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename EnumT,
|
||||||
|
typename = typename std::enable_if<is_flags_enum<EnumT>::value>::type
|
||||||
|
>
|
||||||
|
EnumT &operator|=(EnumT &lhs, EnumT rhs)
|
||||||
|
{
|
||||||
|
return lhs = lhs | rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename EnumT,
|
||||||
|
typename = typename std::enable_if<is_flags_enum<EnumT>::value>::type
|
||||||
|
>
|
||||||
|
EnumT &operator&=(EnumT &lhs, EnumT rhs)
|
||||||
|
{
|
||||||
|
return lhs = lhs & rhs;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
class runtime_error : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit runtime_error(const std::string &message)
|
||||||
|
: std::runtime_error(message) {}
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,6 +1,10 @@
|
||||||
target_sources(${PROJECT_NAME}
|
target_sources(${PROJECT_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
|
${PROJECT_SOURCE_DIR}/src/pclass/ClassType.cpp
|
||||||
${PROJECT_SOURCE_DIR}/src/pclass/HashCalculator.cpp
|
${PROJECT_SOURCE_DIR}/src/pclass/HashCalculator.cpp
|
||||||
|
${PROJECT_SOURCE_DIR}/src/pclass/Property.cpp
|
||||||
|
${PROJECT_SOURCE_DIR}/src/pclass/PropertyClass.cpp
|
||||||
|
${PROJECT_SOURCE_DIR}/src/pclass/PropertyList.cpp
|
||||||
${PROJECT_SOURCE_DIR}/src/pclass/Type.cpp
|
${PROJECT_SOURCE_DIR}/src/pclass/Type.cpp
|
||||||
${PROJECT_SOURCE_DIR}/src/pclass/TypeSystem.cpp
|
${PROJECT_SOURCE_DIR}/src/pclass/TypeSystem.cpp
|
||||||
)
|
)
|
|
@ -0,0 +1,44 @@
|
||||||
|
#include "ki/pclass/types/ClassType.h"
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
ClassTypeBase::ClassTypeBase(const std::string& name,
|
||||||
|
const Type* base_class, const TypeSystem& type_system)
|
||||||
|
: Type(name, type_system)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
throw runtime_error("base_class must be a class type!");
|
||||||
|
|
||||||
|
// Cast the base class up to a ClassTypeBase pointer
|
||||||
|
m_base_class = dynamic_cast<const ClassTypeBase *>(base_class);
|
||||||
|
if (!m_base_class)
|
||||||
|
throw runtime_error("base_class must inherit ClassTypeBase!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClassTypeBase::inherits(const Type &type) const
|
||||||
|
{
|
||||||
|
// Types do not technically inherit from themselves, but it is more useful
|
||||||
|
// if they report that they do since these checks are to make sure that objects
|
||||||
|
// have a common interface
|
||||||
|
if (&type == this)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If we have a base class, go down the inheritance tree and see if our
|
||||||
|
// ancestors inherit from the requested type
|
||||||
|
if (m_base_class)
|
||||||
|
return m_base_class->inherits(type);
|
||||||
|
|
||||||
|
// We've reached the bottom of the inheritance tree; there is no inheritance.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
#include "ki/pclass/HashCalculator.h"
|
#include "ki/pclass/HashCalculator.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
|
@ -35,16 +36,13 @@ namespace pclass
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
hash_t WizardHashCalculator::calculate_property_hash(const std::string& name, const hash_t type_hash) const
|
hash_t WizardHashCalculator::calculate_property_hash(const std::string& name) const
|
||||||
{
|
{
|
||||||
// Find the hash of the property name
|
// Find the hash of the property name
|
||||||
hash_t result = 0x1505;
|
hash_t result = 0x1505;
|
||||||
for (auto it = name.begin(); it != name.end(); ++it)
|
for (auto it = name.begin(); it != name.end(); ++it)
|
||||||
result = (0x21 * result) + *it;
|
result = (0x21 * result) + *it;
|
||||||
result &= 0x7FFFFFFF;
|
return result & 0x7FFFFFFF;
|
||||||
|
|
||||||
// Add the type hash onto it
|
|
||||||
return result + type_hash;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
#include "ki/pclass/Property.h"
|
||||||
|
#include "ki/pclass/PropertyClass.h"
|
||||||
|
#include "ki/pclass/TypeSystem.h"
|
||||||
|
#include "ki/util/exception.h"
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
PropertyBase::PropertyBase(PropertyClass &object,
|
||||||
|
const std::string &name, const Type &type)
|
||||||
|
{
|
||||||
|
m_name = name;
|
||||||
|
m_name_hash = type
|
||||||
|
.get_type_system()
|
||||||
|
.get_hash_calculator()
|
||||||
|
.calculate_property_hash(name);
|
||||||
|
m_full_hash = m_name_hash + type.get_hash();
|
||||||
|
m_type = &type;
|
||||||
|
|
||||||
|
// Add this property to the object's property list
|
||||||
|
object.get_properties().add_property(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PropertyBase::get_name() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_t PropertyBase::get_name_hash() const
|
||||||
|
{
|
||||||
|
return m_name_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_t PropertyBase::get_full_hash() const
|
||||||
|
{
|
||||||
|
return m_full_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type &PropertyBase::get_type() const
|
||||||
|
{
|
||||||
|
return *m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PropertyBase::is_pointer() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PropertyBase::is_dynamic() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicPropertyBase::DynamicPropertyBase(PropertyClass &object,
|
||||||
|
const std::string& name, const Type& type)
|
||||||
|
: PropertyBase(object, name, type) { }
|
||||||
|
|
||||||
|
bool DynamicPropertyBase::is_dynamic() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value DynamicPropertyBase::get_value() const
|
||||||
|
{
|
||||||
|
// The caller must specify an index
|
||||||
|
throw runtime_error("Called get_value() on a dynamic property. Use get_value(index) instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const PropertyClass *DynamicPropertyBase::get_object() const
|
||||||
|
{
|
||||||
|
// The caller must specify an index
|
||||||
|
throw runtime_error("Called get_object() on a dynamic property. Use get_object(index) instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertyBase::write_value_to(BitStream &stream) const
|
||||||
|
{
|
||||||
|
// The caller must specify an index
|
||||||
|
throw runtime_error("Called write_value_to() on a dynamic property. Use write_value_to(index) instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertyBase::read_value_from(BitStream &stream)
|
||||||
|
{
|
||||||
|
// The caller must specify an index
|
||||||
|
throw runtime_error("Called read_value_from() on a dynamic property. Use read_value_from(index) instead.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
#include "ki/pclass/PropertyClass.h"
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
PropertyClass::PropertyClass(const Type &type, const TypeSystem &type_system)
|
||||||
|
{
|
||||||
|
m_type = &type;
|
||||||
|
m_properties = new PropertyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyClass::~PropertyClass()
|
||||||
|
{
|
||||||
|
// Delete the list of properties
|
||||||
|
delete m_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type& PropertyClass::get_type() const
|
||||||
|
{
|
||||||
|
return *m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyList &PropertyClass::get_properties()
|
||||||
|
{
|
||||||
|
return *m_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PropertyList& PropertyClass::get_properties() const
|
||||||
|
{
|
||||||
|
return *m_properties;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
#include "ki/pclass/PropertyList.h"
|
||||||
|
#include "ki/pclass/Property.h"
|
||||||
|
#include "ki/util/exception.h"
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
std::size_t PropertyList::get_property_count() const
|
||||||
|
{
|
||||||
|
return m_properties.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PropertyList::has_property(const std::string& name) const
|
||||||
|
{
|
||||||
|
return m_property_name_lookup.find(name)
|
||||||
|
!= m_property_name_lookup.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PropertyList::has_property(const hash_t hash) const
|
||||||
|
{
|
||||||
|
return m_property_hash_lookup.find(hash)
|
||||||
|
!= m_property_hash_lookup.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const PropertyBase& PropertyList::get_property(const int index) const
|
||||||
|
{
|
||||||
|
if (index >= 0 && index < m_properties.size())
|
||||||
|
return *m_properties[index];
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Property index out of range. (index=" << index
|
||||||
|
<< ", size=" << m_properties.size() << ")";
|
||||||
|
throw runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
const PropertyBase& PropertyList::get_property(const std::string& name) const
|
||||||
|
{
|
||||||
|
const auto it = m_property_name_lookup.find(name);
|
||||||
|
if (it != m_property_name_lookup.end())
|
||||||
|
return *it->second;
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Could not find property with name: '" << name << "'.";
|
||||||
|
throw runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
const PropertyBase& PropertyList::get_property(const hash_t hash) const
|
||||||
|
{
|
||||||
|
const auto it = m_property_hash_lookup.find(hash);
|
||||||
|
if (it != m_property_hash_lookup.end())
|
||||||
|
return *it->second;
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Could not find property with hash: 0x"
|
||||||
|
<< std::hex << std::setw(8) << std::setfill('0')
|
||||||
|
<< std::uppercase << hash << ".";
|
||||||
|
throw runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyList::const_iterator PropertyList::begin() const
|
||||||
|
{
|
||||||
|
return m_properties.cbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyList::const_iterator PropertyList::end() const
|
||||||
|
{
|
||||||
|
return m_properties.cend();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertyList::add_property(PropertyBase *prop)
|
||||||
|
{
|
||||||
|
// Make sure a property with the same name as another isn't being added
|
||||||
|
if (has_property(prop->get_name()))
|
||||||
|
{
|
||||||
|
// This pointer is going to be lost, so delete it now
|
||||||
|
delete prop;
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "A property has already been added with name: '"
|
||||||
|
<< prop->get_name() << "'.";
|
||||||
|
throw runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for hash collisions
|
||||||
|
if (has_property(prop->get_full_hash()))
|
||||||
|
{
|
||||||
|
const auto &other = get_property(prop->get_full_hash());
|
||||||
|
|
||||||
|
// This pointer is going to be lost, so delete it now
|
||||||
|
delete prop;
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Cannot add property '" << prop->get_name() << "'. "
|
||||||
|
<< "Hash collision with property '" << other.get_name() << "'.";
|
||||||
|
throw runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the property to lookups
|
||||||
|
m_properties.push_back(prop);
|
||||||
|
m_property_name_lookup[prop->get_name()] = prop;
|
||||||
|
m_property_hash_lookup[prop->get_full_hash()] = prop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
#include "ki/pclass/Type.h"
|
#include "ki/pclass/types/Type.h"
|
||||||
|
#include "ki/pclass/TypeSystem.h"
|
||||||
|
#include "ki/util/exception.h"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
@ -6,10 +8,13 @@ namespace ki
|
||||||
{
|
{
|
||||||
namespace pclass
|
namespace pclass
|
||||||
{
|
{
|
||||||
Type::Type(const std::string name, const hash_t hash)
|
Type::Type(const std::string &name, const TypeSystem &type_system)
|
||||||
|
: m_type_system(type_system)
|
||||||
{
|
{
|
||||||
m_name = name;
|
m_name = name;
|
||||||
m_hash = hash;
|
m_hash = m_type_system
|
||||||
|
.get_hash_calculator()
|
||||||
|
.calculate_type_hash(name);
|
||||||
m_kind = kind::NONE;
|
m_kind = kind::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,11 +23,6 @@ namespace pclass
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Type::set_hash(const hash_t hash)
|
|
||||||
{
|
|
||||||
m_hash = hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
hash_t Type::get_hash() const
|
hash_t Type::get_hash() const
|
||||||
{
|
{
|
||||||
return m_hash;
|
return m_hash;
|
||||||
|
@ -33,11 +33,37 @@ namespace pclass
|
||||||
return m_kind;
|
return m_kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TypeSystem &Type::get_type_system() const
|
||||||
|
{
|
||||||
|
return m_type_system;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Type::write_to(BitStream& stream, const Value& value) const
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Type '" << m_name << "' does not implement Type::write_to.";
|
||||||
|
throw runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Type::read_from(BitStream& stream, Value& value) const
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Type '" << m_name << "' does not implement Type::read_from.";
|
||||||
|
throw runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
PropertyClass *Type::instantiate() const
|
PropertyClass *Type::instantiate() const
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Type '" << m_name << "' cannot be instantiated.";
|
oss << "Type '" << m_name << "' does not implement Type::instantiate.";
|
||||||
throw std::runtime_error(oss.str());
|
throw runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Type::update_hash()
|
||||||
|
{
|
||||||
|
m_hash = m_type_system
|
||||||
|
.get_hash_calculator()
|
||||||
|
.calculate_type_hash(m_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include "ki/pclass/TypeSystem.h"
|
#include "ki/pclass/TypeSystem.h"
|
||||||
|
#include "ki/util/BitTypes.h"
|
||||||
|
#include "ki/util/exception.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
|
@ -21,15 +23,7 @@ namespace ki
|
||||||
{
|
{
|
||||||
namespace pclass
|
namespace pclass
|
||||||
{
|
{
|
||||||
TypeSystem& TypeSystem::get_singleton()
|
TypeSystem::TypeSystem(HashCalculator *hash_calculator)
|
||||||
{
|
|
||||||
if (s_instance == nullptr)
|
|
||||||
// Create the static instance with the default hash calculator
|
|
||||||
s_instance = new TypeSystem(new WizardHashCalculator());
|
|
||||||
return *s_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeSystem::TypeSystem(HashCalculator* hash_calculator)
|
|
||||||
{
|
{
|
||||||
m_hash_calculator = hash_calculator;
|
m_hash_calculator = hash_calculator;
|
||||||
|
|
||||||
|
@ -69,8 +63,12 @@ namespace pclass
|
||||||
define_primitive<float>("float");
|
define_primitive<float>("float");
|
||||||
define_primitive<double>("double");
|
define_primitive<double>("double");
|
||||||
|
|
||||||
// TODO: Define bit floating point types
|
// Define string types
|
||||||
// TODO: Define string types
|
define_primitive<std::string>("std::string");
|
||||||
|
define_primitive<std::wstring>("std::wstring");
|
||||||
|
|
||||||
|
// Define the base class for all classes
|
||||||
|
define_class<PropertyClass>("class PropertyClass");
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeSystem::~TypeSystem()
|
TypeSystem::~TypeSystem()
|
||||||
|
@ -87,6 +85,15 @@ namespace pclass
|
||||||
delete m_hash_calculator;
|
delete m_hash_calculator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const HashCalculator &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;
|
||||||
|
}
|
||||||
|
|
||||||
void TypeSystem::set_hash_calculator(HashCalculator* hash_calculator)
|
void TypeSystem::set_hash_calculator(HashCalculator* hash_calculator)
|
||||||
{
|
{
|
||||||
// Update the hash calculator
|
// Update the hash calculator
|
||||||
|
@ -96,46 +103,47 @@ namespace pclass
|
||||||
m_type_hash_lookup.clear();
|
m_type_hash_lookup.clear();
|
||||||
for (auto it = m_types.begin(); it != m_types.end(); ++it)
|
for (auto it = m_types.begin(); it != m_types.end(); ++it)
|
||||||
{
|
{
|
||||||
// Calculate the new hash and update the type
|
|
||||||
auto *type = *it;
|
|
||||||
const auto new_hash = m_hash_calculator->calculate_type_hash(type->get_name());
|
|
||||||
type->set_hash(new_hash);
|
|
||||||
|
|
||||||
// Add the new hash to lookup
|
// Add the new hash to lookup
|
||||||
m_type_hash_lookup[new_hash] = type;
|
auto *type = *it;
|
||||||
|
type->update_hash();
|
||||||
// Is this type a class?
|
m_type_hash_lookup[type->get_hash()] = type;
|
||||||
if (type->get_kind() == Type::kind::CLASS)
|
|
||||||
{
|
|
||||||
// TODO: Recalculate property hashes
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type& TypeSystem::get_type(const std::string &name) const
|
bool TypeSystem::has_type(const std::string &name) const
|
||||||
|
{
|
||||||
|
return m_type_name_lookup.find(name) != m_type_name_lookup.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TypeSystem::has_type(const hash_t hash) const
|
||||||
|
{
|
||||||
|
return m_type_hash_lookup.find(hash) != m_type_hash_lookup.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type &TypeSystem::get_type(const std::string &name) const
|
||||||
{
|
{
|
||||||
const auto it = m_type_name_lookup.find(name);
|
const auto it = m_type_name_lookup.find(name);
|
||||||
if (it == m_type_name_lookup.end())
|
if (it == m_type_name_lookup.end())
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Could not find type with name '" << name << "'.";
|
oss << "Could not find type with name '" << name << "'.";
|
||||||
throw std::runtime_error(oss.str());
|
throw runtime_error(oss.str());
|
||||||
}
|
}
|
||||||
return *(it->second);
|
return *it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type& TypeSystem::get_type(const hash_t hash) const
|
const Type &TypeSystem::get_type(const hash_t hash) const
|
||||||
{
|
{
|
||||||
const auto it = m_type_hash_lookup.find(hash);
|
const auto it = m_type_hash_lookup.find(hash);
|
||||||
if (it == m_type_hash_lookup.end())
|
if (it == m_type_hash_lookup.end())
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Could not find type with hash: " <<
|
oss << "Could not find type with hash: 0x" <<
|
||||||
std::hex << std::setw(8) << std::setfill('0') <<
|
std::hex << std::setw(8) << std::setfill('0') <<
|
||||||
std::uppercase << hash << ".";
|
std::uppercase << hash << ".";
|
||||||
throw std::runtime_error(oss.str());
|
throw runtime_error(oss.str());
|
||||||
}
|
}
|
||||||
return *(it->second);
|
return *it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeSystem::define_type(Type *type)
|
void TypeSystem::define_type(Type *type)
|
||||||
|
@ -149,7 +157,7 @@ namespace pclass
|
||||||
// Throw an error
|
// Throw an error
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Type '" << type->get_name() << "' is already defined.";
|
oss << "Type '" << type->get_name() << "' is already defined.";
|
||||||
throw std::runtime_error(oss.str());
|
throw runtime_error(oss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does a type with this hash already exist?
|
// Does a type with this hash already exist?
|
||||||
|
@ -163,7 +171,7 @@ namespace pclass
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Type hash collision between '" << type->get_name()
|
oss << "Type hash collision between '" << type->get_name()
|
||||||
<< "' and '" << other_type.get_name() << "'.";
|
<< "' and '" << other_type.get_name() << "'.";
|
||||||
throw std::runtime_error(oss.str());
|
throw runtime_error(oss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// This type is safe to add to our lookups
|
// This type is safe to add to our lookups
|
||||||
|
|
Loading…
Reference in New Issue