pclass: Implement primitive types

This commit is contained in:
Joshua Scott 2018-10-26 01:00:13 +01:00
parent 8fbb9ba906
commit 73608ce23c
7 changed files with 177 additions and 47 deletions

View File

@ -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")

View File

@ -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"

View File

@ -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
{ {
/** /**

View File

@ -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;

View File

@ -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);
}
};
}
}

View File

@ -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.";

View File

@ -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;
}
} }
} }