Made ComponentPool copyable by making sure string fields are handled properly
This commit is contained in:
@@ -27,6 +27,7 @@ struct ComponentInfo
|
|||||||
std::string Name;
|
std::string Name;
|
||||||
std::unordered_map<std::string, Field_t> Fields;
|
std::unordered_map<std::string, Field_t> Fields;
|
||||||
std::vector<std::string> FieldsInOrder;
|
std::vector<std::string> FieldsInOrder;
|
||||||
|
std::vector<std::string> StringFields;
|
||||||
unsigned int Stride = 0;
|
unsigned int Stride = 0;
|
||||||
std::shared_ptr<char> Defaults = nullptr;
|
std::shared_ptr<char> Defaults = nullptr;
|
||||||
std::shared_ptr<Meta_t> Meta = nullptr;
|
std::shared_ptr<Meta_t> Meta = nullptr;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef ComponentPool_h__
|
#ifndef ComponentPool_h__
|
||||||
#define ComponentPool_h__
|
#define ComponentPool_h__
|
||||||
|
|
||||||
|
#include <set>
|
||||||
#include "MemoryPool.h"
|
#include "MemoryPool.h"
|
||||||
#include "ComponentInfo.h"
|
#include "ComponentInfo.h"
|
||||||
#include "ComponentWrapper.h"
|
#include "ComponentWrapper.h"
|
||||||
@@ -45,7 +46,8 @@ public:
|
|||||||
: m_ComponentInfo(ci)
|
: m_ComponentInfo(ci)
|
||||||
, m_Pool(ci.Meta->Allocation, sizeof(EntityID) + ci.Stride)
|
, m_Pool(ci.Meta->Allocation, sizeof(EntityID) + ci.Stride)
|
||||||
{ }
|
{ }
|
||||||
ComponentPool(const ComponentPool& other) = delete;
|
~ComponentPool();
|
||||||
|
ComponentPool(const ComponentPool& other);
|
||||||
ComponentPool(const ComponentPool&& other) = delete;
|
ComponentPool(const ComponentPool&& other) = delete;
|
||||||
|
|
||||||
const ::ComponentInfo& ComponentInfo() const { return m_ComponentInfo; }
|
const ::ComponentInfo& ComponentInfo() const { return m_ComponentInfo; }
|
||||||
|
|||||||
@@ -7,6 +7,23 @@
|
|||||||
#include "ComponentInfo.h"
|
#include "ComponentInfo.h"
|
||||||
#include "Util/Any.h"
|
#include "Util/Any.h"
|
||||||
|
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct ComponentField { };
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct ComponentField<T, typename std::enable_if<std::is_trivially_copyable<T>::value>::type>
|
||||||
|
{
|
||||||
|
static T& Get(const ComponentInfo::Field_t& info, char* data) { return *reinterpret_cast<T*>(data); }
|
||||||
|
static void Set(const ComponentInfo::Field_t& info, char* data, const T& value) { Get(data) = value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct ComponentField<std::string, void>
|
||||||
|
{
|
||||||
|
static std::string& Get(const ComponentInfo::Field_t& info, char* data) { return **reinterpret_cast<std::string**>(data); }
|
||||||
|
static void Set(const ComponentInfo::Field_t& info, char* data, const std::string& value) { Get(info, data) = value; }
|
||||||
|
};
|
||||||
|
|
||||||
struct ComponentWrapper
|
struct ComponentWrapper
|
||||||
{
|
{
|
||||||
ComponentWrapper(const ComponentInfo& componentInfo, char* data)
|
ComponentWrapper(const ComponentInfo& componentInfo, char* data)
|
||||||
@@ -47,7 +64,20 @@ struct ComponentWrapper
|
|||||||
|
|
||||||
void Copy(ComponentWrapper& destination)
|
void Copy(ComponentWrapper& destination)
|
||||||
{
|
{
|
||||||
memcpy(destination.Data, this->Data, Info.Stride);
|
// Copy trivial data
|
||||||
|
memcpy(destination.Data, Data, Info.Stride);
|
||||||
|
// Duplicate strings
|
||||||
|
SolidifyStrings(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When component data has been copied, strings need to be reconstructed or they'll refer to the same data!
|
||||||
|
static void SolidifyStrings(ComponentWrapper& component)
|
||||||
|
{
|
||||||
|
for (auto& name : component.Info.StringFields) {
|
||||||
|
std::size_t offset = component.Info.Fields.at(name).Offset;
|
||||||
|
auto& value = *reinterpret_cast<const std::string*>(component.Data + offset);
|
||||||
|
new (component.Data + offset) std::string(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SubscriptProxy
|
struct SubscriptProxy
|
||||||
@@ -94,44 +124,4 @@ private:
|
|||||||
boost::shared_array<char> m_DataReference;
|
boost::shared_array<char> m_DataReference;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Move this to Tests once entity importing is finished
|
|
||||||
class ComponentWrapperFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ComponentWrapperFactory() = default;
|
|
||||||
ComponentWrapperFactory(std::string componentTypeName, unsigned int allocation = 0)
|
|
||||||
{
|
|
||||||
m_ComponentInfo.Name = componentTypeName;
|
|
||||||
m_ComponentInfo.Meta->Allocation = allocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void AddProperty(std::string fieldName, T defaultValue)
|
|
||||||
{
|
|
||||||
m_DefaultValues.push_back(defaultValue);
|
|
||||||
m_ComponentInfo.Fields[fieldName].Type = typeid(T).name();
|
|
||||||
m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Stride;
|
|
||||||
m_ComponentInfo.Fields[fieldName].Stride = sizeof(T);
|
|
||||||
m_ComponentInfo.Stride += sizeof(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComponentInfo& Finalize()
|
|
||||||
{
|
|
||||||
m_ComponentInfo.Defaults = std::shared_ptr<char>(new char[m_ComponentInfo.Stride]);
|
|
||||||
std::size_t offset = 0;
|
|
||||||
for (auto& val : m_DefaultValues) {
|
|
||||||
memcpy(m_ComponentInfo.Defaults.get() + offset, val.Data.get(), val.Size);
|
|
||||||
offset += val.Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_ComponentInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator ComponentInfo&() { return Finalize(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
ComponentInfo m_ComponentInfo;
|
|
||||||
std::vector<Any> m_DefaultValues;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -66,9 +66,24 @@ public:
|
|||||||
, m_LowestAllocatedSlot(m_NumSlots)
|
, m_LowestAllocatedSlot(m_NumSlots)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
//We may get problems with memory being released
|
MemoryPool(const MemoryPool<T>& other)
|
||||||
//prematurely, etc. if we allow copies.
|
: m_StartAddress(new char[other.m_NumSlots*other.m_Stride])
|
||||||
MemoryPool(const MemoryPool<T>& other) = delete;
|
, m_SlotIsAllocated(other.m_NumSlots, false)
|
||||||
|
, m_NumSlots(other.m_NumSlots)
|
||||||
|
, m_Stride(other.m_Stride)
|
||||||
|
, m_NumAllocatedSlots(0)
|
||||||
|
, m_CurrentAllocSlot(0)
|
||||||
|
, m_LowestAllocatedSlot(m_NumSlots)
|
||||||
|
{
|
||||||
|
// Copy statically allocated pool
|
||||||
|
memcpy(m_StartAddress, other.m_StartAddress, m_NumSlots*m_Stride);
|
||||||
|
// Copy dynamically allocated memory
|
||||||
|
for (char* otherAddr : other.m_ExtraMemory) {
|
||||||
|
char* addr = (char*)malloc(m_Stride);
|
||||||
|
memcpy(addr, otherAddr, m_Stride);
|
||||||
|
m_ExtraMemory.push_back(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
MemoryPool(const MemoryPool<T>&& other) = delete;
|
MemoryPool(const MemoryPool<T>&& other) = delete;
|
||||||
|
|
||||||
//Free all memory that has been allocated.
|
//Free all memory that has been allocated.
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#include "Core/ComponentPool.h"
|
#include "Core/ComponentPool.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ComponentWrapper ComponentPoolForwardIterator::operator*() const
|
ComponentWrapper ComponentPoolForwardIterator::operator*() const
|
||||||
{
|
{
|
||||||
char* data = &(*m_MemoryPoolIterator);
|
char* data = &(*m_MemoryPoolIterator);
|
||||||
@@ -32,6 +30,28 @@ ComponentPoolForwardIterator& ComponentPoolForwardIterator::operator++()
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ComponentPool::ComponentPool(const ComponentPool& other)
|
||||||
|
: m_ComponentInfo(other.m_ComponentInfo)
|
||||||
|
, m_Pool(other.m_Pool)
|
||||||
|
{
|
||||||
|
// Duplicate strings
|
||||||
|
for (auto& name : m_ComponentInfo.StringFields) {
|
||||||
|
for (auto& c : *this) {
|
||||||
|
ComponentWrapper::SolidifyStrings(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComponentPool::~ComponentPool()
|
||||||
|
{
|
||||||
|
// Call std::string destructors
|
||||||
|
for (auto& name : m_ComponentInfo.StringFields) {
|
||||||
|
for (auto& c : *this) {
|
||||||
|
c.Field<std::string>(name).~basic_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//const ::ComponentInfo& ComponentPool::ComponentInfo() const
|
//const ::ComponentInfo& ComponentPool::ComponentInfo() const
|
||||||
//{
|
//{
|
||||||
// return m_ComponentInfo;
|
// return m_ComponentInfo;
|
||||||
@@ -39,10 +59,19 @@ ComponentPoolForwardIterator& ComponentPoolForwardIterator::operator++()
|
|||||||
|
|
||||||
ComponentWrapper ComponentPool::Allocate(EntityID entity)
|
ComponentWrapper ComponentPool::Allocate(EntityID entity)
|
||||||
{
|
{
|
||||||
|
// Allocate pool data
|
||||||
char* data = m_Pool.Allocate();
|
char* data = m_Pool.Allocate();
|
||||||
|
// Copy EntityID
|
||||||
memcpy(data, &entity, sizeof(EntityID));
|
memcpy(data, &entity, sizeof(EntityID));
|
||||||
|
|
||||||
m_EntityToComponent[entity] = data;
|
m_EntityToComponent[entity] = data;
|
||||||
return ComponentWrapper(m_ComponentInfo, data);
|
ComponentWrapper component(m_ComponentInfo, data);
|
||||||
|
|
||||||
|
// Copy defaults
|
||||||
|
memcpy(component.Data, m_ComponentInfo.Defaults.get(), m_ComponentInfo.Stride);
|
||||||
|
ComponentWrapper::SolidifyStrings(component);
|
||||||
|
|
||||||
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentWrapper ComponentPool::GetByEntity(EntityID ent)
|
ComponentWrapper ComponentPool::GetByEntity(EntityID ent)
|
||||||
|
|||||||
@@ -185,6 +185,9 @@ void EntityFilePreprocessor::parseComponentInfo()
|
|||||||
field.Offset = fieldOffset;
|
field.Offset = fieldOffset;
|
||||||
field.Stride = stride;
|
field.Stride = stride;
|
||||||
compInfo.FieldsInOrder.push_back(name);
|
compInfo.FieldsInOrder.push_back(name);
|
||||||
|
if (field.Type == "string") {
|
||||||
|
compInfo.StringFields.push_back(name);
|
||||||
|
}
|
||||||
fieldOffset += stride;
|
fieldOffset += stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ ComponentWrapper World::AttachComponent(EntityID entity, const std::string& comp
|
|||||||
ComponentWrapper c = pool->Allocate(entity);
|
ComponentWrapper c = pool->Allocate(entity);
|
||||||
// Write default values
|
// Write default values
|
||||||
memcpy(c.Data, ci.Defaults.get(), ci.Stride);
|
memcpy(c.Data, ci.Defaults.get(), ci.Stride);
|
||||||
|
ComponentWrapper::SolidifyStrings(c);
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user