mirror of https://github.com/SeanOMik/libki.git
pclass: Implement primitive types
This commit is contained in:
parent
8fbb9ba906
commit
73608ce23c
|
@ -21,6 +21,7 @@ target_include_directories(${PROJECT_NAME}
|
||||||
target_link_libraries(${PROJECT_NAME} RapidXML)
|
target_link_libraries(${PROJECT_NAME} RapidXML)
|
||||||
|
|
||||||
add_subdirectory("src/dml")
|
add_subdirectory("src/dml")
|
||||||
|
add_subdirectory("src/pclass")
|
||||||
add_subdirectory("src/protocol")
|
add_subdirectory("src/protocol")
|
||||||
add_subdirectory("src/util")
|
add_subdirectory("src/util")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
#pragma once
|
||||||
|
#include "ki/pclass/Type.h"
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
template <typename ValueT, typename Enable = void>
|
||||||
|
struct PrimitiveTypeWriter
|
||||||
|
{
|
||||||
|
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 PrimitiveTypeWriter::write_to"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
template <typename ValueT, typename Enable = void>
|
||||||
|
struct PrimitiveTypeReader
|
||||||
|
{
|
||||||
|
static void read_from(BitStream &stream, ValueT &value)
|
||||||
|
{
|
||||||
|
// Provide a compiler error if this is not specialized
|
||||||
|
static_assert(
|
||||||
|
sizeof(ValueT) == 0,
|
||||||
|
"Missing specialization of PrimitiveTypeReader::read_from"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
template <typename ValueT>
|
||||||
|
class PrimitiveType : public Type
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrimitiveType(const std::string name, const hash_t hash)
|
||||||
|
: Type(name, hash)
|
||||||
|
{
|
||||||
|
m_kind = kind::PRIMITIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_to(BitStream &stream, const Value &value) const override
|
||||||
|
{
|
||||||
|
if (!value.is<ValueT>())
|
||||||
|
throw std::runtime_error("Invalid call to Type::write_to -- value type does not match ValueT.");
|
||||||
|
PrimitiveTypeWriter<ValueT>::write_to(stream, value.get<ValueT>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_from(BitStream &stream, Value &value) const override
|
||||||
|
{
|
||||||
|
if (!value.is<ValueT>())
|
||||||
|
throw std::runtime_error("Invalid call to Type::read_from -- value type does not match ValueT.");
|
||||||
|
PrimitiveTypeReader<ValueT>::read_from(stream, value.get<ValueT>());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include all template specializations
|
||||||
|
#include "ki/pclass/types/IntegralPrimitiveType.h"
|
|
@ -5,11 +5,10 @@
|
||||||
#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/pclass/PropertyClass.h"
|
||||||
|
#include "ki/util/BitStream.h"
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
class BitStream;
|
|
||||||
|
|
||||||
namespace pclass
|
namespace pclass
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,14 +30,17 @@ namespace pclass
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
Type &define_primitive(const std::string &name)
|
Type &define_primitive(const std::string &name)
|
||||||
{
|
{
|
||||||
// TODO: Create primitive types
|
auto hash = m_hash_calculator->calculate_type_hash(name);
|
||||||
|
auto *type = new PrimitiveType<ValueT>(name, hash);
|
||||||
|
define_type(type);
|
||||||
|
return *type;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ClassT>
|
template <class ClassT>
|
||||||
Type &define_class(const std::string &name)
|
Type &define_class(const std::string &name)
|
||||||
{
|
{
|
||||||
// Ensure that ClassT inherits PropertyClass
|
// Ensure that ClassT inherits PropertyClass
|
||||||
static_assert(std::is_base_of<Object, ClassT>::value, "ClassT must inherit PropertyClass!");
|
static_assert(std::is_base_of<PropertyClass, ClassT>::value, "ClassT must inherit PropertyClass!");
|
||||||
|
|
||||||
// TODO: Create class types
|
// TODO: Create class types
|
||||||
}
|
}
|
||||||
|
@ -51,6 +54,9 @@ namespace pclass
|
||||||
// TODO: Create enum types
|
// TODO: Create enum types
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void define_type(Type *type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static TypeSystem *s_instance;
|
static TypeSystem *s_instance;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
template <typename ValueT>
|
||||||
|
struct PrimitiveTypeWriter<
|
||||||
|
ValueT,
|
||||||
|
typename std::enable_if<std::is_integral<ValueT>::value>::type
|
||||||
|
>
|
||||||
|
{
|
||||||
|
static void write_to(BitStream &stream, const ValueT &value)
|
||||||
|
{
|
||||||
|
stream.write<ValueT>(value, sizeof(ValueT) * 8);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ValueT>
|
||||||
|
struct PrimitiveTypeReader<
|
||||||
|
ValueT,
|
||||||
|
typename std::enable_if<std::is_integral<ValueT>::value>::type
|
||||||
|
>
|
||||||
|
{
|
||||||
|
static void read_from(BitStream &stream, ValueT &value)
|
||||||
|
{
|
||||||
|
value = stream.read<ValueT>(sizeof(ValueT) * 8);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ namespace pclass
|
||||||
return m_kind;
|
return m_kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 << "' cannot be instantiated.";
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
#define DEFINE_INTEGER_PRIMTIIVE(st, ut, n) \
|
#define DEFINE_INTEGER_PRIMTIIVE(st, ut, n) \
|
||||||
s_instance->define_primitive<st>(n); \
|
define_primitive<st>(n); \
|
||||||
s_instance->define_primitive<st>("signed " n); \
|
define_primitive<st>("signed " n); \
|
||||||
s_instance->define_primitive<ut>("unsigned " n)
|
define_primitive<ut>("unsigned " n)
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
|
@ -14,54 +14,41 @@ namespace pclass
|
||||||
TypeSystem& TypeSystem::get_singleton()
|
TypeSystem& TypeSystem::get_singleton()
|
||||||
{
|
{
|
||||||
if (s_instance == nullptr)
|
if (s_instance == nullptr)
|
||||||
{
|
|
||||||
// Create the static instance with the default hash calculator
|
// Create the static instance with the default hash calculator
|
||||||
s_instance = new TypeSystem(new WizardHashCalculator());
|
s_instance = new TypeSystem(new WizardHashCalculator());
|
||||||
|
|
||||||
// Define integer types
|
|
||||||
s_instance->define_primitive<bool>("bool");
|
|
||||||
DEFINE_INTEGER_PRIMTIIVE(int8_t, uint8_t, "char");
|
|
||||||
DEFINE_INTEGER_PRIMTIIVE(int8_t, uint8_t, "__int8");
|
|
||||||
s_instance->define_primitive<int8_t>("int8_t");
|
|
||||||
s_instance->define_primitive<uint8_t>("uint8_t");
|
|
||||||
|
|
||||||
DEFINE_INTEGER_PRIMTIIVE(int16_t, uint16_t, "short");
|
|
||||||
DEFINE_INTEGER_PRIMTIIVE(int16_t, uint16_t, "__int16");
|
|
||||||
s_instance->define_primitive<int16_t>("int16_t");
|
|
||||||
s_instance->define_primitive<uint16_t>("uint16_t");
|
|
||||||
|
|
||||||
DEFINE_INTEGER_PRIMTIIVE(int32_t, uint32_t, "int");
|
|
||||||
DEFINE_INTEGER_PRIMTIIVE(int32_t, uint32_t, "__int32");
|
|
||||||
s_instance->define_primitive<int32_t>("int32_t");
|
|
||||||
s_instance->define_primitive<uint32_t>("uint32_t");
|
|
||||||
|
|
||||||
DEFINE_INTEGER_PRIMTIIVE(int64_t, uint64_t, "long");
|
|
||||||
DEFINE_INTEGER_PRIMTIIVE(int64_t, uint64_t, "__int64");
|
|
||||||
s_instance->define_primitive<int64_t>("int64_t");
|
|
||||||
s_instance->define_primitive<uint64_t>("uint64_t");
|
|
||||||
s_instance->define_primitive<uint64_t>("gid");
|
|
||||||
|
|
||||||
// TODO: Define bit integer types
|
|
||||||
|
|
||||||
// Define floating point types
|
|
||||||
s_instance->define_primitive<float>("float");
|
|
||||||
s_instance->define_primitive<double>("double");
|
|
||||||
|
|
||||||
// TODO: Define bit floating point types
|
|
||||||
|
|
||||||
// Define string types
|
|
||||||
s_instance->define_primitive<std::string>("std::string");
|
|
||||||
s_instance->define_primitive<std::wstring>("std::wstring");
|
|
||||||
}
|
|
||||||
|
|
||||||
return *s_instance;
|
return *s_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeSystem::TypeSystem(HashCalculator* hash_calculator)
|
TypeSystem::TypeSystem(HashCalculator* hash_calculator)
|
||||||
{
|
{
|
||||||
m_hash_calculator = hash_calculator;
|
m_hash_calculator = hash_calculator;
|
||||||
}
|
|
||||||
|
|
||||||
|
// Pre-define C++ primitive types
|
||||||
|
// Define integer types
|
||||||
|
define_primitive<bool>("bool");
|
||||||
|
DEFINE_INTEGER_PRIMTIIVE(int8_t, uint8_t, "char");
|
||||||
|
DEFINE_INTEGER_PRIMTIIVE(int8_t, uint8_t, "__int8");
|
||||||
|
define_primitive<int8_t>("int8_t");
|
||||||
|
define_primitive<uint8_t>("uint8_t");
|
||||||
|
DEFINE_INTEGER_PRIMTIIVE(int16_t, uint16_t, "short");
|
||||||
|
DEFINE_INTEGER_PRIMTIIVE(int16_t, uint16_t, "__int16");
|
||||||
|
define_primitive<int16_t>("int16_t");
|
||||||
|
define_primitive<uint16_t>("uint16_t");
|
||||||
|
DEFINE_INTEGER_PRIMTIIVE(int32_t, uint32_t, "int");
|
||||||
|
DEFINE_INTEGER_PRIMTIIVE(int32_t, uint32_t, "__int32");
|
||||||
|
define_primitive<int32_t>("int32_t");
|
||||||
|
define_primitive<uint32_t>("uint32_t");
|
||||||
|
DEFINE_INTEGER_PRIMTIIVE(int64_t, uint64_t, "long");
|
||||||
|
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");
|
||||||
|
|
||||||
|
// TODO: Define bit integer types
|
||||||
|
// TODO: Define floating point types
|
||||||
|
// TODO: Define bit floating point types
|
||||||
|
// TODO: Define string types
|
||||||
|
}
|
||||||
|
|
||||||
TypeSystem::~TypeSystem()
|
TypeSystem::~TypeSystem()
|
||||||
{
|
{
|
||||||
|
@ -127,5 +114,39 @@ namespace pclass
|
||||||
}
|
}
|
||||||
return *(it->second);
|
return *(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TypeSystem::define_type(Type *type)
|
||||||
|
{
|
||||||
|
// Does a type with this name already exist?
|
||||||
|
if (m_type_name_lookup.find(type->get_name()) != m_type_name_lookup.end())
|
||||||
|
{
|
||||||
|
// This pointer will become lost since it isn't being added to the lookups.
|
||||||
|
delete type;
|
||||||
|
|
||||||
|
// Throw an error
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Type '" << type->get_name() << "' is already defined.";
|
||||||
|
throw std::runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does a type with this hash already exist?
|
||||||
|
if (m_type_name_lookup.find(type->get_name()) != m_type_name_lookup.end())
|
||||||
|
{
|
||||||
|
// This pointer will become lost since it isn't being added to the lookups.
|
||||||
|
delete type;
|
||||||
|
|
||||||
|
// Throw an error
|
||||||
|
auto &other_type = get_type(type->get_hash());
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Type hash collision between '" << type->get_name()
|
||||||
|
<< "' and '" << other_type.get_name() << "'.";
|
||||||
|
throw std::runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// This type is safe to add to our lookups
|
||||||
|
m_types.push_back(type);
|
||||||
|
m_type_name_lookup[type->get_name()] = type;
|
||||||
|
m_type_hash_lookup[type->get_hash()] = type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue