mirror of https://github.com/SeanOMik/libki.git
pclass: Start implementing TypeSystem
This commit is contained in:
parent
8f7d9bc896
commit
8fbb9ba906
|
@ -0,0 +1,46 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The type used to store a type/property hash.
|
||||||
|
*/
|
||||||
|
typedef uint32_t hash_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base class for type/property hash calculators.
|
||||||
|
*/
|
||||||
|
class HashCalculator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~HashCalculator() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate a type hash from the type's name.
|
||||||
|
* @param name The name of the type.
|
||||||
|
*/
|
||||||
|
virtual hash_t calculate_type_hash(const std::string &name) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate a property hash from the property's name and type.
|
||||||
|
* @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;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hash calculator that uses the algorithms found and used in
|
||||||
|
* Wizard101.
|
||||||
|
*/
|
||||||
|
class WizardHashCalculator : public HashCalculator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
class Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
class PropertyClass
|
||||||
|
{
|
||||||
|
explicit PropertyClass(const Type &type) : m_type(type) {}
|
||||||
|
virtual ~PropertyClass() {};
|
||||||
|
|
||||||
|
const Type &get_type();
|
||||||
|
|
||||||
|
virtual void on_created();
|
||||||
|
private:
|
||||||
|
const Type &m_type;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include "ki/pclass/HashCalculator.h"
|
||||||
|
#include "ki/pclass/Value.h"
|
||||||
|
#include "ki/pclass/PropertyClass.h"
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
class BitStream;
|
||||||
|
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
class Type
|
||||||
|
{
|
||||||
|
friend class TypeSystem;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
enum class kind
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
PRIMITIVE,
|
||||||
|
CLASS,
|
||||||
|
ENUM
|
||||||
|
};
|
||||||
|
|
||||||
|
Type(std::string name, hash_t hash);
|
||||||
|
virtual ~Type() {};
|
||||||
|
|
||||||
|
std::string get_name() const;
|
||||||
|
hash_t get_hash() const;
|
||||||
|
kind get_kind() const;
|
||||||
|
|
||||||
|
virtual PropertyClass *instantiate() const;
|
||||||
|
virtual void write_to(BitStream &stream, const Value &value) const = 0;
|
||||||
|
virtual void read_from(BitStream &stream, Value &value) const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
kind m_kind;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
hash_t m_hash;
|
||||||
|
|
||||||
|
void set_hash(hash_t hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<Type *> TypeList;
|
||||||
|
typedef std::map<std::string, Type *> TypeNameMap;
|
||||||
|
typedef std::map<hash_t, Type *> TypeHashMap;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include "Type.h"
|
||||||
|
#include "PrimitiveType.h"
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
class TypeSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @return A singleton instance of TypeSystem with all C++ primitives defined.
|
||||||
|
*/
|
||||||
|
static TypeSystem &get_singleton();
|
||||||
|
|
||||||
|
explicit TypeSystem(HashCalculator *hash_calculator);
|
||||||
|
~TypeSystem();
|
||||||
|
|
||||||
|
void set_hash_calculator(HashCalculator *hash_calculator);
|
||||||
|
|
||||||
|
Type &get_type(const std::string &name) const;
|
||||||
|
Type &get_type(hash_t hash) const;
|
||||||
|
|
||||||
|
template <typename ValueT>
|
||||||
|
Type &define_primitive(const std::string &name)
|
||||||
|
{
|
||||||
|
// TODO: Create primitive types
|
||||||
|
}
|
||||||
|
|
||||||
|
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!");
|
||||||
|
|
||||||
|
// TODO: Create class types
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename EnumT>
|
||||||
|
Type &define_enum(const std::string &name)
|
||||||
|
{
|
||||||
|
// Ensure that EnumT is an enum
|
||||||
|
static_assert(std::is_enum<EnumT>::value, "EnumT must be an enum!");
|
||||||
|
|
||||||
|
// TODO: Create enum types
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static TypeSystem *s_instance;
|
||||||
|
|
||||||
|
TypeList m_types;
|
||||||
|
TypeNameMap m_type_name_lookup;
|
||||||
|
TypeHashMap m_type_hash_lookup;
|
||||||
|
HashCalculator *m_hash_calculator;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
#pragma once
|
||||||
|
#include <utility>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <typeinfo>
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A wrapper around a void pointer that ensures type safety.
|
||||||
|
*/
|
||||||
|
class Value
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
Value(T &value)
|
||||||
|
{
|
||||||
|
m_value_ptr = value;
|
||||||
|
m_type_hash = typeid(value).hash_code();
|
||||||
|
}
|
||||||
|
|
||||||
|
Value(Value &&o) noexcept
|
||||||
|
: m_value_ptr(std::move(m_value_ptr))
|
||||||
|
, m_type_hash(std::move(o.m_type_hash))
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Whether or not the value being held is of type T.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
bool is() const
|
||||||
|
{
|
||||||
|
// Do the type hashes match?
|
||||||
|
return m_type_hash == typeid(T).hash_code();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A reference to the value being held as the specified type.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
const T &get() const
|
||||||
|
{
|
||||||
|
// Make sure that this is allowed
|
||||||
|
if (!is<T>())
|
||||||
|
throw std::runtime_error("Type mismatch in Value::get<T>() call.");
|
||||||
|
return *(T *)m_value_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A reference to the value being held as the specified type.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
T &get()
|
||||||
|
{
|
||||||
|
// Make sure that this is allowed
|
||||||
|
if (!is<T>())
|
||||||
|
throw std::runtime_error("Type mismatch in Value::get<T>() call.");
|
||||||
|
return *(T *)m_value_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void *m_value_ptr;
|
||||||
|
std::size_t m_type_hash;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
target_sources(${PROJECT_NAME}
|
||||||
|
PRIVATE
|
||||||
|
${PROJECT_SOURCE_DIR}/src/pclass/HashCalculator.cpp
|
||||||
|
${PROJECT_SOURCE_DIR}/src/pclass/Type.cpp
|
||||||
|
${PROJECT_SOURCE_DIR}/src/pclass/TypeSystem.cpp
|
||||||
|
)
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include "ki/pclass/HashCalculator.h"
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
hash_t WizardHashCalculator::calculate_type_hash(const std::string& name) const
|
||||||
|
{
|
||||||
|
// Declare variables
|
||||||
|
auto result = 0;
|
||||||
|
auto a = 0;
|
||||||
|
auto b = 32;
|
||||||
|
|
||||||
|
// Iterate through the characters in the string
|
||||||
|
for (auto it = name.begin(); it != name.end(); ++it)
|
||||||
|
{
|
||||||
|
result ^= (*it - 32) << a;
|
||||||
|
if (a > 24)
|
||||||
|
{
|
||||||
|
result ^= (*it - 32) >> b;
|
||||||
|
if (a >= 27)
|
||||||
|
{
|
||||||
|
a -= 32;
|
||||||
|
b += 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a += 5;
|
||||||
|
b -= 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the result an absolute value
|
||||||
|
if (result < 0)
|
||||||
|
result = -result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_t WizardHashCalculator::calculate_property_hash(const std::string& name, const hash_t type_hash) const
|
||||||
|
{
|
||||||
|
// Find the hash of the property name
|
||||||
|
hash_t result = 0x1505;
|
||||||
|
for (auto it = name.begin(); it != name.end(); ++it)
|
||||||
|
result = (0x21 * result) + *it;
|
||||||
|
result &= 0x7FFFFFFF;
|
||||||
|
|
||||||
|
// Add the type hash onto it
|
||||||
|
return result + type_hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
#include "ki/pclass/Type.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
namespace pclass
|
||||||
|
{
|
||||||
|
Type::Type(const std::string name, const hash_t hash)
|
||||||
|
{
|
||||||
|
m_name = name;
|
||||||
|
m_hash = hash;
|
||||||
|
m_kind = kind::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Type::get_name() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Type::set_hash(const hash_t hash)
|
||||||
|
{
|
||||||
|
m_hash = hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_t Type::get_hash() const
|
||||||
|
{
|
||||||
|
return m_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type::kind Type::get_kind() const
|
||||||
|
{
|
||||||
|
return m_kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyClass* Type::instantiate() const
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Type '" << m_name << "' cannot be instantiated.";
|
||||||
|
throw std::runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
#include "ki/pclass/TypeSystem.h"
|
||||||
|
#include <sstream>
|
||||||
|
#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)
|
||||||
|
|
||||||
|
namespace ki
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TypeSystem::~TypeSystem()
|
||||||
|
{
|
||||||
|
// Delete all type declarations
|
||||||
|
for (auto it = m_types.begin(); it != m_types.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
|
||||||
|
// Clear lookups
|
||||||
|
m_type_name_lookup.clear();
|
||||||
|
m_type_hash_lookup.clear();
|
||||||
|
|
||||||
|
// Delete the hash calculator
|
||||||
|
delete m_hash_calculator;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeSystem::set_hash_calculator(HashCalculator* hash_calculator)
|
||||||
|
{
|
||||||
|
// Update the hash calculator
|
||||||
|
m_hash_calculator = hash_calculator;
|
||||||
|
|
||||||
|
// Iterate through all types and recalculate their hash
|
||||||
|
m_type_hash_lookup.clear();
|
||||||
|
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
|
||||||
|
m_type_hash_lookup[new_hash] = type;
|
||||||
|
|
||||||
|
// Is this type a class?
|
||||||
|
if (type->get_kind() == Type::kind::CLASS)
|
||||||
|
{
|
||||||
|
// TODO: Recalculate property hashes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Type& TypeSystem::get_type(const std::string &name) const
|
||||||
|
{
|
||||||
|
const auto it = m_type_name_lookup.find(name);
|
||||||
|
if (it == m_type_name_lookup.end())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Could not find type with name '" << name << "'.";
|
||||||
|
throw std::runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
return *(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type& TypeSystem::get_type(const hash_t hash) const
|
||||||
|
{
|
||||||
|
const auto it = m_type_hash_lookup.find(hash);
|
||||||
|
if (it == m_type_hash_lookup.end())
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Could not find type with hash: " <<
|
||||||
|
std::hex << std::setw(8) << std::setfill('0') <<
|
||||||
|
std::uppercase << hash << ".";
|
||||||
|
throw std::runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
return *(it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <math.h>
|
#include <cmath>
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
|
@ -168,7 +168,7 @@ namespace ki
|
||||||
void BitStream::expand_buffer()
|
void BitStream::expand_buffer()
|
||||||
{
|
{
|
||||||
// Work out a new buffer size
|
// Work out a new buffer size
|
||||||
auto new_size = (2 << (uint64_t)log2(m_position.get_byte()) + 1) + 2;
|
auto new_size = (2 << (uint64_t)std::log2(m_position.get_byte()) + 1) + 2;
|
||||||
if (new_size < m_buffer_size)
|
if (new_size < m_buffer_size)
|
||||||
new_size = std::numeric_limits<size_t>::max();
|
new_size = std::numeric_limits<size_t>::max();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue