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)
|
||||
|
||||
add_subdirectory("src/dml")
|
||||
add_subdirectory("src/pclass")
|
||||
add_subdirectory("src/protocol")
|
||||
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/Value.h"
|
||||
#include "ki/pclass/PropertyClass.h"
|
||||
#include "ki/util/BitStream.h"
|
||||
|
||||
namespace ki
|
||||
{
|
||||
class BitStream;
|
||||
|
||||
namespace pclass
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -30,14 +30,17 @@ namespace pclass
|
|||
template <typename ValueT>
|
||||
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>
|
||||
Type &define_class(const std::string &name)
|
||||
{
|
||||
// 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
|
||||
}
|
||||
|
@ -51,6 +54,9 @@ namespace pclass
|
|||
// TODO: Create enum types
|
||||
}
|
||||
|
||||
protected:
|
||||
void define_type(Type *type);
|
||||
|
||||
private:
|
||||
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;
|
||||
}
|
||||
|
||||
PropertyClass* Type::instantiate() const
|
||||
PropertyClass *Type::instantiate() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Type '" << m_name << "' cannot be instantiated.";
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
#include <iomanip>
|
||||
|
||||
#define DEFINE_INTEGER_PRIMTIIVE(st, ut, n) \
|
||||
s_instance->define_primitive<st>(n); \
|
||||
s_instance->define_primitive<st>("signed " n); \
|
||||
s_instance->define_primitive<ut>("unsigned " n)
|
||||
define_primitive<st>(n); \
|
||||
define_primitive<st>("signed " n); \
|
||||
define_primitive<ut>("unsigned " n)
|
||||
|
||||
namespace ki
|
||||
{
|
||||
|
@ -14,54 +14,41 @@ namespace pclass
|
|||
TypeSystem& TypeSystem::get_singleton()
|
||||
{
|
||||
if (s_instance == nullptr)
|
||||
{
|
||||
// Create the static instance with the default hash calculator
|
||||
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;
|
||||
}
|
||||
|
||||
TypeSystem::TypeSystem(HashCalculator* 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()
|
||||
{
|
||||
|
@ -127,5 +114,39 @@ namespace pclass
|
|||
}
|
||||
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