diff --git a/src/Game/GameObject.cpp b/src/Game/GameObject.cpp index 42ab42b..5cd4f2c 100644 --- a/src/Game/GameObject.cpp +++ b/src/Game/GameObject.cpp @@ -11,10 +11,19 @@ GameObject::GameObject(Mono::Object managed_obj, GameObject *parent) : object_handle(managed_obj), parent(parent) {} -GameObject &GameObject::operator=(GameObject &&o){ +GameObject::GameObject(GameObject &&o) : + transform(o.transform), + components(std::move(o.components)), + object_handle(std::move(o.object_handle)), + parent(o.parent) +{ +} + +GameObject &GameObject::operator=(GameObject &&o){ transform = o.transform; components = std::move(o.components); object_handle = std::move(o.object_handle); + parent = o.parent; return *this; } diff --git a/src/Game/GameObject.hpp b/src/Game/GameObject.hpp index cbf8ec3..c815123 100644 --- a/src/Game/GameObject.hpp +++ b/src/Game/GameObject.hpp @@ -32,10 +32,15 @@ class GameObject { GameObject* parent; public: GameObject(Mono::Object managed_obj, GameObject* parent); + GameObject(const GameObject& o) = delete; + GameObject(GameObject&& o); GameObject& operator=(GameObject&& o); - inline Transform& getTransform(){ return transform; } + inline Transform& getTransform() { return transform; } + inline const Transform& getTransform() const { return transform; } + inline Mono::ObjectHandle& getObjectHandle() { return object_handle; } + inline const Mono::ObjectHandle& getObjectHandle() const { return object_handle; } bool tryGetComponent(const std::u16string& name, Component** out_component); bool tryAddComponent(const std::u16string& name, Component&& component); }; diff --git a/src/Game/GameObjectPool.cpp b/src/Game/GameObjectPool.cpp index 5a08b8a..e97935f 100644 --- a/src/Game/GameObjectPool.cpp +++ b/src/Game/GameObjectPool.cpp @@ -9,7 +9,7 @@ GameObjectPool::GameObjectPool(u32 size) first_unused_index = 0; buffer = new char[size*sizeof(GameObject)]; used_indices = new u64[size/64]; - std::memset(buffer, 0, size*sizeof(GameObject)); + // std::memset(buffer, 0, size*sizeof(GameObject)); std::memset(used_indices, 0, size/8); } @@ -26,7 +26,7 @@ GameObjectPool::~GameObjectPool() bool GameObjectPool::isIndexUsed(u32 index) { - return ( used_indices[index/64] & (1<<(index%64)) ) != 0; + return ( used_indices[index/64] & (u64(1)<<(index%64)) ) != 0; } u32 GameObjectPool::getNearestUnusedIndex(u32 startIndex) @@ -38,7 +38,7 @@ u32 GameObjectPool::getNearestUnusedIndex(u32 startIndex) u32 i = startIndex/64; // mark previous bits as used - u64 u = used_indices[i] | ( (1< GameObjectPool::put_new(GameObject&& new_obj) +std::pair GameObjectPool::emplace(GameObject&& new_obj) { u32 i = first_unused_index; - if(i == (u32)-1) + if(i == u32(-1)) throw UsefulException("can't put new GameObject to GameObjectPool because it's full"); GameObject& r = ( ((GameObject*)buffer)[i] = std::move(new_obj) ); - used_indices[i] |= 1<<(i%64); // mark index bit as used + used_indices[i/64] |= u64(1)<<(i%64); // mark index bit as used first_unused_index = getNearestUnusedIndex(i+1); return std::pair(i, r); } -void GameObjectPool::remove(u32 index) +void GameObjectPool::erase(u32 index) { if(index >= size) throw UsefulException(format("index %i is out of size %i", index, size)); if(!isIndexUsed(index)) throw UsefulException(format("there is no object at index %i", index)); ((GameObject*)buffer)[index].~GameObject(); - used_indices[index/64] ^= ~(1<<(index%64)); // mark index bit as unused + used_indices[index/64] &= ~(u64(1)<<(index%64)); // mark index bit as unused if(index < first_unused_index) first_unused_index = index; } diff --git a/src/Game/GameObjectPool.hpp b/src/Game/GameObjectPool.hpp index c6c91c5..fbd7aa5 100644 --- a/src/Game/GameObjectPool.hpp +++ b/src/Game/GameObjectPool.hpp @@ -1,5 +1,32 @@ #include "GameObject.hpp" +/* +Fixed array stkring deleted elements indices as bits in array of u64. +Fast emplace, erase and lookup. + +------------------------[construct]------------------------ +operation 'GameObjectPool::GameObjectPool()' took 1.0549 ms +operation 'other_collections_construct' took 0.0133 ms +-------------------------[emplace]------------------------- +operation 'GameObjectPool::emplace' took 8.0557 ms +operation 'vector::emplace_back' took 11.3735 ms +operation 'set::emplace' took 80.5633 ms +operation 'list::emplace_front' took 18.1442 ms +operation 'forward_list::emplace_front' took 11.5467 ms +--------------------------[erase]-------------------------- +operation 'GameObjectPool::erase' took 0.2745 ms +operation 'vector::erase' took 15790.6 ms +operation 'set::erase' took 1.2697 ms +operation 'list::erase_after' took 0.93 ms +operation 'forward_list::erase_after' took 1.1127 ms +-------------------------[iterate]------------------------- +operation 'GameObjectPool::iterate' took 1.1166 ms +operation 'vector::iterate' took 0.8883 ms +operation 'set::iterate' took 2.8011 ms +operation 'list::iterate' took 2.0766 ms +operation 'forward_list::iterate' took 2.0823 ms +*/ + class GameObjectPool { void* buffer; u64* used_indices; @@ -9,16 +36,14 @@ class GameObjectPool { bool isIndexUsed(u32 index); u32 getNearestUnusedIndex(u32 startIndex); u32 getNearestUsedIndex(u32 startIndex); - - friend class iterator; public: ///@param size must be a multiple of 64 GameObjectPool(u32 size); ~GameObjectPool(); GameObject& get(u32 index); - std::pair put_new(GameObject&& new_obj); - void remove(u32 index); + std::pair emplace(GameObject&& new_obj); + void erase(u32 index); class iterator { GameObjectPool* p; @@ -34,4 +59,6 @@ public: inline iterator begin() { return iterator(this, 0); } inline iterator end() { return iterator(this, -1); } + + friend class iterator; }; diff --git a/src/Mono/Mono.hpp b/src/Mono/Mono.hpp index 11001c1..67de32b 100644 --- a/src/Mono/Mono.hpp +++ b/src/Mono/Mono.hpp @@ -128,13 +128,12 @@ class ObjectHandle { Object object; u32 gc_handle; public: + inline ObjectHandle() : object(nullptr), gc_handle(0) {} inline ObjectHandle(Object obj) : object(obj) { gc_handle = mono_gchandle_new(obj, false); } inline ObjectHandle(const ObjectHandle& o) = delete; - inline ObjectHandle(ObjectHandle&& o) { - object = o.object; - gc_handle = o.gc_handle; - o.gc_handle = 0; - }; + inline ObjectHandle(ObjectHandle&& o) + : object(o.object), gc_handle(o.gc_handle) + { o.gc_handle = 0; }; inline ObjectHandle& operator=(ObjectHandle&& o) { object = o.object; gc_handle = o.gc_handle; @@ -142,7 +141,8 @@ public: return *this; }; inline ~ObjectHandle() { if(gc_handle) mono_gchandle_free(gc_handle); } - inline Object getObject() { return object; } + inline Object getObject() const { return object; } + inline u32 getGCHandle() const { return gc_handle; } }; } diff --git a/src/main.cpp b/src/main.cpp index 1d8be50..9d4f5a3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,11 +8,22 @@ #include "UsefulException.hpp" #include "Mono/Mono.hpp" #include "Game/GameObjectPool.hpp" -#include -#include using namespace ougge; +#define GAMEOBJECTPOOL_SIZE 64*1024 + +#define optime(N, LABEL, CODE) {\ + nsec_t b = getMonotonicTimeNsec();\ + for(u32 i = 0; i < (u32)N; i++) {\ + CODE ;\ + }\ + nsec_t e = getMonotonicTimeNsec();\ + nsec_t t = e-b;\ + std::cout<<"operation '"< updateCallbacks; void update(f64 deltaTime){ @@ -28,15 +39,16 @@ int main(int argc, const char** argv){ Mono::RuntimeJIT mono; std::cout<<"initialized mono jit runtime"<getClass("Ougge", "GameObject"); - for(int i = 0; i < 32*1024; i++){ + for(int i = 0; i < GAMEOBJECTPOOL_SIZE; i++){ Mono::Object gameObjectManaged = mono_object_new(mono.getDomain(), gameObjectClass); - p.put_new(GameObject(gameObjectManaged, nullptr)); + p.emplace(GameObject(gameObjectManaged, nullptr)); GameObject& o = p.get(0); - std::cout<<'['<