Compare commits
32 commits
Author | SHA1 | Date | |
---|---|---|---|
Stephen Seo | b7117c09b3 | ||
Stephen Seo | f6fa8a6173 | ||
Stephen Seo | 107c1094c9 | ||
Stephen Seo | 7894955ff5 | ||
Stephen Seo | bc23918637 | ||
Stephen Seo | 6a4be98216 | ||
Stephen Seo | 3e6fd6c1a5 | ||
Stephen Seo | b2cd215faf | ||
Stephen Seo | f009ef1135 | ||
Stephen Seo | 56d7ddd3ba | ||
Stephen Seo | 0a7929b0a4 | ||
Stephen Seo | 60f35e8270 | ||
Stephen Seo | 9732ac80bd | ||
Stephen Seo | cfccb5f863 | ||
Stephen Seo | dd83a492c8 | ||
Stephen Seo | 4752a67380 | ||
Stephen Seo | eca91d3670 | ||
Stephen Seo | 5baa4e92b7 | ||
Stephen Seo | 39500e1fdc | ||
Stephen Seo | 12ea26a69a | ||
Stephen Seo | 8d44b8e2bc | ||
Stephen Seo | af12aa577b | ||
Stephen Seo | 155df42657 | ||
Stephen Seo | bfd5dba0b2 | ||
Stephen Seo | 481f223c7d | ||
Stephen Seo | 20df53837b | ||
Stephen Seo | eb638f325e | ||
Stephen Seo | 95697ae7b6 | ||
Stephen Seo | f6dbe5414e | ||
Stephen Seo | 5f1e6f1b5a | ||
Stephen Seo | 25c864dd8a | ||
Stephen Seo | f59f78385d |
|
@ -35,7 +35,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
|
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -D NDEBUG")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -D NDEBUG")
|
||||||
|
|
||||||
target_compile_features(EntityComponentSystem INTERFACE cxx_std_14)
|
target_compile_features(EntityComponentSystem INTERFACE cxx_std_17)
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||||
message(STATUS "Setting build type to 'Debug', none was specified.")
|
message(STATUS "Setting build type to 'Debug', none was specified.")
|
||||||
|
@ -59,7 +59,7 @@ if(GTEST_FOUND)
|
||||||
add_executable(UnitTests ${UnitTests_SOURCES})
|
add_executable(UnitTests ${UnitTests_SOURCES})
|
||||||
target_link_libraries(UnitTests EntityComponentSystem ${GTEST_LIBRARIES})
|
target_link_libraries(UnitTests EntityComponentSystem ${GTEST_LIBRARIES})
|
||||||
target_include_directories(UnitTests PUBLIC ${GTEST_INCLUDE_DIR})
|
target_include_directories(UnitTests PUBLIC ${GTEST_INCLUDE_DIR})
|
||||||
target_compile_features(UnitTests PUBLIC cxx_std_14)
|
target_compile_features(UnitTests PUBLIC cxx_std_17)
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_test(NAME UnitTests COMMAND UnitTests)
|
add_test(NAME UnitTests COMMAND UnitTests)
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace EC
|
||||||
Bitset<ComponentsList, TagsList> bitset;
|
Bitset<ComponentsList, TagsList> bitset;
|
||||||
|
|
||||||
EC::Meta::forEach<Contents>([&bitset] (auto t) {
|
EC::Meta::forEach<Contents>([&bitset] (auto t) {
|
||||||
if(EC::Meta::Contains<decltype(t), Combined>::value)
|
if constexpr (EC::Meta::Contains<decltype(t), Combined>::value)
|
||||||
{
|
{
|
||||||
bitset[EC::Meta::IndexOf<decltype(t), Combined>::value] =
|
bitset[EC::Meta::IndexOf<decltype(t), Combined>::value] =
|
||||||
true;
|
true;
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
#include "Meta/Combine.hpp"
|
#include "Meta/Combine.hpp"
|
||||||
#include "Meta/ForEachDoubleTuple.hpp"
|
#include "Meta/ForEachDoubleTuple.hpp"
|
||||||
#include "Meta/ForEachWithIndex.hpp"
|
#include "Meta/ForEachWithIndex.hpp"
|
||||||
#include "Meta/IndexOf.hpp"
|
|
||||||
#include "Meta/Matching.hpp"
|
#include "Meta/Matching.hpp"
|
||||||
#include "ThreadPool.hpp"
|
#include "ThreadPool.hpp"
|
||||||
|
|
||||||
|
@ -81,7 +80,7 @@ struct Manager {
|
||||||
|
|
||||||
template <typename... Types>
|
template <typename... Types>
|
||||||
struct Storage {
|
struct Storage {
|
||||||
using type = std::tuple<std::deque<Types>..., std::deque<char> >;
|
using type = std::tuple<std::deque<Types>...>;
|
||||||
};
|
};
|
||||||
using ComponentsStorage =
|
using ComponentsStorage =
|
||||||
typename EC::Meta::Morph<ComponentsList, Storage<> >::type;
|
typename EC::Meta::Morph<ComponentsList, Storage<> >::type;
|
||||||
|
@ -194,7 +193,7 @@ struct Manager {
|
||||||
*/
|
*/
|
||||||
Manager() : threadPool{}, idStackCounter(0) {
|
Manager() : threadPool{}, idStackCounter(0) {
|
||||||
resize(EC_INIT_ENTITIES_SIZE);
|
resize(EC_INIT_ENTITIES_SIZE);
|
||||||
if (ThreadCount >= 2) {
|
if constexpr (ThreadCount >= 2) {
|
||||||
threadPool = std::make_unique<ThreadPool<ThreadCount> >();
|
threadPool = std::make_unique<ThreadPool<ThreadCount> >();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,14 +359,9 @@ struct Manager {
|
||||||
*/
|
*/
|
||||||
template <typename Component>
|
template <typename Component>
|
||||||
Component* getEntityData(const std::size_t& index) {
|
Component* getEntityData(const std::size_t& index) {
|
||||||
constexpr auto componentIndex =
|
if constexpr (EC::Meta::Contains<Component, Components>::value) {
|
||||||
EC::Meta::IndexOf<Component, Components>::value;
|
return &std::get<std::deque<Component> >(componentsStorage)
|
||||||
if (componentIndex < Components::size) {
|
.at(index);
|
||||||
// Cast required due to compiler thinking that an invalid
|
|
||||||
// Component is needed even though the enclosing if statement
|
|
||||||
// prevents this from ever happening.
|
|
||||||
return (Component*)&std::get<componentIndex>(componentsStorage)
|
|
||||||
.at(index);
|
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -408,14 +402,9 @@ struct Manager {
|
||||||
*/
|
*/
|
||||||
template <typename Component>
|
template <typename Component>
|
||||||
const Component* getEntityData(const std::size_t& index) const {
|
const Component* getEntityData(const std::size_t& index) const {
|
||||||
constexpr auto componentIndex =
|
if constexpr (EC::Meta::Contains<Component, Components>::value) {
|
||||||
EC::Meta::IndexOf<Component, Components>::value;
|
return &std::get<std::deque<Component> >(componentsStorage)
|
||||||
if (componentIndex < Components::size) {
|
.at(index);
|
||||||
// Cast required due to compiler thinking that an invalid
|
|
||||||
// Component is needed even though the enclosing if statement
|
|
||||||
// prevents this from ever happening.
|
|
||||||
return (Component*)&std::get<componentIndex>(componentsStorage)
|
|
||||||
.at(index);
|
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -501,23 +490,20 @@ struct Manager {
|
||||||
*/
|
*/
|
||||||
template <typename Component, typename... Args>
|
template <typename Component, typename... Args>
|
||||||
void addComponent(const std::size_t& entityID, Args&&... args) {
|
void addComponent(const std::size_t& entityID, Args&&... args) {
|
||||||
if (!EC::Meta::Contains<Component, Components>::value ||
|
if constexpr (!EC::Meta::Contains<Component, Components>::value) {
|
||||||
!isAlive(entityID)) {
|
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
if (!isAlive(entityID)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Component component(std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
std::get<BitsetType>(entities[entityID])
|
||||||
|
.template getComponentBit<Component>() = true;
|
||||||
|
|
||||||
|
std::get<std::deque<Component> >(componentsStorage)[entityID] =
|
||||||
|
std::move(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
Component component(std::forward<Args>(args)...);
|
|
||||||
|
|
||||||
std::get<BitsetType>(entities[entityID])
|
|
||||||
.template getComponentBit<Component>() = true;
|
|
||||||
|
|
||||||
constexpr auto index = EC::Meta::IndexOf<Component, Components>::value;
|
|
||||||
|
|
||||||
// Cast required due to compiler thinking that deque<char> at
|
|
||||||
// index = Components::size is being used, even if the previous
|
|
||||||
// if statement will prevent this from ever happening.
|
|
||||||
(*((std::deque<Component>*)(&std::get<index>(
|
|
||||||
componentsStorage))))[entityID] = std::move(component);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -533,13 +519,15 @@ struct Manager {
|
||||||
*/
|
*/
|
||||||
template <typename Component>
|
template <typename Component>
|
||||||
void removeComponent(const std::size_t& entityID) {
|
void removeComponent(const std::size_t& entityID) {
|
||||||
if (!EC::Meta::Contains<Component, Components>::value ||
|
if constexpr (!EC::Meta::Contains<Component, Components>::value) {
|
||||||
!isAlive(entityID)) {
|
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
if (!isAlive(entityID)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::get<BitsetType>(entities[entityID])
|
||||||
|
.template getComponentBit<Component>() = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::get<BitsetType>(entities[entityID])
|
|
||||||
.template getComponentBit<Component>() = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -552,12 +540,16 @@ struct Manager {
|
||||||
*/
|
*/
|
||||||
template <typename Tag>
|
template <typename Tag>
|
||||||
void addTag(const std::size_t& entityID) {
|
void addTag(const std::size_t& entityID) {
|
||||||
if (!EC::Meta::Contains<Tag, Tags>::value || !isAlive(entityID)) {
|
if constexpr (!EC::Meta::Contains<Tag, Tags>::value) {
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
|
if (!isAlive(entityID)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() =
|
std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() =
|
||||||
true;
|
true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -572,12 +564,16 @@ struct Manager {
|
||||||
*/
|
*/
|
||||||
template <typename Tag>
|
template <typename Tag>
|
||||||
void removeTag(const std::size_t& entityID) {
|
void removeTag(const std::size_t& entityID) {
|
||||||
if (!EC::Meta::Contains<Tag, Tags>::value || !isAlive(entityID)) {
|
if constexpr (!EC::Meta::Contains<Tag, Tags>::value) {
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
|
if (!isAlive(entityID)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() =
|
std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() =
|
||||||
false;
|
false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
@ -23,8 +23,8 @@ namespace Internal {
|
||||||
using TPFnType = std::function<void(void *)>;
|
using TPFnType = std::function<void(void *)>;
|
||||||
using TPTupleType = std::tuple<TPFnType, void *>;
|
using TPTupleType = std::tuple<TPFnType, void *>;
|
||||||
using TPQueueType = std::queue<TPTupleType>;
|
using TPQueueType = std::queue<TPTupleType>;
|
||||||
using ThreadPtr = std::unique_ptr<std::thread>;
|
using ThreadOpt = std::optional<std::thread>;
|
||||||
using ThreadStackType = std::vector<std::tuple<ThreadPtr, std::thread::id>>;
|
using ThreadStackType = std::vector<std::tuple<ThreadOpt, std::thread::id>>;
|
||||||
using ThreadStacksType = std::deque<ThreadStackType>;
|
using ThreadStacksType = std::deque<ThreadStackType>;
|
||||||
using ThreadStacksMutexesT = std::deque<std::mutex>;
|
using ThreadStacksMutexesT = std::deque<std::mutex>;
|
||||||
using ThreadCountersT = std::deque<std::atomic_uint>;
|
using ThreadCountersT = std::deque<std::atomic_uint>;
|
||||||
|
@ -75,14 +75,14 @@ class ThreadPool {
|
||||||
been executed.
|
been executed.
|
||||||
*/
|
*/
|
||||||
Internal::PointersT startThreads() {
|
Internal::PointersT startThreads() {
|
||||||
if (MAXSIZE >= 2) {
|
if constexpr (MAXSIZE >= 2) {
|
||||||
checkStacks();
|
checkStacks();
|
||||||
auto pointers = newStackEntry();
|
auto pointers = newStackEntry();
|
||||||
Internal::ThreadStackType *threadStack = std::get<0>(pointers);
|
Internal::ThreadStackType *threadStack = std::get<0>(pointers);
|
||||||
std::mutex *threadStackMutex = std::get<1>(pointers);
|
std::mutex *threadStackMutex = std::get<1>(pointers);
|
||||||
std::atomic_uint *aCounter = std::get<2>(pointers);
|
std::atomic_uint *aCounter = std::get<2>(pointers);
|
||||||
for (unsigned int i = 0; i < MAXSIZE; ++i) {
|
for (unsigned int i = 0; i < MAXSIZE; ++i) {
|
||||||
std::thread *newThread = new std::thread(
|
std::thread newThread(
|
||||||
[](Internal::ThreadStackType *threadStack,
|
[](Internal::ThreadStackType *threadStack,
|
||||||
std::mutex *threadStackMutex,
|
std::mutex *threadStackMutex,
|
||||||
Internal::TPQueueType *fnQueue, std::mutex *queueMutex,
|
Internal::TPQueueType *fnQueue, std::mutex *queueMutex,
|
||||||
|
@ -91,7 +91,7 @@ class ThreadPool {
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(*threadStackMutex);
|
std::lock_guard<std::mutex> lock(*threadStackMutex);
|
||||||
threadStack->push_back(
|
threadStack->push_back(
|
||||||
{Internal::ThreadPtr(nullptr),
|
{Internal::ThreadOpt{},
|
||||||
std::this_thread::get_id()});
|
std::this_thread::get_id()});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ class ThreadPool {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(15));
|
std::this_thread::sleep_for(std::chrono::microseconds(15));
|
||||||
}
|
}
|
||||||
std::lock_guard<std::mutex> stackLock(*threadStackMutex);
|
std::lock_guard<std::mutex> stackLock(*threadStackMutex);
|
||||||
std::get<0>(threadStack->at(i)).reset(newThread);
|
std::get<0>(threadStack->at(i)) = std::move(newThread);
|
||||||
}
|
}
|
||||||
return pointers;
|
return pointers;
|
||||||
} else {
|
} else {
|
||||||
|
@ -178,7 +178,7 @@ class ThreadPool {
|
||||||
all previously queued functions have been executed.
|
all previously queued functions have been executed.
|
||||||
*/
|
*/
|
||||||
void easyStartAndWait() {
|
void easyStartAndWait() {
|
||||||
if (MAXSIZE >= 2) {
|
if constexpr (MAXSIZE >= 2) {
|
||||||
Internal::PointersT pointers = startThreads();
|
Internal::PointersT pointers = startThreads();
|
||||||
do {
|
do {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(30));
|
std::this_thread::sleep_for(std::chrono::microseconds(30));
|
||||||
|
|
Loading…
Reference in a new issue