diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 0000000..a8d52f4 --- /dev/null +++ b/.bazelignore @@ -0,0 +1 @@ +Examples/ diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 0000000..89340a4 --- /dev/null +++ b/.bazelrc @@ -0,0 +1,18 @@ +# Common +common --enable_platform_specific_config +common --incompatible_strict_action_env +common --toolchain_resolution_debug=all +common --show_timestamps +common --verbose_failures +test --test_output=errors + +# Opts +common:linux --config=default_compiler_opts +common:msvc --config=microsoft_compiler_opts + +common:default_compiler_opts --copt -std=c++20 +common:microsoft_compiler_opts --copt /std:c++20 + +# BuildBuddy +common:linux --workspace_status_command=$(pwd)/.buildbuddy/workspace_status.sh +common:windows --workspace_status_command=.buildbuddy/workspace_status.bat diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 0000000..e69de29 diff --git a/.buildbuddy/workspace_status.bat b/.buildbuddy/workspace_status.bat new file mode 100755 index 0000000..cc31c36 --- /dev/null +++ b/.buildbuddy/workspace_status.bat @@ -0,0 +1,2 @@ +@echo off +call PowerShell -NoProfile -ExecutionPolicy Bypass -Command "%CD%\.buildbuddy\workspace_status.ps1" diff --git a/.buildbuddy/workspace_status.ps1 b/.buildbuddy/workspace_status.ps1 new file mode 100755 index 0000000..a2c1a20 --- /dev/null +++ b/.buildbuddy/workspace_status.ps1 @@ -0,0 +1,33 @@ +# This script will be run by Bazel when the building process starts to +# generate key-value information that represents the status of the +# workspace. The output should be like +# +# KEY1 VALUE1 +# KEY2 VALUE2 +# +# If the script exits with a non-zero code, it's considered as a failure +# and the output will be discarded. + +$ErrorActionPreference = "Stop" + +# Get the repository URL without credentials +$repo_url = (git config --get remote.origin.url) -replace '//.*?:.*?@', '//' +$repo_url = $repo_url -replace '^git@github.com:', 'https://github.com/' +$urrepo_urll = $repo_url -replace '\.git$' +Write-Output "REPO_URL $repo_url" + +# Get the commit SHA +$commit_sha = git rev-parse HEAD +Write-Output "COMMIT_SHA $commit_sha" + +# Get the current Git branch +$git_branch = git rev-parse --abbrev-ref HEAD +Write-Output "GIT_BRANCH $git_branch" + +# Check if there are any modified files in the working directory +if (git diff-index --quiet HEAD) { + $git_tree_status = 'Clean' +} else { + $git_tree_status = 'Modified' +} +Write-Output "GIT_TREE_STATUS $git_tree_status" diff --git a/.buildbuddy/workspace_status.sh b/.buildbuddy/workspace_status.sh new file mode 100755 index 0000000..df1dac9 --- /dev/null +++ b/.buildbuddy/workspace_status.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# This script will be run bazel when building process starts to +# generate key-value information that represents the status of the +# workspace. The output should be like +# +# KEY1 VALUE1 +# KEY2 VALUE2 +# +# If the script exits with non-zero code, it's considered as a failure +# and the output will be discarded. + +set -eo pipefail # exit immediately if any command fails. + +function remove_url_credentials() { + which perl >/dev/null && perl -pe 's#//.*?:.*?@#//#' || cat +} + +repo_url=$(git config --get remote.origin.url | remove_url_credentials) +repo_url=${repo_url/git@github.com:/https://github.com/} +repo_url=${repo_url%.git} +echo "REPO_URL $repo_url" + +commit_sha=$(git rev-parse HEAD) +echo "COMMIT_SHA $commit_sha" + +git_branch=$(git rev-parse --abbrev-ref HEAD) +echo "GIT_BRANCH $git_branch" + +git_tree_status=$(git diff-index --quiet HEAD -- && echo 'Clean' || echo 'Modified') +echo "GIT_TREE_STATUS $git_tree_status" diff --git a/.buildkite/linux_amd64.yml b/.buildkite/linux_amd64.yml new file mode 100644 index 0000000..6fec44b --- /dev/null +++ b/.buildkite/linux_amd64.yml @@ -0,0 +1,13 @@ +agents: + queue: "agent-runners-linux-amd64" + +steps: + - label: ":bazel: Build and Test on gcc" + commands: + - CC=gcc bazelisk build --config=default_compiler_opts //:LittleECSTests + - CC=gcc bazelisk test --config=default_compiler_opts //:LittleECSTests + + - label: ":bazel: Build and Test on Clang" + commands: + - CC=clang bazelisk build --config=default_compiler_opts //:LittleECSTests + - CC=clang bazelisk test --config=default_compiler_opts //:LittleECSTests \ No newline at end of file diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml new file mode 100644 index 0000000..b9d8345 --- /dev/null +++ b/.buildkite/pipeline.yml @@ -0,0 +1,5 @@ +steps: + - label: ":pipeline: Launch Windows Pipeline" + command: "buildkite-agent pipeline upload .buildkite/windows_amd64.yml" + - label: ":pipeline: Launch Linux Pipeline" + command: "buildkite-agent pipeline upload .buildkite/linux_amd64.yml" diff --git a/.buildkite/template.yml b/.buildkite/template.yml new file mode 100644 index 0000000..7c77187 --- /dev/null +++ b/.buildkite/template.yml @@ -0,0 +1,4 @@ +name: "LittleECS" +steps: + - label: ":pipeline: Launch Embbeded Pipeline" + command: "buildkite-agent pipeline upload .builkite/pipeline.yml" diff --git a/.buildkite/windows_amd64.yml b/.buildkite/windows_amd64.yml new file mode 100644 index 0000000..75354c1 --- /dev/null +++ b/.buildkite/windows_amd64.yml @@ -0,0 +1,8 @@ +agents: + queue: "agent-runners-windows-amd64" + +steps: + - label: ":bazel: Build" + commands: + - bazelisk build --config=microsoft_compiler_opts //:LittleECSTests + - bazelisk test --config=microsoft_compiler_opts //:LittleECSTests diff --git a/.github/workflows/LittleECS.yml b/.github/workflows/LittleECS.yml new file mode 100644 index 0000000..7bb512b --- /dev/null +++ b/.github/workflows/LittleECS.yml @@ -0,0 +1,64 @@ +name: LittleECS + +on: + push: + branches: + - '**' + pull_request: + branches: + - '**' + +jobs: + windows-latest-msvc: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: bazelbuild/setup-bazelisk@v3 + - name: Mount bazel cache + uses: actions/cache@v4 + with: + path: "~/.cache/bazel" + key: bazel + - name: Building... + run: bazelisk build --config=microsoft_compiler_opts //:LittleECSTests + - name: Testing... + run: bazelisk test --config=microsoft_compiler_opts //:LittleECSTests + + ubuntu-latest-gcc: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: bazelbuild/setup-bazelisk@v3 + - name: Mount bazel cache + uses: actions/cache@v4 + with: + path: "~/.cache/bazel" + key: bazel + - name: Version + run: gcc --version + - name: Building... + run: CC=gcc bazelisk build --config=default_compiler_opts //:LittleECSTests + - name: Testing... + run: CC=gcc bazelisk test --config=default_compiler_opts //:LittleECSTests + + ubuntu-latest-clang: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: bazelbuild/setup-bazelisk@v3 + - name: Mount bazel cache + uses: actions/cache@v4 + with: + path: "~/.cache/bazel" + key: bazel + - name: Install clang + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x ./llvm.sh + sudo ./llvm.sh 17 + - name: Version + run: clang --version + - name: Building... + run: CC=clang++-17 bazelisk build --config=default_compiler_opts //:LittleECSTests + - name: Testing... + run: CC=clang++-17 bazelisk test --config=default_compiler_opts //:LittleECSTests diff --git a/.gitignore b/.gitignore index e689c20..df84819 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,14 @@ +# bazel +MODULE.bazel.lock +bazel-bin +bazel-out +bazel-littleecs +bazel-LittleECS +bazel-examples +bazel-Examples +bazel-testlogs + # VS .vs *.sln @@ -6,13 +16,11 @@ *.vcxproj.filters *.vcxproj.user +# Make Makefile *.make -# VSCode -.vscode - -# VSCode +# bin bin bin-int diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..33e4d94 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,16 @@ +{ + "configurations": [ + { + "name": "Default Windows", + "includePath": [ + "src/", + "bazel-littleecs/external/_main~_repo_rules~ProjectCore/src/" + ], + "cStandard": "c17", + "cppStandard": "c++20", + "compilerPath": "cl.exe", + "intelliSenseMode": "windows-msvc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..aad90bb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,89 @@ +{ + "files.associations": { + "*.tpl": "starlark", + ".bazelrc": "bat", + "algorithm": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "compare": "cpp", + "concepts": "cpp", + "exception": "cpp", + "filesystem": "cpp", + "format": "cpp", + "iomanip": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "memory": "cpp", + "new": "cpp", + "optional": "cpp", + "ostream": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "vector": "cpp", + "xhash": "cpp", + "xlocnum": "cpp", + "xmemory": "cpp", + "xstring": "cpp", + "xtr1common": "cpp", + "xutility": "cpp", + "future": "cpp", + "xlocale": "cpp", + "any": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "cctype": "cpp", + "cinttypes": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "condition_variable": "cpp", + "csignal": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "deque": "cpp", + "coroutine": "cpp", + "resumable": "cpp", + "forward_list": "cpp", + "fstream": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "locale": "cpp", + "map": "cpp", + "mutex": "cpp", + "queue": "cpp", + "ranges": "cpp", + "ratio": "cpp", + "set": "cpp", + "span": "cpp", + "sstream": "cpp", + "stack": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "string": "cpp", + "thread": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "xfacet": "cpp", + "xiosbase": "cpp", + "xlocbuf": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xloctime": "cpp", + "xtree": "cpp" + } +} \ No newline at end of file diff --git a/BUILD b/BUILD new file mode 100644 index 0000000..f1fe707 --- /dev/null +++ b/BUILD @@ -0,0 +1,32 @@ +"" + +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") + +cc_library( + name = "LittleECS", + srcs = glob([ "src/**/*.h" ]), + hdrs = glob([ "src/**/*.h" ]), + includes = [ "src/" ], + strip_include_prefix = "src", + include_prefix = "LittleECS", + linkstatic = True, + visibility = ["//visibility:public"], +) + +cc_test( + name = "LittleECSTests", + includes = [ "src/" ], + srcs = glob([ "Tests/**/*.h", "Tests/**/*.cpp" ], exclude=["Tests/Perf/**"]), + defines = [ "LECS_USE_PROJECTCORE" ], + deps = [ "@ProjectCore//:ProjectCore", ":LittleECS" ], + visibility = ["//visibility:public"], +) + +cc_test( + name = "LittleECSTestsPerf", + includes = [ "src/" ], + srcs = glob([ "Tests/**/*.h", "Tests/**/*.cpp" ]), + defines = [ "LECS_USE_PROJECTCORE" ], + deps = [ "@ProjectCore//:ProjectCore", ":LittleECS" ], + visibility = ["//visibility:public"], +) diff --git a/Docs/Workflow.md b/Docs/Workflow.md new file mode 100644 index 0000000..2e652cf --- /dev/null +++ b/Docs/Workflow.md @@ -0,0 +1,14 @@ +# LittleECS Workflow + +This doc is tigtelly related to the [Workflow example](../Examples/Workflow/main.cpp) + +To launch it, you can set your working directory to Examples/ and run: +- On Windows, using msvc: + ``` + bazelisk run --config=msvc //Workflow:Workflow + ``` +- On Linux: (This `--config=linux` is not mandatory) + ``` + bazelisk run --config=linux //Workflow:Workflow + ``` + diff --git a/Examples/.bazelrc b/Examples/.bazelrc new file mode 100644 index 0000000..4340403 --- /dev/null +++ b/Examples/.bazelrc @@ -0,0 +1,13 @@ +# Common +common --enable_platform_specific_config +common --incompatible_strict_action_env +common --show_timestamps +common --verbose_failures +test --test_output=errors + +# Opts +common:linux --config=default_compiler_opts +common:msvc --config=microsoft_compiler_opts + +common:default_compiler_opts --copt -std=c++20 +common:microsoft_compiler_opts --copt /std:c++20 diff --git a/Examples/MODULE.bazel b/Examples/MODULE.bazel new file mode 100644 index 0000000..68148e3 --- /dev/null +++ b/Examples/MODULE.bazel @@ -0,0 +1,23 @@ +"" + +# buildifier: disable=module-docstring +module( + name = "littleecs_examples", + version = "0.1", + repo_name = "com_sacha_littleecs_examples", +) + +bazel_dep(name = "rules_cc", version = "0.0.9") + +bazel_dep(name = "littleecs") +local_path_override( + module_name = "littleecs", + path = "../", +) + +http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +http_archive( + name = "ProjectCore", + urls = [ "https://github.com/0-Sacha/ProjectCore/archive/refs/heads/dev.zip" ], + strip_prefix = "ProjectCore-dev" +) diff --git a/Examples/README.md b/Examples/README.md new file mode 100644 index 0000000..3d3d4c4 --- /dev/null +++ b/Examples/README.md @@ -0,0 +1,34 @@ +# Example of ProjectCore + +### Try thoses examples ! + +##### Build and Run examples one by one (Recommended) +Example with `//Workflow:Workflow` (see below for the list of example) +- On Windows, using msvc: + ``` + bazelisk run --config=msvc //Workflow:Workflow + ``` +- On Linux: (This `--config=linux` is not mandatory) + ``` + bazelisk run --config=linux //Workflow:Workflow + ``` + +##### Compile all examples, then run binaries +To compile every example: +- On Windows, using msvc: + ``` + bazelisk build --config=msvc //... + ``` +- On Linux: (This `--config=linux` is not mandatory) + ``` + bazelisk build --config=linux //... + ``` + +Then you can run a program with (example with `//Workflow:Workflow`, see below for the list of example) +``` +.\bazel-bin\Workflow\Workflow +``` + +### List Of Examples + +- `//Workflow:Workflow`: Workflow using the Internal Logger diff --git a/Examples/Workflow/BUILD b/Examples/Workflow/BUILD new file mode 100644 index 0000000..4eef309 --- /dev/null +++ b/Examples/Workflow/BUILD @@ -0,0 +1,11 @@ +"" + +load("@rules_cc//cc:defs.bzl", "cc_binary") + +cc_binary( + name = "Workflow", + srcs = glob([ "*.h", "*.cpp" ]), + defines = [ "LECS_USE_PROJECTCORE" ], + deps = [ "@ProjectCore//:ProjectCore", "@littleecs//:LittleECS" ], + visibility = ["//visibility:public"], +) diff --git a/Examples/Workflow/main.cpp b/Examples/Workflow/main.cpp new file mode 100644 index 0000000..92a259d --- /dev/null +++ b/Examples/Workflow/main.cpp @@ -0,0 +1,221 @@ +#include "LittleECS/LittleECS.h" + +#include "ProjectCore/FLog.h" + +ProjectCore::FLog::BasicLogger Logger("Workflow"); + +/****** Components ******/ +struct ASmallComponent +{ + std::array Buffer; +}; + +struct ABigComponent +{ + std::array Buffer; +}; + +struct Name +{ + std::string Name; +}; +// To be able to Format the struct Name +PROJECTCORE_AUTO_FORMATTER(Name, "{}", value.Name); + +int main() +{ + /****** The Registry to use ******/ + LECS::Registry registry; + + + /****** Entity Ids (Trivially copiable) ******/ + LECS::EntityId alice = registry.CreateEntityId(); + LECS::EntityId bob = registry.CreateEntityId(); + + + /****** Add Components ******/ + registry.Add(alice, 42); + registry.Add(bob, 7); + + /** + * Constructors parameters are Forwarded + */ + registry.Add(alice, "Alice"); + registry.Add(bob, "Bob"); + + /****** Get Components ******/ + std::cout << std::endl; + Logger.Info("Alice's int: {}", registry.Get(alice)); + Logger.Info("Bob's int: {}", registry.Get(bob)); + + + /****** ForEachUniqueComponent ******/ + std::cout << std::endl; + /** + * To ForEach on a specific Component, use ForEachUniqueComponent. + * It takes an lambda which can contains optionally an `LECS::EntityId` as first parameter, in that case the entityId will be send to the lambda + * The component you want to loop over is take as an template argument, and the lambda can take the component as: + * - value + * - const value + * - const reference + * - reference **Only if the registry is non-const** + * + * It will loop on all entities that have the specified component. + */ + Logger.Info("ForEachUniqueComponent (With Entity Id):"); + registry.ForEachUniqueComponent( + [](LECS::EntityId entityId, const Name& name) + { + Logger.Info(" {} -> {}", entityId, name); + } + ); + + std::cout << std::endl; + Logger.Info("ForEachUniqueComponent (Without Entity Id):"); + registry.ForEachUniqueComponent( + [](const Name& name) + { + Logger.Info(" {}", name); + } + ); + + + /****** Add Custom Components ******/ + std::cout << std::endl; + /** + * You can add any Custom Component as any others types. No need for these components to herit from anythings + */ + registry.Add(alice); + registry.Add(alice); + registry.Add(bob); + + /****** ForEachComponents ******/ + std::cout << std::endl; + /** + * To ForEach on a multiple components (only one included), use ForEachComponents. + * Like `ForEachUniqueComponent`: + * It takes an lambda which can contains optionally an `LECS::EntityId` as first parameter, in that case the entityId will be send to the lambda + * The component you want to loop over is take as an template argument, and the lambda can take the component as: + * - value + * - const value + * - const reference + * - reference **Only if the registry is non-const** + * + * It will loop on all entities that have **ALL** the specified components. + */ + Logger.Info("ForEachComponents (Without Entity Id) on :"); + registry.ForEachComponents( + [](const Name& name, const int k) + { + Logger.Info(" {} -> {}", name, k); + } + ); + + std::cout << std::endl; + /** + * Here both Alice and Bob have and , so they will be both printed + */ + Logger.Info("ForEachComponents (With Entity Id) on :"); + Logger.Debug("Both Alice and Bob have and "); + registry.ForEachComponents( + [](LECS::EntityId entityId, const Name& name, const int k, const ABigComponent&) + { + Logger.Info(" {} ({}) -> {}", name, entityId, k); + } + ); + + std::cout << std::endl; + /** + * Here only Alice all 3 components required: so she will be printed. + * Bob doesn't have a so he will not printed + */ + Logger.Info("ForEachComponents (With Entity Id) on :"); + Logger.Debug("Only Alice has so Bob is not printed. Alice does appear since she has all required components"); + registry.ForEachComponents( + [](LECS::EntityId entityId, const Name& name, const ASmallComponent&, const int k, const ABigComponent&) + { + Logger.Info(" {} ({}) -> {}", name, entityId, k); + } + ); + + /****** EachEntitiesWith ******/ + std::cout << std::endl; + /** + * EachEntitiesWith will loop over ever entities that have all components required (here only ) + */ + Logger.Info("EachEntitiesWith :"); + for (LECS::EntityId entityId : registry.EachEntitiesWith()) + { + Logger.Info(" {} -> {}", registry.Get(entityId), + registry.Has(entityId) ? "Has " : "Does NOT has " + ); + } + + + /****** Views ******/ + std::cout << std::endl; + Logger.Info("Views"); + + /** + * You can create views on components: + * Here a view on and + * It will only be able to view thoses components, any references to another component will end up in 'constraint was not satisfied' error + */ + auto view = registry.View(); + + /** + * With view, you c=have access to all previous defined For and Each functions + * Except this time you cannot reference components that where not present in the constructor + */ + Logger.Info("View: Entity with the component "); + for (LECS::EntityId entityId : view.EachEntitiesWith()) + { + Logger.Info(" {} ({})", registry.Get(entityId), entityId); + } + + LECS::EntityId eve = registry.CreateEntityId(); + registry.Add(eve, "Eve"); + + std::cout << std::endl; + Logger.Info("View doesn't need to be recreated, they are always up to date (After adding Eve):"); + for (LECS::EntityId entityId : view.EachEntitiesWith()) + { + Logger.Info(" {} ({})", registry.Get(entityId), entityId); + } + + std::cout << std::endl; + /** + * With view, you can use the regular for each loop on components. + * And use C++17 structural bindings. + * Here Eve will not appear since she doesn't have an component + */ + Logger.Info("Views: EachComponents"); + for (const auto& [name, intComponent] : view.EachComponents()) + { + Logger.Info(" {} -> {}", name, intComponent); + } + + registry.Add(eve, 123); + + /** + * Again, no need to recreate the view, a view is always up to date + */ + std::cout << std::endl; + Logger.Info("View after adding an component to Eve"); + for (const auto& [name, intComponent] : view.EachComponents()) + { + Logger.Info(" {} -> {}", name, intComponent); + } + + /** + * To destroy an entity, just use DestroyEntityId + */ + std::cout << std::endl; + registry.DestroyEntityId(bob); + + Logger.Info("View after destroying Bob"); + for (const auto& [name, intComponent] : view.EachComponents()) + { + Logger.Info(" {} -> {}", name, intComponent); + } +} diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000..bc938cc --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,17 @@ +"" + +# buildifier: disable=module-docstring +module( + name = "littleecs", + version = "0.1", + repo_name = "com_sacha_littleecs", +) + +bazel_dep(name = "rules_cc", version = "0.0.9") + +http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +http_archive( + name = "ProjectCore", + urls = [ "https://github.com/0-Sacha/ProjectCore/archive/refs/heads/dev.zip" ], + strip_prefix = "ProjectCore-dev" +) diff --git a/README.md b/README.md index 61bedc0..63d038b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,32 @@ +[![Build status](https://badge.buildkite.com/0cf82389a7a3436a623ce9a61e15bdd701d29c73ffbb6ecaf0.svg)](https://buildkite.com/sacha/littleecs) +[![LittleECS](https://github.com/0-Sacha/LittleECS/actions/workflows/LittleECS.yml/badge.svg)](https://github.com/0-Sacha/LittleECS/actions/workflows/LittleECS.yml) + # LittleECS -This is a Little Entity Component System. +LittleECS is a C++ Entity Component System. +The API is mostly inspired from [entt](https://github.com/skypjack/entt) + +I highly encourage you to check out the Workflow [documentation](Docs/Workflow.md) and [example](Examples/Workflow/main.cpp) to see what it can do and how to use it. + +## Warnings +This project is mostly an educational project of mine that I have started to learn about C++. Some features are not finished to be implemented/tested. I highly not recomend using this for a serious project. +**Do not hesitate to open an issue if you have any suggestions or review to make.** + +## Docs / Comments +Like said above, I have begun this project when learning C++, and at the time my projects where absolutely not documented. I am trying to fix this error whenever I got the time. A doc and comments will come one day... + +For now, at least, you have the [Examples](Examples/README.md) (and maybe the Tests/) folders to understand what you can do with it. More examples are coming, but again I am trying to do this whenever I have the time to do it. + +## Download +``` +git clone git@github.com:0-Sacha/LittleECS.git +``` + +## Using the Lib +It can be used using [Bazel](https://bazel.build/). +A `cc_library` rule has been created: `@LittleECS//:LittleECS`. +You need to add the module `littleecs` to your dependencies. + +You will need at least to give an c++ standard to use (at least c++20) since no one have been forced. You can check the [bazelrc](.bazelrc) to see how you can add one. + +Not Recommended: There is also a [Premake](https://premake.github.io/docs/using-premake) configuration, thought it is deprecated (and run on a wrapper of mine: [PremakeUtilities](https://github.com/0-Sacha/PremakeUtilities)). I keep it for my Game Engine [Blackbird](https://github.com/0-Sacha/Blackbird) which is using `Premake` as Build system. diff --git a/tests/BaseLittleECSTest.h b/Tests/BaseLittleECSTest.h similarity index 100% rename from tests/BaseLittleECSTest.h rename to Tests/BaseLittleECSTest.h diff --git a/Tests/BasicWorkflow.cpp b/Tests/BasicWorkflow.cpp new file mode 100644 index 0000000..4fba4ce --- /dev/null +++ b/Tests/BasicWorkflow.cpp @@ -0,0 +1,221 @@ +#include "BaseLittleECSTest.h" + +#include "LittleECS/LittleECS.h" + +#include "ProjectCore/ProfilerManager.h" + +#include + +PCT_TEST_GROUP(LITTLE_ECS, BASIC_WORKFLOW); + +struct BasicFloatComponent +{ + BasicFloatComponent(float value = 0.0f) + : Value(value) + {} + + float Value; +}; + +struct BasicIntComponentFC +{ + BasicIntComponentFC(std::size_t value = 0) + : Value(value) + {} + + std::size_t Value; +}; +template <> +struct LECS::Detail::ComponentStorageInfo : public DefaultComponentStorageInfo::FastComponent {}; + +struct BasicIntComponentFCNREF +{ + BasicIntComponentFCNREF(std::size_t value = 0) + : Value(value) + {} + + std::size_t Value; +}; +template <> +struct LECS::Detail::ComponentStorageInfo : public DefaultComponentStorageInfo::FastComponentWithoutREF {}; + +struct BasicIntComponentCC +{ + BasicIntComponentCC(std::size_t value = 0) + : Value(value) + {} + + std::size_t Value; +}; +template <> +struct LECS::Detail::ComponentStorageInfo : public DefaultComponentStorageInfo::CommonComponent {}; + +struct BasicIntComponentRC +{ + BasicIntComponentRC(std::size_t value = 0) + : Value(value) + {} + + std::size_t Value; +}; +template <> +struct LECS::Detail::ComponentStorageInfo : public DefaultComponentStorageInfo::RareComponent {}; + +#define BasicWorkflow(Postfix_ComponentToUse) PCT_TEST_FUNC(BASIC_WORKFLOW, BASIC_WORK_FLOW_TEST##Postfix_ComponentToUse) \ + { \ + LECS::Registry registry; \ + const LECS::Registry& constRegistry = registry; \ + \ + LECS::EntityId entity1 = registry.CreateEntityId(); \ + LECS::EntityId entity2 = registry.CreateEntityId(); \ + LECS::EntityId entity3 = registry.CreateEntityId(); \ + PCT_NEQ(entity1.Id, entity2.Id); \ + PCT_NEQ(entity1.Id, entity3.Id); \ + PCT_NEQ(entity2.Id, entity3.Id); \ + \ + registry.Add(entity1, 7ull); \ + registry.Add(entity2, 101ull); \ + registry.Add(entity2, 101); \ + registry.Add(entity2, 101.0f); \ + \ + PCT_EQ(registry.Get(entity1).Value, 7ull); \ + PCT_EQ(registry.Get(entity2).Value, 101ull); \ + PCT_ASSERT(registry.Has(entity3) == false); \ + \ + registry.Add(entity1, 171.0f); \ + registry.Add(entity3, 5.0f); \ + \ + PCT_EQ(registry.Get(entity1).Value, 171.0f); \ + PCT_EQ(registry.Get(entity3).Value, 5.0f); \ + PCT_ASSERT(registry.Has(entity2) == false); \ + PCT_EQ(registry.Get(entity1).Value, 7ull); \ + PCT_EQ(registry.Get(entity2).Value, 101ull); \ + PCT_ASSERT(registry.Has(entity3) == false); \ + \ + registry.ForEachComponents( \ + [](BasicIntComponent##Postfix_ComponentToUse& k, BasicFloatComponent& v) \ + { \ + k = 325ull; \ + v = 22.0f; \ + } \ + ); \ + \ + constRegistry.ForEachComponents( \ + [&link](const BasicIntComponent##Postfix_ComponentToUse& k, const BasicFloatComponent& v) \ + { \ + PCT_EQ(k.Value, 325ull); \ + PCT_EQ(v.Value, 22.0f); \ + } \ + ); \ + \ + registry.ForEachComponents( \ + [](BasicIntComponent##Postfix_ComponentToUse& k) \ + { \ + k = 85ull; \ + } \ + ); \ + \ + constRegistry.ForEachComponents( \ + [&link](const BasicIntComponent##Postfix_ComponentToUse& k) \ + { \ + PCT_EQ(k.Value, 85ull); \ + } \ + ); \ + \ + PCT_EQ(registry.Get(entity1).Value, 85ull); \ + PCT_EQ(registry.Get(entity2).Value, 85ull); \ + PCT_ASSERT(registry.Has(entity3) == false); \ + PCT_EQ(registry.Get(entity1).Value, 22.0f); \ + PCT_EQ(registry.Get(entity3).Value, 5.0f); \ + PCT_ASSERT(registry.Has(entity2) == false); \ + \ + registry.ForEachUniqueComponent( \ + [](LECS::EntityId entity, BasicIntComponent##Postfix_ComponentToUse& k) \ + { \ + k = static_cast(entity.Id); \ + } \ + ); \ + \ + PCT_EQ(registry.Get(entity1).Value, entity1.Id); \ + PCT_ASSERT(registry.Has(entity2) == true); \ + PCT_ASSERT(registry.Has(entity3) == false); \ + \ + int entityCount = 0; \ + for (LECS::EntityId entity : registry.EachEntitiesWith()) \ + { \ + ++entityCount; \ + PCT_ASSERT(registry.Has(entity)); \ + } \ + PCT_EQ(entityCount, 2); \ + \ + auto view = registry.View(); \ + \ + entityCount = 0; \ + for (LECS::EntityId entity : view.EachEntitiesWith()) \ + { \ + ++entityCount; \ + PCT_ASSERT(registry.Has(entity)); \ + } \ + PCT_EQ(entityCount, 2); \ + \ + entityCount = 0; \ + for (auto [intComponent] : view.EachComponents()) \ + { \ + ++entityCount; \ + intComponent = 52ull; \ + } \ + PCT_EQ(entityCount, 2); \ + \ + entityCount = 0; \ + view.ForEachComponents( \ + [&entityCount, &link, ®istry](LECS::EntityId entity, BasicIntComponent##Postfix_ComponentToUse& k, BasicFloatComponent& v) \ + { \ + PCT_ASSERT(registry.Has(entity)); \ + PCT_ASSERT(registry.Has(entity)); \ + \ + ++entityCount; \ + } \ + ); \ + PCT_EQ(entityCount, 1); \ + \ + entityCount = 0; \ + view.ForEachComponents( \ + [&entityCount](BasicIntComponent##Postfix_ComponentToUse& k, BasicFloatComponent& v) \ + { \ + ++entityCount; \ + } \ + ); \ + PCT_EQ(entityCount, 1); \ + \ + entityCount = 0; \ + for (LECS::EntityId entity : view.EachEntitiesWithAll()) \ + { \ + PCT_ASSERT(registry.Has(entity)); \ + PCT_ASSERT(registry.Has(entity)); \ + ++entityCount; \ + } \ + PCT_EQ(entityCount, 1); \ + \ + entityCount = 0; \ + for (auto [intComponent, floatComponent] : view.EachComponents()) \ + { \ + PCT_EQ(intComponent.Value, 52ull); \ + PCT_EQ(floatComponent.Value, 22.0f); \ + ++entityCount; \ + } \ + PCT_EQ(entityCount, 1); \ + \ + PCT_EQ(registry.Get(entity1).Value, 52ull); \ + PCT_EQ(registry.Get(entity2).Value, 52ull); \ + PCT_ASSERT(registry.Has(entity3) == false); \ + registry.DestroyEntityId(entity2); \ + PCT_EQ(registry.Get(entity1).Value, 52ull); \ + PCT_ASSERT(registry.Has(entity2) == false); \ + PCT_ASSERT(registry.Has(entity3) == false); \ + } + + +BasicWorkflow(FC); +BasicWorkflow(FCNREF); +BasicWorkflow(CC); +BasicWorkflow(RC); diff --git a/tests/Detail/ComponentId.cpp b/Tests/ComponentId.cpp similarity index 95% rename from tests/Detail/ComponentId.cpp rename to Tests/ComponentId.cpp index ce34f21..d77efc3 100644 --- a/tests/Detail/ComponentId.cpp +++ b/Tests/ComponentId.cpp @@ -1,4 +1,4 @@ -#include "../BaseLittleECSTest.h" +#include "BaseLittleECSTest.h" #include "LittleECS/Detail/ComponentId.h" #include "LittleECS/Detail/ComponentIdGenerator.h" diff --git a/tests/Detail/PerformanceTest.cpp b/Tests/Perf/PerformanceTest.cpp similarity index 68% rename from tests/Detail/PerformanceTest.cpp rename to Tests/Perf/PerformanceTest.cpp index cac5da2..c2140cb 100644 --- a/tests/Detail/PerformanceTest.cpp +++ b/Tests/Perf/PerformanceTest.cpp @@ -1,6 +1,6 @@ #include "../BaseLittleECSTest.h" -#include "LittleECS/Registry/Registry.h" +#include "LittleECS/LittleECS.h" #include "ProjectCore/Instrumentation/ProfilerManger/ProfilerManger.h" @@ -29,51 +29,57 @@ struct BasicFloatComponent template <> struct LECS::Detail::ComponentStorageInfo : public DefaultComponentStorageInfo::FastComponent { - static constexpr bool HAS_ENTITIES_REF = false; - static constexpr bool SEND_ENTITIES_POOL_ON_EACH = true; + static constexpr bool HAS_ENTITIES_REF = false; + static constexpr bool SEND_ENTITIES_POOL_ON_EACH = true; }; -#define BenchmarkTest(Size, Name) PCT_TEST_FUNC(PERFORMANCE, ADD_MANY_COMPONENT_ ## Name) \ +#define BenchmarkTest(Size, Name) PCT_TEST_FUNC(PERFORMANCE, ADD_MANY_COMPONENT_ ## Name) \ { \ ProjectCore::Instrumentation::Profiler profiler("ADD_MANY_COMPONENT_" #Name); \ \ - LECS::Registry registry; \ + LECS::Registry registry; \ \ - std::vector entities; \ + std::vector entities; \ entities.reserve(Size); \ \ - for (std::size_t i = 0; i < Size; ++i) \ { \ - entities.emplace_back(registry.CreateEntity()); \ + ProjectCore::Instrumentation::ScopeProfile scope(profiler, "Create Entities"); \ + \ + for (std::size_t i = 0; i < Size; ++i) \ + { \ + entities.emplace_back(registry.CreateEntityId()); \ + } \ } \ \ { \ + ProjectCore::Instrumentation::ScopeProfile scope(profiler, "Check Entities Ids"); \ + \ bool uid = true; \ \ - for (std::size_t i = 0; i < Size; ++i) \ - { \ + for (std::size_t i = 0; i < Size; ++i) \ + { \ if (entities[i].Id != i) \ { \ uid = false; \ break; \ } \ - } \ + } \ \ if (uid == false) \ { \ uid = true; \ \ - std::set setUID; \ + std::set setUID; \ \ - for (std::size_t i = 0; i < Size; ++i) \ - { \ - if (setUID.contains(entities[i].Id)) \ - { \ - uid = false; \ - break; \ - } \ + for (std::size_t i = 0; i < Size; ++i) \ + { \ + if (setUID.contains(entities[i].Id)) \ + { \ + uid = false; \ + break; \ + } \ setUID.insert(entities[i].Id); \ - } \ + } \ \ if (uid) \ { \ @@ -89,31 +95,31 @@ struct LECS::Detail::ComponentStorageInfo : public DefaultCom \ for (std::size_t i = 0; i < Size; ++i) \ { \ - registry.Add(entities[i], i); \ + registry.Add(entities[i], i); \ } \ } \ \ { \ - ProjectCore::Instrumentation::ScopeProfile scope(profiler, "Get Component"); \ + ProjectCore::Instrumentation::ScopeProfile scope(profiler, "Get Component"); \ \ - for (std::size_t i = 0; i < Size; ++i) \ - { \ - PCT_EQ(i, registry.Get(entities[i]).Value); \ - } \ + for (std::size_t i = 0; i < Size; ++i) \ + { \ + PCT_EQ(i, registry.Get(entities[i]).Value); \ + } \ } \ \ { \ - ProjectCore::Instrumentation::ScopeProfile scope(profiler, "Has Component"); \ + ProjectCore::Instrumentation::ScopeProfile scope(profiler, "Has Component"); \ \ for (std::size_t i = 0; i < Size; ++i) \ { \ - PCT_ASSERT(registry.Has(entities[i])); \ - PCT_ASSERT(registry.Has(entities[i]) == false); \ + PCT_ASSERT(registry.Has(entities[i])); \ + PCT_ASSERT(registry.Has(entities[i]) == false); \ } \ } \ \ { \ - ProjectCore::Instrumentation::ScopeProfile scope(profiler, "ForEach Component"); \ + ProjectCore::Instrumentation::ScopeProfile scope(profiler, "ForEach Component"); \ \ registry.ForEachUniqueComponent([](LECS::EntityId, BasicIntComponent& k) \ { \ @@ -124,9 +130,9 @@ struct LECS::Detail::ComponentStorageInfo : public DefaultCom ProjectCore::Instrumentation::ProfilerFactory::ToJson(profiler); \ } -// BenchmarkTest(1'000, 1K); -// BenchmarkTest(10'000, 10K); -// BenchmarkTest(100'000, 100K); -// BenchmarkTest(1'000'000, 1M); -// BenchmarkTest(10'000'000, 10M); -// BenchmarkTest(100'000'000, 100M); +BenchmarkTest(1'000, 1K); +BenchmarkTest(10'000, 10K); +BenchmarkTest(100'000, 100K); +BenchmarkTest(1'000'000, 1M); +BenchmarkTest(10'000'000, 10M); +BenchmarkTest(100'000'000, 100M); diff --git a/Tests/Tests.cpp b/Tests/Tests.cpp new file mode 100644 index 0000000..090a463 --- /dev/null +++ b/Tests/Tests.cpp @@ -0,0 +1,8 @@ + +#include "ProjectCore/Tester/TestSuite/AllTestSuite.h" + +int main() +{ + ProjectCore::Tester::TestSuitesManager::Verbose = false; + return ProjectCore::Tester::TestSuitesManager::ExecAllTestSuites(); +} diff --git a/buildbuddy.yaml b/buildbuddy.yaml new file mode 100644 index 0000000..5aa70a7 --- /dev/null +++ b/buildbuddy.yaml @@ -0,0 +1,18 @@ +plugins: + - repo: buildbuddy-io/plugins + path: open-invocation + - repo: siggisim/theme-modern + - repo: buildbuddy-io/plugins + path: notify + +actions: + - name: "BuildBuddy Workflows" + triggers: + push: + branches: + - "*" + pull_request: + branches: + - "*" + bazel_commands: + - "test --remote_header=x-buildbuddy-api-key=$BUILDBUDDY_RBEKEY_WINDOWS_WSL //..." diff --git a/src/LittleECS/Registry/CompressedComponentStorage/CCSForEach.h b/src/LittleECS/ComponentStrorages/CompressedComponentStorage/CCSForEach-inl.h similarity index 100% rename from src/LittleECS/Registry/CompressedComponentStorage/CCSForEach.h rename to src/LittleECS/ComponentStrorages/CompressedComponentStorage/CCSForEach-inl.h diff --git a/src/LittleECS/Registry/CompressedComponentStorage/CCSIterator.h b/src/LittleECS/ComponentStrorages/CompressedComponentStorage/CCSIterator-inl.h similarity index 94% rename from src/LittleECS/Registry/CompressedComponentStorage/CCSIterator.h rename to src/LittleECS/ComponentStrorages/CompressedComponentStorage/CCSIterator-inl.h index e0da04e..1c34e81 100644 --- a/src/LittleECS/Registry/CompressedComponentStorage/CCSIterator.h +++ b/src/LittleECS/ComponentStrorages/CompressedComponentStorage/CCSIterator-inl.h @@ -24,20 +24,20 @@ namespace LECS::Detail , m_CurrentIndexOfPage(currentIndexOfPage) , m_CurrentPageIndexOfCurrent(currentPageIndexOfCurrent) { - if (CurrentEntityIsValid() == false) - { - if (currentIndexOfPage == 0 && currentPageIndexOfCurrent == 0) - operator++(); - else - m_CompressedComponentStorage = nullptr; - } + if (CurrentEntityIsValid() == false) + { + if (currentIndexOfPage == 0 && currentPageIndexOfCurrent == 0) + operator++(); + else + m_CompressedComponentStorage = nullptr; + } } private: bool CurrentEntityIsValid() const { - if (m_CompressedComponentStorage == nullptr) - return false; + if (m_CompressedComponentStorage == nullptr) + return false; if (m_CurrentIndexOfPage >= m_CompressedComponentStorage->GetPageContainer().size()) return false; @@ -65,7 +65,7 @@ namespace LECS::Detail if (m_CurrentPageIndexOfCurrent < CompressedComponentStorage::PAGE_SIZE) { found = true; - break; + break; } ++m_CurrentIndexOfPage; } diff --git a/src/LittleECS/Registry/CompressedComponentStorage/CCSPageForEach.h b/src/LittleECS/ComponentStrorages/CompressedComponentStorage/CCSPageForEach-inl.h similarity index 100% rename from src/LittleECS/Registry/CompressedComponentStorage/CCSPageForEach.h rename to src/LittleECS/ComponentStrorages/CompressedComponentStorage/CCSPageForEach-inl.h diff --git a/src/LittleECS/Registry/CompressedComponentStorage/CompressedCSInlineEntityToComponent.h b/src/LittleECS/ComponentStrorages/CompressedComponentStorage/CompressedCSInlineEntityToComponent.h similarity index 98% rename from src/LittleECS/Registry/CompressedComponentStorage/CompressedCSInlineEntityToComponent.h rename to src/LittleECS/ComponentStrorages/CompressedComponentStorage/CompressedCSInlineEntityToComponent.h index 75ff41a..3af2b2d 100644 --- a/src/LittleECS/Registry/CompressedComponentStorage/CompressedCSInlineEntityToComponent.h +++ b/src/LittleECS/ComponentStrorages/CompressedComponentStorage/CompressedCSInlineEntityToComponent.h @@ -4,7 +4,6 @@ namespace LECS::Detail { - template class CompressedCSInlineEntityToComponent { @@ -31,8 +30,8 @@ namespace LECS::Detail public: CompressedCSInlineEntityToComponent() - : m_BucketContainer() - , m_AliveEntitiesContainer() + : m_BucketContainer() + , m_AliveEntitiesContainer() { if constexpr (HAS_ENTITIES_REF) m_AliveEntitiesContainer.reserve(PAGE_SIZE); @@ -139,5 +138,4 @@ namespace LECS::Detail (*bucketRef)[bucketInfo.PageIndexOfComponent].IndexInfo.SetInvalid(); } }; - } diff --git a/src/LittleECS/Registry/CompressedComponentStorage/CompressedCSMapEntityToComponent.h b/src/LittleECS/ComponentStrorages/CompressedComponentStorage/CompressedCSMapEntityToComponent.h similarity index 99% rename from src/LittleECS/Registry/CompressedComponentStorage/CompressedCSMapEntityToComponent.h rename to src/LittleECS/ComponentStrorages/CompressedComponentStorage/CompressedCSMapEntityToComponent.h index f1001de..bdc03c8 100644 --- a/src/LittleECS/Registry/CompressedComponentStorage/CompressedCSMapEntityToComponent.h +++ b/src/LittleECS/ComponentStrorages/CompressedComponentStorage/CompressedCSMapEntityToComponent.h @@ -6,7 +6,6 @@ namespace LECS::Detail { - class CompressedCSMapEntityToComponent { public: @@ -44,5 +43,4 @@ namespace LECS::Detail m_Container[entity.Id].SetInvalid(); } }; - } diff --git a/src/LittleECS/Registry/CompressedComponentStorage/CompressedComponentStorage.h b/src/LittleECS/ComponentStrorages/CompressedComponentStorage/CompressedComponentStorage.h similarity index 83% rename from src/LittleECS/Registry/CompressedComponentStorage/CompressedComponentStorage.h rename to src/LittleECS/ComponentStrorages/CompressedComponentStorage/CompressedComponentStorage.h index 2513748..fc254e5 100644 --- a/src/LittleECS/Registry/CompressedComponentStorage/CompressedComponentStorage.h +++ b/src/LittleECS/ComponentStrorages/CompressedComponentStorage/CompressedComponentStorage.h @@ -1,11 +1,13 @@ #pragma once +#include "LittleECS/Registry/IComponentStorage.h" +#include "LittleECS/Detail/Exception.h" + #include "CompressedComponentStoragePage.h" #include "CompressedCSMapEntityToComponent.h" #include "CompressedCSInlineEntityToComponent.h" - #include #include #include @@ -14,7 +16,6 @@ namespace LECS::Detail { - template requires (TypeValidForComponentStorage::Value) class CompressedComponentStorage : public IComponentStorage @@ -22,11 +23,11 @@ namespace LECS::Detail public: using M_Type = CompressedComponentStorage; - static constexpr Index::GlobalIndexOfComponent PAGE_SIZE = ComponentStorageInfo::PAGE_SIZE; + static constexpr Index::GlobalIndexOfComponent PAGE_SIZE = ComponentStorageInfo::PAGE_SIZE; using PageType = CompressedComponentStoragePage; using PageTypeRef = std::unique_ptr; - using PagesContainer = std::vector; + using PagesContainer = std::vector; using FreePages = std::set; using CompressedCSInlineEntityToComponentType = CompressedCSInlineEntityToComponent::HAS_ENTITIES_REF, PAGE_SIZE>; @@ -34,13 +35,13 @@ namespace LECS::Detail CompressedCSMapEntityToComponent, CompressedCSInlineEntityToComponentType>; - public: - ~CompressedComponentStorage() override {} + public: + ~CompressedComponentStorage() override {} - protected: - PagesContainer m_PageContainer; + protected: + PagesContainer m_PageContainer; FreePages m_FreePages; - EntityToComponent m_EntityToComponent; + EntityToComponent m_EntityToComponent; public: const PagesContainer& GetPageContainer() const @@ -48,25 +49,25 @@ namespace LECS::Detail return m_PageContainer; } - bool HasThisComponent(EntityId entity) const - { - return m_EntityToComponent.HasEntity(entity); - } + bool HasThisComponent(EntityId entity) const + { + return m_EntityToComponent.HasEntity(entity); + } bool HasThisComponentV(EntityId entity) const override - { - return HasThisComponent(entity); - } + { + return HasThisComponent(entity); + } private: Index::IndexOfPage GetFreePageIndexOrCreateIt() { if (m_FreePages.size() == 0) { - m_PageContainer.emplace_back(new PageType); + m_PageContainer.emplace_back(new PageType); Index::IndexOfPage indexOfPage = m_PageContainer.size() - 1; m_FreePages.insert(indexOfPage); - return indexOfPage; + return indexOfPage; } Index::IndexOfPage indexOfPage = *m_FreePages.begin(); @@ -81,7 +82,7 @@ namespace LECS::Detail PageTypeRef& page = m_PageContainer[indexInfo.IndexOfPage]; page->RemoveComponentAtIndex(indexInfo.PageIndexOfComponent); - m_FreePages.insert(indexInfo.IndexOfPage); + m_FreePages.insert(indexInfo.IndexOfPage); } void RemoveComponentOfEntityV(EntityId entity) override @@ -89,7 +90,7 @@ namespace LECS::Detail return RemoveComponentOfEntity(entity); } - public: + public: template ComponentType& AddComponentToEntity(EntityId entity, Args&&... args) { @@ -116,7 +117,7 @@ namespace LECS::Detail const ComponentType& GetComponentOfEntity(EntityId entity) const { Index::IndexInfo indexInfo = m_EntityToComponent.GetIndexInfoOfEntity(entity); - LECS_ASSERT(indexInfo.IndexOfPage < m_PageContainer.size(), "Entity doesn't have this component") + LECS_ASSERT(indexInfo.IndexOfPage < m_PageContainer.size(), "Entity doesn't have this component") const PageTypeRef& page = m_PageContainer[indexInfo.IndexOfPage]; return page->GetComponentAtIndex(indexInfo.PageIndexOfComponent); } @@ -142,7 +143,7 @@ namespace LECS::Detail { return reinterpret_cast(GetComponentOfEntityPtr(entity)); } - void* GetComponentAliasedPtrV(EntityId entity) override + void* GetComponentAliasedPtrV(EntityId entity) override { return reinterpret_cast(GetComponentOfEntityPtr(entity)); } @@ -150,13 +151,13 @@ namespace LECS::Detail private: // Function = std::function template - void ForEachStorageImpl(Function&& function) + void ForEachStorageImpl(Function&& function) requires (ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false); public: // Function = std::function template - inline void ForEachStorage(Function&& function) + inline void ForEachStorage(Function&& function) requires (ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) { return ForEachStorageImpl(std::forward(function)); @@ -164,7 +165,7 @@ namespace LECS::Detail // Function = std::function template - inline void ForEachStorage(Function&& function) const + inline void ForEachStorage(Function&& function) const requires (ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) { return const_cast*>(this)->template ForEachStorageImpl(std::forward(function)); @@ -176,5 +177,5 @@ namespace LECS::Detail }; } -#include "CCSForEach.h" -#include "CCSIterator.h" +#include "CCSForEach-inl.h" +#include "CCSIterator-inl.h" diff --git a/src/LittleECS/Registry/CompressedComponentStorage/CompressedComponentStoragePage.h b/src/LittleECS/ComponentStrorages/CompressedComponentStorage/CompressedComponentStoragePage.h similarity index 82% rename from src/LittleECS/Registry/CompressedComponentStorage/CompressedComponentStoragePage.h rename to src/LittleECS/ComponentStrorages/CompressedComponentStorage/CompressedComponentStoragePage.h index 28b3871..70dc390 100644 --- a/src/LittleECS/Registry/CompressedComponentStorage/CompressedComponentStoragePage.h +++ b/src/LittleECS/ComponentStrorages/CompressedComponentStorage/CompressedComponentStoragePage.h @@ -1,6 +1,6 @@ #pragma once -#include "../IComponentStorage.h" +#include "LittleECS/Registry/IComponentStorage.h" #include @@ -18,8 +18,8 @@ namespace LECS::Detail std::uint8_t StorageData[sizeof(ComponentType)]; ComponentType ComponentValue; - DataStorageType() {} - ~DataStorageType() {} + DataStorageType() {} + ~DataStorageType() {} }; DataStorageType Data{}; }; @@ -27,14 +27,14 @@ namespace LECS::Detail static constexpr std::size_t NUMBER_OF_BLOCKS = PAGE_SIZE / sizeof(std::size_t); static constexpr std::size_t BLOCK_SIZE = sizeof(std::size_t) * 8; - private: + private: template - inline ComponentType& ConstructAt(Index::PageIndexOfComponent index, Args&&... args) - { - ComponentDataBuffer* buffer = &m_Page[index]; - ComponentType* component = new (buffer) ComponentType(std::forward(args)...); + inline ComponentType& ConstructAt(Index::PageIndexOfComponent index, Args&&... args) + { + ComponentDataBuffer* buffer = &m_Page[index]; + ComponentType* component = new (buffer) ComponentType(std::forward(args)...); return *component; - } + } inline void DestroyAt(Index::PageIndexOfComponent index) { @@ -54,12 +54,12 @@ namespace LECS::Detail #endif } - ~CompressedComponentStoragePage() = default; + ~CompressedComponentStoragePage() = default; protected: std::array m_Page; - std::size_t m_FreeComponent[NUMBER_OF_BLOCKS]; - EntityId m_EntityIdLinked[PAGE_SIZE]; + std::size_t m_FreeComponent[NUMBER_OF_BLOCKS]; + EntityId m_EntityIdLinked[PAGE_SIZE]; std::size_t m_CurrentSize = 0; public: @@ -95,10 +95,10 @@ namespace LECS::Detail ++beginFreeListBlocks; } - LECS_ASSERT(beginFreeListBlocks != endFreeListBlocks, "This page is full") - LECS_ASSERT(*beginFreeListBlocks != 0, "This page is full") + LECS_ASSERT(beginFreeListBlocks != endFreeListBlocks, "This page is full") + LECS_ASSERT(*beginFreeListBlocks != 0, "This page is full") - std::size_t blockIndex = static_cast(beginFreeListBlocks - m_FreeComponent); + std::size_t blockIndex = static_cast(beginFreeListBlocks - m_FreeComponent); std::size_t block = *beginFreeListBlocks; std::size_t mask = 1; @@ -139,7 +139,7 @@ namespace LECS::Detail { if ((*currentBlock & mask) == 0) { - std::size_t blockIndex = NUMBER_OF_BLOCKS - std::size_t(endBlock - currentBlock); + std::size_t blockIndex = NUMBER_OF_BLOCKS - std::size_t(endBlock - currentBlock); foundIndex = indexInSubBlock + (blockIndex * BLOCK_SIZE); currentBlock = endBlock; break; @@ -162,7 +162,7 @@ namespace LECS::Detail LECS_ASSERT(CanAddComponent(), "Can't add more component to this page") Index::PageIndexOfComponent index = GetNextFreeIndex(); - LECS_ASSERT(HasComponentAtIndex(index) == false, "There are already a component at this index") + LECS_ASSERT(HasComponentAtIndex(index) == false, "There are already a component at this index") ComponentType& component = ConstructAt(index, std::forward(args)...); SetHasComponentAtIndex(index, true); @@ -184,18 +184,18 @@ namespace LECS::Detail ComponentType& GetComponentAtIndex(Index::PageIndexOfComponent index) { LECS_ASSERT(HasComponentAtIndex(index) == true, "There are no component at this index") - LECS_ASSERT(m_EntityIdLinked[index] != EntityId::INVALID, "Not supposed to have a valid component linked to a non valid entityId") + LECS_ASSERT(m_EntityIdLinked[index] != EntityId::INVALID, "Not supposed to have a valid component linked to a non valid entityId") return *reinterpret_cast(&m_Page[index]); - } + } const ComponentType& GetComponentAtIndex(Index::PageIndexOfComponent index) const { LECS_ASSERT(HasComponentAtIndex(index) == true, "There are no component at this index") - LECS_ASSERT(m_EntityIdLinked[index] != EntityId::INVALID, "Not supposed to have a valid component linked to a non valid entityId") + LECS_ASSERT(m_EntityIdLinked[index] != EntityId::INVALID, "Not supposed to have a valid component linked to a non valid entityId") return *reinterpret_cast(&m_Page[index]); - } + } ComponentType* GetComponentAtIndexPtr(Index::PageIndexOfComponent index) { @@ -204,7 +204,7 @@ namespace LECS::Detail if (m_EntityIdLinked[index] != EntityId::INVALID) return nullptr; return reinterpret_cast(&m_Page[index]); - } + } const ComponentType* GetComponentAtIndexPtr(Index::PageIndexOfComponent index) const { @@ -213,30 +213,30 @@ namespace LECS::Detail if (m_EntityIdLinked[index] != EntityId::INVALID) return nullptr; return reinterpret_cast(&m_Page[index]); - } + } inline EntityId GetEntityIdAtIndex(Index::PageIndexOfComponent index) const - { - return m_EntityIdLinked[index]; + { + return m_EntityIdLinked[index]; } private: template - void ForEachPageImpl(Function&& function); + void ForEachPageImpl(Function&& function); public: template - inline void ForEachPage(Function&& function) + inline void ForEachPage(Function&& function) { return ForEachPageImpl(std::forward(function)); } template - void ForEachPage(Function&& function) const + void ForEachPage(Function&& function) const { return const_cast*>(this)->template ForEachPageImpl(std::forward(function)); } }; } - -#include "CCSPageForEach.h" + +#include "CCSPageForEach-inl.h" diff --git a/src/LittleECS/Registry/FastComponentStorage/FCSEach.h b/src/LittleECS/ComponentStrorages/FastComponentStorage/FCSEach-inl.h similarity index 100% rename from src/LittleECS/Registry/FastComponentStorage/FCSEach.h rename to src/LittleECS/ComponentStrorages/FastComponentStorage/FCSEach-inl.h diff --git a/src/LittleECS/ComponentStrorages/FastComponentStorage/FCSIterator-inl.h b/src/LittleECS/ComponentStrorages/FastComponentStorage/FCSIterator-inl.h new file mode 100644 index 0000000..8080ff5 --- /dev/null +++ b/src/LittleECS/ComponentStrorages/FastComponentStorage/FCSIterator-inl.h @@ -0,0 +1,122 @@ +#pragma once + +#include "FastComponentStorage.h" + +#include "LittleECS/Detail/Iterable.h" + +namespace LECS::Detail +{ + template + class FCSIteratorNoRef + { + public: + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = EntityId; + using pointer = const EntityId*; + using reference = EntityId; + + public: + FCSIteratorNoRef(const FastComponentStorage* fastComponentStorage, ContainerIterator containerIterator, ContainerIterator containerIteratorLast) + : m_FastComponentStorage(fastComponentStorage) + , m_ContainerIterator(containerIterator) + , m_ContainerIteratorLast(containerIteratorLast) + {} + + public: + reference operator*() const + { + return m_ContainerIterator.operator*(); + } + pointer operator->() + { + return m_ContainerIterator.operator->(); + } + + FCSIteratorNoRef& operator++() + { + bool currentEntityValid = false; + do + { + ++m_ContainerIterator; + if (m_ContainerIterator == m_ContainerIteratorLast) + break; + + EntityId entity = *m_ContainerIterator; + currentEntityValid = m_FastComponentStorage->HasThisComponent(entity); + } while (currentEntityValid == false); + + if (currentEntityValid == false) + { + m_FastComponentStorage = nullptr; + } + + return *this; + } + + FCSIteratorNoRef operator++(int) + { + FCSIteratorNoRef res = this; + ++(*this); + return res; + } + + bool operator==(const FCSIteratorNoRef& rhs) const + { +#ifdef LECS_DEBUG + bool complexResult = m_FastComponentStorage != nullptr && + m_FastComponentStorage == rhs.m_FastComponentStorage && + m_ContainerIterator == rhs.m_ContainerIterator && + m_ContainerIteratorLast == rhs.m_ContainerIteratorLast; + bool simpleResult = m_FastComponentStorage != nullptr; + + LECS_ASSERT(simpleResult == complexResult, "Operator== for Iterator is wrong") + + return simpleResult; +#else + return m_FastComponentStorage != nullptr; +#endif + } + + bool operator!=(const FCSIteratorNoRef& rhs) const { return !(*this == rhs); } + + bool operator==(IterableEnd rhs) { return m_FastComponentStorage == nullptr; } + bool operator!=(IterableEnd rhs) { return !(*this == rhs); } + + private: + const FastComponentStorage* m_FastComponentStorage; + ContainerIterator m_ContainerIterator; + ContainerIterator m_ContainerIteratorLast; + }; + + template + requires (TypeValidForComponentStorage::Value) + decltype(auto) FastComponentStorage::EntitiesIteratorBegin() const + requires (ComponentStorageInfo::HAS_ENTITIES_REF && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) + { + return m_AliveEntitiesContainer.cbegin(); + } + template + requires (TypeValidForComponentStorage::Value) + decltype(auto) FastComponentStorage::EntitiesIteratorEnd() const + requires (ComponentStorageInfo::HAS_ENTITIES_REF && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) + { + return m_AliveEntitiesContainer.cend(); + } + + template + requires (TypeValidForComponentStorage::Value) + decltype(auto) FastComponentStorage::EntitiesIteratorBegin(const auto& registryAliveEntities) const + requires (ComponentStorageInfo::HAS_ENTITIES_REF == false && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH) + { + return FCSIteratorNoRef(this, registryAliveEntities.cbegin(), registryAliveEntities.cend()); + } + + template + requires (TypeValidForComponentStorage::Value) + decltype(auto) FastComponentStorage::EntitiesIteratorEnd(const auto&) const + requires (ComponentStorageInfo::HAS_ENTITIES_REF == false && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH) + { + return IterableEnd(); + } +} diff --git a/src/LittleECS/Registry/FastComponentStorage/FastComponentStorage.h b/src/LittleECS/ComponentStrorages/FastComponentStorage/FastComponentStorage.h similarity index 83% rename from src/LittleECS/Registry/FastComponentStorage/FastComponentStorage.h rename to src/LittleECS/ComponentStrorages/FastComponentStorage/FastComponentStorage.h index 63af0a1..ef97020 100644 --- a/src/LittleECS/Registry/FastComponentStorage/FastComponentStorage.h +++ b/src/LittleECS/ComponentStrorages/FastComponentStorage/FastComponentStorage.h @@ -1,8 +1,10 @@ #pragma once -#include "FastComponentStoragePage.h" +#include "LittleECS/Registry/IComponentStorage.h" #include "LittleECS/Detail/Exception.h" +#include "FastComponentStoragePage.h" + #include #include #include @@ -11,7 +13,6 @@ namespace LECS::Detail { - template requires (TypeValidForComponentStorage::Value) class FastComponentStorage : public IComponentStorage @@ -19,45 +20,43 @@ namespace LECS::Detail public: using M_Type = FastComponentStorage; - static constexpr Index::GlobalIndexOfComponent PAGE_SIZE = ComponentStorageInfo::PAGE_SIZE; + static constexpr Index::GlobalIndexOfComponent PAGE_SIZE = ComponentStorageInfo::PAGE_SIZE; using PageType = FastComponentStoragePage; using PageTypeRef = std::unique_ptr; - using PagesContainer = std::vector; + using PagesContainer = std::vector; using AliveEntitiesContainerType = std::vector; using AliveEntitiesContainer = std::conditional_t::HAS_ENTITIES_REF, AliveEntitiesContainerType, int>; - class FCSErrorCantForEachOnNonREFContainer : public LECSException {}; - - public: - FastComponentStorage() - : m_PageContainer() - , m_AliveEntitiesContainer() - { - } - - ~FastComponentStorage() override + public: + FastComponentStorage() + : m_PageContainer() + , m_AliveEntitiesContainer() { if constexpr (ComponentStorageInfo::HAS_ENTITIES_REF) m_AliveEntitiesContainer.reserve(PAGE_SIZE); } - protected: - PagesContainer m_PageContainer; + ~FastComponentStorage() override + { + } + + protected: + PagesContainer m_PageContainer; AliveEntitiesContainer m_AliveEntitiesContainer; - protected: - inline Index::IndexInfo GetIndexInfoOfEntity(EntityId entity) const - { - Index::IndexInfo indexInfo; - indexInfo.IndexOfPage = entity.Id / PAGE_SIZE; - indexInfo.PageIndexOfComponent = entity.Id % PAGE_SIZE; - return indexInfo; - } + protected: + inline Index::IndexInfo GetIndexInfoOfEntity(EntityId entity) const + { + Index::IndexInfo indexInfo; + indexInfo.IndexOfPage = entity.Id / PAGE_SIZE; + indexInfo.PageIndexOfComponent = entity.Id % PAGE_SIZE; + return indexInfo; + } public: - bool HasThisComponent(EntityId entity) const - { + bool HasThisComponent(EntityId entity) const + { Index::IndexInfo indexInfo = GetIndexInfoOfEntity(entity); if (indexInfo.IndexOfPage >= m_PageContainer.size()) @@ -65,11 +64,11 @@ namespace LECS::Detail if (m_PageContainer[indexInfo.IndexOfPage] == nullptr) return false; - return m_PageContainer[indexInfo.IndexOfPage]->HasEntityAtIndex(indexInfo.PageIndexOfComponent); - } + return m_PageContainer[indexInfo.IndexOfPage]->HasEntityAtIndex(indexInfo.PageIndexOfComponent); + } bool HasThisComponentV(EntityId entity) const override - { + { return HasThisComponent(entity); } @@ -94,7 +93,7 @@ namespace LECS::Detail return RemoveComponentOfEntity(entity); } - public: + public: template ComponentType& AddComponentToEntity(EntityId entity, Args&&... args) { @@ -124,7 +123,7 @@ namespace LECS::Detail ComponentType& GetComponentOfEntity(EntityId entity) { Index::IndexInfo indexInfo = GetIndexInfoOfEntity(entity); - LECS_ASSERT(indexInfo.IndexOfPage < m_PageContainer.size(), "Entity doesn't have this component") + LECS_ASSERT(indexInfo.IndexOfPage < m_PageContainer.size(), "Entity doesn't have this component") PageTypeRef& page = m_PageContainer[indexInfo.IndexOfPage]; return page->GetComponentAtIndex(indexInfo.PageIndexOfComponent); } @@ -132,7 +131,7 @@ namespace LECS::Detail const ComponentType& GetComponentOfEntity(EntityId entity) const { Index::IndexInfo indexInfo = GetIndexInfoOfEntity(entity); - LECS_ASSERT(indexInfo.IndexOfPage < m_PageContainer.size(), "Entity doesn't have this component") + LECS_ASSERT(indexInfo.IndexOfPage < m_PageContainer.size(), "Entity doesn't have this component") const PageTypeRef& page = m_PageContainer[indexInfo.IndexOfPage]; return page->GetComponentAtIndex(indexInfo.PageIndexOfComponent); } @@ -159,7 +158,7 @@ namespace LECS::Detail { return reinterpret_cast(GetComponentOfEntityPtr(entity)); } - void* GetComponentAliasedPtrV(EntityId entity) override + void* GetComponentAliasedPtrV(EntityId entity) override { return reinterpret_cast(GetComponentOfEntityPtr(entity)); } @@ -172,7 +171,7 @@ namespace LECS::Detail // Function = std::function template - void ForEachStorage(Function&& function) const + void ForEachStorage(Function&& function) const requires (ComponentStorageInfo::HAS_ENTITIES_REF && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false); // Function = std::function @@ -182,20 +181,23 @@ namespace LECS::Detail // Function = std::function template - void ForEachStorage(Function&& function, const auto& registryAliveEntities) const + void ForEachStorage(Function&& function, const auto& registryAliveEntities) const requires (ComponentStorageInfo::HAS_ENTITIES_REF == false && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH); public: decltype(auto) EntitiesIteratorBegin() const requires (ComponentStorageInfo::HAS_ENTITIES_REF && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false); + decltype(auto) EntitiesIteratorEnd() const requires (ComponentStorageInfo::HAS_ENTITIES_REF && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false); + decltype(auto) EntitiesIteratorBegin(const auto& registryAliveEntities) const requires (ComponentStorageInfo::HAS_ENTITIES_REF == false && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH); + decltype(auto) EntitiesIteratorEnd(const auto& registryAliveEntities) const requires (ComponentStorageInfo::HAS_ENTITIES_REF == false && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH); }; } - -#include "FCSEach.h" -#include "FCSIterator.h" + +#include "FCSEach-inl.h" +#include "FCSIterator-inl.h" diff --git a/src/LittleECS/Registry/FastComponentStorage/FastComponentStoragePage.h b/src/LittleECS/ComponentStrorages/FastComponentStorage/FastComponentStoragePage.h similarity index 68% rename from src/LittleECS/Registry/FastComponentStorage/FastComponentStoragePage.h rename to src/LittleECS/ComponentStrorages/FastComponentStorage/FastComponentStoragePage.h index f627c11..9fd1b5b 100644 --- a/src/LittleECS/Registry/FastComponentStorage/FastComponentStoragePage.h +++ b/src/LittleECS/ComponentStrorages/FastComponentStorage/FastComponentStoragePage.h @@ -1,6 +1,6 @@ #pragma once -#include "../IComponentStorage.h" +#include "LittleECS/Registry/IComponentStorage.h" #include @@ -13,13 +13,13 @@ namespace LECS::Detail private: struct ComponentDataBuffer { - union DataStorageType - { - std::uint8_t StorageData[sizeof(ComponentType)]; - ComponentType ComponentValue; + union DataStorageType + { + std::uint8_t StorageData[sizeof(ComponentType)]; + ComponentType ComponentValue; - DataStorageType() {} - ~DataStorageType() {} + DataStorageType() {} + ~DataStorageType() {} }; DataStorageType Data{}; }; @@ -42,30 +42,30 @@ namespace LECS::Detail struct EntityLinkedWithRef { - typename EntityId::Type Entity; + typename EntityId::Type Entity; Index::IndexInAliveList IndexInAliveList; - inline bool constexpr IsValid() const - { - return Entity != EntityId::INVALID; - } + inline bool constexpr IsValid() const + { + return Entity != EntityId::INVALID; + } - inline void constexpr SetInvalid() - { - Entity = EntityId::INVALID; - } + inline void constexpr SetInvalid() + { + Entity = EntityId::INVALID; + } }; using EntityLinked = std::conditional_t::HAS_ENTITIES_REF, EntityLinkedWithRef, EntityLinkedWithoutRef>; - private: + private: template - inline ComponentType& ConstructAt(Index::PageIndexOfComponent index, Args&&... args) - { - ComponentDataBuffer* buffer = &m_Page[index]; - ComponentType* component = new (buffer) ComponentType(std::forward(args)...); + inline ComponentType& ConstructAt(Index::PageIndexOfComponent index, Args&&... args) + { + ComponentDataBuffer* buffer = &m_Page[index]; + ComponentType* component = new (buffer) ComponentType(std::forward(args)...); return *component; - } + } inline void DestroyAt(Index::PageIndexOfComponent index) { @@ -80,30 +80,30 @@ namespace LECS::Detail m_EntitiesLinked[i].SetInvalid(); } - ~FastComponentStoragePage() - { - // ForEach([this](Index::PageIndexOfComponent index) { this->DestroyAt(index); }); - } + ~FastComponentStoragePage() + { + // ForEach([this](Index::PageIndexOfComponent index) { this->DestroyAt(index); }); + } protected: std::array m_Page; EntityLinked m_EntitiesLinked[PAGE_SIZE]; public: - inline typename EntityId::Type GetEntityIdAtIndex(Index::PageIndexOfComponent index) const - { - return m_EntitiesLinked[index].Entity; + inline typename EntityId::Type GetEntityIdAtIndex(Index::PageIndexOfComponent index) const + { + return m_EntitiesLinked[index].Entity; } inline bool HasEntityAtIndex(Index::PageIndexOfComponent index) const - { - return m_EntitiesLinked[index].IsValid(); + { + return m_EntitiesLinked[index].IsValid(); } inline Index::IndexInAliveList GetIndexInAliveListAtIndex(Index::PageIndexOfComponent index) const - { + { if constexpr (ComponentStorageInfo::HAS_ENTITIES_REF) - return m_EntitiesLinked[index].IndexInAliveList; + return m_EntitiesLinked[index].IndexInAliveList; else return 0; } @@ -145,36 +145,36 @@ namespace LECS::Detail ComponentType& GetComponentAtIndex(Index::PageIndexOfComponent index) { - LECS_ASSERT(index < m_Page.size(), "There are no component linked to this entity at this page") - LECS_ASSERT(HasEntityAtIndex(index) == true, "There are no component linked to this entity at this page") + LECS_ASSERT(index < m_Page.size(), "There are no component linked to this entity at this page") + LECS_ASSERT(HasEntityAtIndex(index) == true, "There are no component linked to this entity at this page") return *reinterpret_cast(&m_Page[index]); - } + } const ComponentType& GetComponentAtIndex(Index::PageIndexOfComponent index) const { - LECS_ASSERT(index < m_Page.size(), "There are no component linked to this entity at this page") - LECS_ASSERT(HasEntityAtIndex(index) == true, "There are no component linked to this entity at this page") + LECS_ASSERT(index < m_Page.size(), "There are no component linked to this entity at this page") + LECS_ASSERT(HasEntityAtIndex(index) == true, "There are no component linked to this entity at this page") return *reinterpret_cast(&m_Page[index]); - } + } ComponentType* GetComponentAtIndexPtr(Index::PageIndexOfComponent index) - { - if (index >= m_Page.size()) - return nullptr; + { + if (index >= m_Page.size()) + return nullptr; if (HasEntityAtIndex(index) == false) return nullptr; return reinterpret_cast(&m_Page[index]); - } + } const ComponentType* GetComponentAtIndexPtr(Index::PageIndexOfComponent index) const { - if (index >= m_Page.size()) - return nullptr; + if (index >= m_Page.size()) + return nullptr; if (HasEntityAtIndex(index) == false) return nullptr; return reinterpret_cast(&m_Page[index]); - } + } }; } diff --git a/src/LittleECS/Core/CompilerInfo.h b/src/LittleECS/Core/CompilerInfo.h new file mode 100644 index 0000000..ecd4512 --- /dev/null +++ b/src/LittleECS/Core/CompilerInfo.h @@ -0,0 +1,23 @@ +#pragma once + +#ifndef LECS_DO_NOT_USE_DEFAULT_MACRO + #if defined(__clang__) + #define LECS_COMPILER_CLANG + #elif defined(__GNUC__) || defined(__GNUG__) + #define LECS_COMPILER_GCC + #elif defined(_MSC_VER) + #define LECS_COMPILER_MSVC + #endif + + #ifdef LECS_COMPILER_MSVC + #ifdef _DEBUG + #define LECS_DEBUG + #endif + #endif + + #if defined(LECS_COMPILER_CLANG) || defined(LECS_COMPILER_GCC) + #if !defined(NDEBUG) + #define LECS_DEBUG + #endif + #endif +#endif diff --git a/src/LittleECS/Core/Core.h b/src/LittleECS/Core/Core.h new file mode 100644 index 0000000..712a835 --- /dev/null +++ b/src/LittleECS/Core/Core.h @@ -0,0 +1,43 @@ +#pragma once + +#include "CompilerInfo.h" + +#include + +#ifdef LECS_DEBUG + #define LECS_LOGGER_ENABLE + #define LECS_ASSERT_ENABLE +#endif + +#ifdef LECS_ASSERT_ENABLE + #define LECS_LOGGER_ENABLE +#endif + +#ifdef LECS_USE_PROJECTCORE + #include "UseProjectCore.h" +#endif + +#ifdef LECS_LOGGER_ENABLE + #define LECS_TRACE(...) // TODO: ? + #define LECS_INFO(...) // TODO: ? + #define LECS_WARN(...) // TODO: ? + #define LECS_ERROR(...) // TODO: ? + #define LECS_FATAL(...) // TODO: ? +#else + #define LECS_TRACE(...) + #define LECS_INFO(...) + #define LECS_WARN(...) + #define LECS_ERROR(...) + #define LECS_FATAL(...) +#endif + +#ifdef LECS_ASSERT_ENABLE + #ifdef LECS_COMPILER_MSVC + #define LECS_ASSERT(x, ...) if(!(x)) { LECS_FATAL("ASSERT FAILED! : " #x __VA_ARGS__); __debugbreak(); } + #else + #include + #define LECS_ASSERT(x, ...) if(!(x)) { LECS_FATAL("ASSERT FAILED! : " #x __VA_ARGS__); std::raise(SIGINT); } + #endif +#else + #define LECS_ASSERT(...) +#endif diff --git a/src/LittleECS/Core/UseProjectCore.h b/src/LittleECS/Core/UseProjectCore.h new file mode 100644 index 0000000..0aaedaa --- /dev/null +++ b/src/LittleECS/Core/UseProjectCore.h @@ -0,0 +1,24 @@ +#pragma once + +#include "ProjectCore/FMT.h" + +#ifdef LECS_LOGGER_ENABLE + #include "ProjectCore/FLog.h" + + namespace LECS + { + class Core + { + public: + static ProjectCore::FLog::BasicLogger& Logger() { return m_Logger; } + private: + static inline ProjectCore::FLog::BasicLogger m_Logger{}; + }; + } + + #define LECS_TRACE(...) LECS::Core::Logger().Trace(__VA_ARGS__) + #define LECS_INFO(...) LECS::Core::Logger().Info(__VA_ARGS__) + #define LECS_WARN(...) LECS::Core::Logger().Warn(__VA_ARGS__) + #define LECS_ERROR(...) LECS::Core::Logger().Error(__VA_ARGS__) + #define LECS_FATAL(...) LECS::Core::Logger().Fatal(__VA_ARGS__) +#endif diff --git a/src/LittleECS/Detail/ComponentId.h b/src/LittleECS/Detail/ComponentId.h index be3ed40..ab72db6 100644 --- a/src/LittleECS/Detail/ComponentId.h +++ b/src/LittleECS/Detail/ComponentId.h @@ -1,6 +1,7 @@ #pragma once -#include "Core.h" +#include "LittleECS/Core/Core.h" + #include namespace LECS @@ -50,11 +51,11 @@ namespace LECS namespace ProjectCore::FMT { - template - struct FormatterType { - static void Format(LECS::ComponentId typeId, FormatterContext& context) + template + struct FormatterType { + static void Format(LECS::ComponentId typeId, FormatterContext& context) { - FormatterType, FormatterContext>::Format(typeId, context); - } - }; + FormatterType, FormatterContext>::Format(typeId, context); + } + }; } diff --git a/src/LittleECS/Detail/ComponentIdGenerator.h b/src/LittleECS/Detail/ComponentIdGenerator.h index 942b0f7..6354f36 100644 --- a/src/LittleECS/Detail/ComponentIdGenerator.h +++ b/src/LittleECS/Detail/ComponentIdGenerator.h @@ -1,19 +1,19 @@ #pragma once -#include "Core.h" +#include "LittleECS/Core/Core.h" #include "ComponentId.h" #include -#if UTILITIES_COMPILER_GMAKE - #define LECS_FUNCTION_SIGNATURE_ID __PRETTY_FUNCTION__ - #define LECS_FUNCTION_SIGNATURE_ID_PREFIX '=' - #define LECS_FUNCTION_SIGNATURE_ID_SUFFIX ']' -#elif UTILITIES_COMPILER_VS +#ifdef LECS_COMPILER_MSVC #define LECS_FUNCTION_SIGNATURE_ID __FUNCSIG__ #define LECS_FUNCTION_SIGNATURE_ID_PREFIX '<' #define LECS_FUNCTION_SIGNATURE_ID_SUFFIX '>' +#else + #define LECS_FUNCTION_SIGNATURE_ID __PRETTY_FUNCTION__ + #define LECS_FUNCTION_SIGNATURE_ID_PREFIX '=' + #define LECS_FUNCTION_SIGNATURE_ID_SUFFIX ']' #endif namespace LECS::Detail diff --git a/src/LittleECS/Detail/Core.h b/src/LittleECS/Detail/Core.h deleted file mode 100644 index 507d101..0000000 --- a/src/LittleECS/Detail/Core.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "ProjectCore/FMT/FMT.h" -#include "ProjectCore/LoggerManager/LoggerManager.h" - -#include - -namespace LECS -{ - class Core - { - public: - static ProjectCore::LoggerManager::BasicLogger& Logger() { return m_Logger; } - - private: - static inline ProjectCore::LoggerManager::BasicLogger m_Logger{}; - }; -} - -#ifdef LECS_DEBUG - #define LECS_LOGGER_ENABLE - #define LECS_ASSERT_ENABLE -#endif - - -#ifdef LECS_ASSERT_ENABLE - #define LECS_LOGGER_ENABLE -#endif - -#ifdef LECS_LOGGER_ENABLE - #define LECS_TRACE(...) LECS::Core::Logger().Trace(__VA_ARGS__) - #define LECS_INFO(...) LECS::Core::Logger().Info(__VA_ARGS__) - #define LECS_WARN(...) LECS::Core::Logger().Warn(__VA_ARGS__) - #define LECS_ERROR(...) LECS::Core::Logger().Error(__VA_ARGS__) - #define LECS_FATAL(...) LECS::Core::Logger().Fatal(__VA_ARGS__) -#else - #define LECS_TRACE(...) - #define LECS_INFO(...) - #define LECS_WARN(...) - #define LECS_ERROR(...) - #define LECS_FATAL(...) -#endif - -#ifdef LECS_ASSERT_ENABLE - #ifdef UTILITIES_COMPILER_VS - #define LECS_ASSERT(x, ...) if(!(x)) { LECS_FATAL("ASSERT FAILED! : " #x __VA_ARGS__); __debugbreak(); } - #else - #include - #define LECS_ASSERT(x, ...) if(!(x)) { LECS_FATAL("ASSERT FAILED! : " #x __VA_ARGS__); std::raise(SIGINT); } - #endif -#else - #define LECS_ASSERT(x) -#endif diff --git a/src/LittleECS/Detail/EntityId.h b/src/LittleECS/Detail/EntityId.h index 4b3e999..352e6aa 100644 --- a/src/LittleECS/Detail/EntityId.h +++ b/src/LittleECS/Detail/EntityId.h @@ -1,6 +1,7 @@ #pragma once -#include "Core.h" +#include "LittleECS/Core/Core.h" + #include namespace LECS @@ -48,13 +49,15 @@ namespace LECS } } -namespace ProjectCore::FMT -{ - template - struct FormatterType { - static void Format(LECS::EntityId typeId, FormatterContext& context) - { - FormatterType, FormatterContext>::Format(typeId, context); - } - }; -} +#ifdef PROJECTCORE_FORMATTER_DECLARED + namespace ProjectCore::FMT + { + template + struct FormatterType { + static void Format(LECS::EntityId typeId, FormatterContext& context) + { + FormatterType, FormatterContext>::Format(typeId, context); + } + }; + } +#endif diff --git a/src/LittleECS/Detail/Iterable.h b/src/LittleECS/Detail/Iterable.h index da1c0ea..fb293c2 100644 --- a/src/LittleECS/Detail/Iterable.h +++ b/src/LittleECS/Detail/Iterable.h @@ -5,27 +5,27 @@ namespace LECS::Detail { template - struct Iterable - { - Iterable(Begin&& begin, End&& end) - : m_Begin(std::forward(begin)) - , m_End(std::forward(end)) - {} + struct Iterable + { + Iterable(Begin&& begin, End&& end) + : m_Begin(std::forward(begin)) + , m_End(std::forward(end)) + {} - Begin begin() - { + Begin begin() + { return m_Begin; - } + } - End end() - { + End end() + { return m_End; - } + } private: Begin m_Begin; End m_End; - }; + }; - struct IterableEnd {}; + struct IterableEnd {}; } diff --git a/src/LittleECS/Detail/TypeParameterPack.h b/src/LittleECS/Detail/TypeTraits.h similarity index 100% rename from src/LittleECS/Detail/TypeParameterPack.h rename to src/LittleECS/Detail/TypeTraits.h diff --git a/src/LittleECS/Registry/Entity/Entity.inl b/src/LittleECS/Entity/Entity-inl-r.h similarity index 71% rename from src/LittleECS/Registry/Entity/Entity.inl rename to src/LittleECS/Entity/Entity-inl-r.h index 9df3bfc..9529749 100644 --- a/src/LittleECS/Registry/Entity/Entity.inl +++ b/src/LittleECS/Entity/Entity-inl-r.h @@ -5,28 +5,28 @@ namespace LECS { inline ConstEntity::ConstEntity() - : m_Registry(nullptr) - , m_EntityId(EntityId::INVALID) - , m_ComponentsContainer() - {} - - inline ConstEntity::ConstEntity(const Registry* registry, EntityId entityId) - : m_Registry(registry) - , m_EntityId(entityId) - , m_ComponentsContainer() - { - LECS_ASSERT(m_EntityId != EntityId::INVALID) - LECS_ASSERT(m_Registry != nullptr) - LECS_ASSERT(m_Registry->RegistryHas(m_EntityId)) - - Refresh(); - } + : m_Registry(nullptr) + , m_EntityId(EntityId::INVALID) + , m_ComponentsContainer() + {} + + inline ConstEntity::ConstEntity(const Registry* registry, EntityId entityId) + : m_Registry(registry) + , m_EntityId(entityId) + , m_ComponentsContainer() + { + LECS_ASSERT(m_EntityId != EntityId::INVALID) + LECS_ASSERT(m_Registry != nullptr) + LECS_ASSERT(m_Registry->RegistryHas(m_EntityId)) + + Refresh(); + } inline void ConstEntity::Refresh() { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) - for (auto& container : m_Registry->GetComponentIdToComponentData()) + for (auto& container : m_Registry->GetComponentIdToComponentData()) { const void* component = container.second.ComponentStorage->GetComponentAliasedPtrV(m_EntityId); if (component != nullptr) @@ -39,11 +39,11 @@ namespace LECS template const ComponentType* ConstEntity::GetComponentPtr() const { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) ComponentId componentId = Registry::ComponentIdGenerator::GetTypeId(); - const auto component = m_ComponentsContainer.find(componentId); + const auto component = m_ComponentsContainer.find(componentId); if (component == m_ComponentsContainer.end()) return nullptr; @@ -52,9 +52,9 @@ namespace LECS } template - bool ConstEntity::Has() const + bool ConstEntity::Has() const { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) if constexpr (Detail::ComponentStorageInfo::PTR_TO_COMPONENT_VALID) { @@ -69,7 +69,7 @@ namespace LECS template const ComponentType& ConstEntity::Get() const { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) if constexpr (Detail::ComponentStorageInfo::PTR_TO_COMPONENT_VALID) { @@ -83,7 +83,7 @@ namespace LECS template const ComponentType* ConstEntity::GetPtr() const { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) if constexpr (Detail::ComponentStorageInfo::PTR_TO_COMPONENT_VALID) { @@ -97,9 +97,9 @@ namespace LECS template std::tuple ConstEntity::GetAll() const { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) - return std::tuple(Get(m_EntityId)...); + return std::tuple(Get(m_EntityId)...); } } @@ -116,15 +116,15 @@ namespace LECS template std::tuple Entity::GetAll() { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) - return std::tuple(Get(m_EntityId)...); + return std::tuple(Get(m_EntityId)...); } template ComponentType& Entity::Add(Args&&... args) { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) ComponentId componentId = Registry::ComponentIdGenerator::GetTypeId(); diff --git a/src/LittleECS/Registry/Entity/Entity.h b/src/LittleECS/Entity/Entity.h similarity index 68% rename from src/LittleECS/Registry/Entity/Entity.h rename to src/LittleECS/Entity/Entity.h index 328ae75..aa907f7 100644 --- a/src/LittleECS/Registry/Entity/Entity.h +++ b/src/LittleECS/Entity/Entity.h @@ -7,16 +7,16 @@ namespace LECS { - class Registry; + class Registry; class ConstEntity { public: - using ComponentsContainer = std::unordered_map; + using ComponentsContainer = std::unordered_map; public: - ConstEntity(); - ConstEntity(const Registry* registry, EntityId entityId); + ConstEntity(); + ConstEntity(const Registry* registry, EntityId entityId); protected: const Registry* m_Registry; @@ -24,16 +24,16 @@ namespace LECS ComponentsContainer m_ComponentsContainer; public: - bool IsValid() const + bool IsValid() const { return m_EntityId != EntityId::INVALID && m_Registry != nullptr; } - void Invalidate() - { - m_EntityId = EntityId::INVALID; - m_Registry = nullptr; - } + void Invalidate() + { + m_EntityId = EntityId::INVALID; + m_Registry = nullptr; + } public: void Refresh(); @@ -49,20 +49,20 @@ namespace LECS public: template - bool Has() const; + bool Has() const; template - const ComponentType& Get() const; - template - const ComponentType* GetPtr() const; - template - std::tuple GetAll() const; + const ComponentType& Get() const; + template + const ComponentType* GetPtr() const; + template + std::tuple GetAll() const; }; class Entity : public ConstEntity { public: - using ComponentsContainer = std::unordered_map; + using ComponentsContainer = std::unordered_map; public: Entity(); @@ -84,43 +84,43 @@ namespace LECS public: template - bool Has() const + bool Has() const { return ConstEntity::template Has(); } template - const ComponentType& Get() const + const ComponentType& Get() const { return ConstEntity::template Get(); } template - ComponentType& Get() + ComponentType& Get() { return const_cast(ConstEntity::template Get()); } - template - const ComponentType* GetPtr() const + template + const ComponentType* GetPtr() const { return ConstEntity::template GetPtr(); } template - ComponentType* GetPtr() + ComponentType* GetPtr() { return const_cast(ConstEntity::template GetPtr()); } - template - std::tuple GetAll() const + template + std::tuple GetAll() const { return ConstEntity::template GetAll(); } template - std::tuple GetAll(); + std::tuple GetAll(); public: template - ComponentType& Add(Args&&... args); + ComponentType& Add(Args&&... args); }; } diff --git a/src/LittleECS/Registry/Entity/LiteEntity.inl b/src/LittleECS/Entity/LiteEntity-inl-r.h similarity index 59% rename from src/LittleECS/Registry/Entity/LiteEntity.inl rename to src/LittleECS/Entity/LiteEntity-inl-r.h index 530ebb0..dbc3865 100644 --- a/src/LittleECS/Registry/Entity/LiteEntity.inl +++ b/src/LittleECS/Entity/LiteEntity-inl-r.h @@ -4,25 +4,25 @@ namespace LECS { - inline LiteEntity::LiteEntity() - : m_Registry(nullptr) - , m_EntityId(EntityId::INVALID) - { - } + inline LiteEntity::LiteEntity() + : m_Registry(nullptr) + , m_EntityId(EntityId::INVALID) + { + } - inline LiteEntity::LiteEntity(Registry* registry, EntityId entityId) - : m_Registry(registry) - , m_EntityId(entityId) - { - LECS_ASSERT(m_EntityId != EntityId::INVALID) - LECS_ASSERT(m_Registry != nullptr) - LECS_ASSERT(m_Registry->RegistryHas(m_EntityId)) - } + inline LiteEntity::LiteEntity(Registry* registry, EntityId entityId) + : m_Registry(registry) + , m_EntityId(entityId) + { + LECS_ASSERT(m_EntityId != EntityId::INVALID) + LECS_ASSERT(m_Registry != nullptr) + LECS_ASSERT(m_Registry->RegistryHas(m_EntityId)) + } template - bool LiteEntity::Has() const + bool LiteEntity::Has() const { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) return m_Registry->Has(m_EntityId); } @@ -30,7 +30,7 @@ namespace LECS template const ComponentType& LiteEntity::Get() const { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) return m_Registry->Get(m_EntityId); } @@ -38,7 +38,7 @@ namespace LECS template ComponentType& LiteEntity::Get() { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) return m_Registry->Get(m_EntityId); } @@ -46,7 +46,7 @@ namespace LECS template std::tuple LiteEntity::GetAll() const { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) return m_Registry->GetAll(m_EntityId); } @@ -54,15 +54,15 @@ namespace LECS template std::tuple LiteEntity::GetAll() { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) return m_Registry->GetAll(m_EntityId); } template - ComponentType& LiteEntity::Add(Args&&... args) + ComponentType& LiteEntity::Add(Args&&... args) { - LECS_ASSERT(IsValid()) + LECS_ASSERT(IsValid()) return m_Registry->Add(m_EntityId, std::forward(args)...); } diff --git a/src/LittleECS/Registry/Entity/LiteEntity.h b/src/LittleECS/Entity/LiteEntity.h similarity index 60% rename from src/LittleECS/Registry/Entity/LiteEntity.h rename to src/LittleECS/Entity/LiteEntity.h index ecde91e..603a200 100644 --- a/src/LittleECS/Registry/Entity/LiteEntity.h +++ b/src/LittleECS/Entity/LiteEntity.h @@ -9,8 +9,8 @@ namespace LECS class LiteEntity { public: - LiteEntity(); - LiteEntity(Registry* registry, EntityId entityId); + LiteEntity(); + LiteEntity(Registry* registry, EntityId entityId); protected: Registry* m_Registry; @@ -22,29 +22,29 @@ namespace LECS inline operator bool () { return m_EntityId != EntityId::INVALID; } public: - bool IsValid() const + bool IsValid() const { return m_EntityId != EntityId::INVALID && m_Registry != nullptr; } - void Invalidate() - { - m_EntityId = EntityId::INVALID; - m_Registry = nullptr; - } + void Invalidate() + { + m_EntityId = EntityId::INVALID; + m_Registry = nullptr; + } public: template - bool Has() const; + bool Has() const; template - const ComponentType& Get() const; + const ComponentType& Get() const; template - ComponentType& Get(); - template - std::tuple GetAll() const; + ComponentType& Get(); + template + std::tuple GetAll() const; template - std::tuple GetAll(); + std::tuple GetAll(); template - ComponentType& Add(Args&&... args); + ComponentType& Add(Args&&... args); }; } \ No newline at end of file diff --git a/src/LittleECS/LittleECS.h b/src/LittleECS/LittleECS.h index d2318a9..c0d6654 100644 --- a/src/LittleECS/LittleECS.h +++ b/src/LittleECS/LittleECS.h @@ -1,3 +1,8 @@ #pragma once +/****** Registry ******/ #include "Registry/Registry.h" + +/****** Components Storages ******/ +#include "ComponentStrorages/FastComponentStorage/FastComponentStorage.h" +#include "ComponentStrorages/CompressedComponentStorage/CompressedComponentStorage.h" diff --git a/src/LittleECS/Registry/FastComponentStorage/FCSIterator.h b/src/LittleECS/Registry/FastComponentStorage/FCSIterator.h deleted file mode 100644 index 04e2d3d..0000000 --- a/src/LittleECS/Registry/FastComponentStorage/FCSIterator.h +++ /dev/null @@ -1,122 +0,0 @@ -#pragma once - -#include "FastComponentStorage.h" - -#include "LittleECS/Detail/Iterable.h" - -namespace LECS::Detail -{ - template - class FCSIteratorNoRef - { - public: - using iterator_category = std::forward_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = EntityId; - using pointer = const EntityId*; - using reference = EntityId; - - public: - FCSIteratorNoRef(const FastComponentStorage* fastComponentStorage, ContainerIterator containerIterator, ContainerIterator containerIteratorLast) - : m_FastComponentStorage(fastComponentStorage) - , m_ContainerIterator(containerIterator) - , m_ContainerIteratorLast(containerIteratorLast) - {} - - public: - reference operator*() const - { - return m_ContainerIterator.operator*(); - } - pointer operator->() - { - return m_ContainerIterator.operator->(); - } - - FCSIteratorNoRef& operator++() - { - bool currentEntityValid = false; - do - { - ++m_ContainerIterator; - if (m_ContainerIterator == m_ContainerIteratorLast) - break; - - EntityId entity = *m_ContainerIterator; - currentEntityValid = m_FastComponentStorage->HasThisComponent(entity); - } while (currentEntityValid == false); - - if (currentEntityValid == false) - { - m_FastComponentStorage = nullptr; - } - - return *this; - } - - FCSIteratorNoRef operator++(int) - { - FCSIteratorNoRef res = this; - ++(*this); - return res; - } - - bool operator==(const FCSIteratorNoRef& rhs) const - { -#ifdef LECS_DEBUG - bool complexResult = m_FastComponentStorage != nullptr && - m_FastComponentStorage == rhs.m_FastComponentStorage && - m_ContainerIterator == rhs.m_ContainerIterator && - m_ContainerIteratorLast == rhs.m_ContainerIteratorLast; - bool simpleResult = m_FastComponentStorage != nullptr; - - LECS_ASSERT(simpleResult == complexResult, "Operator== for Iterator is wrong") - - return simpleResult; -#else - return m_FastComponentStorage != nullptr; -#endif - } - - bool operator!=(const FCSIteratorNoRef& rhs) const { return !(*this == rhs); } - - bool operator==(IterableEnd rhs) { return m_FastComponentStorage == nullptr; } - bool operator!=(IterableEnd rhs) { return !(*this == rhs); } - - private: - const FastComponentStorage* m_FastComponentStorage; - ContainerIterator m_ContainerIterator; - ContainerIterator m_ContainerIteratorLast; - }; - - template - requires (TypeValidForComponentStorage::Value) - decltype(auto) FastComponentStorage::EntitiesIteratorBegin() const - requires (ComponentStorageInfo::HAS_ENTITIES_REF && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) - { - return m_AliveEntitiesContainer.cbegin(); - } - template - requires (TypeValidForComponentStorage::Value) - decltype(auto) FastComponentStorage::EntitiesIteratorEnd() const - requires (ComponentStorageInfo::HAS_ENTITIES_REF && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) - { - return m_AliveEntitiesContainer.cend(); - } - - template - requires (TypeValidForComponentStorage::Value) - decltype(auto) FastComponentStorage::EntitiesIteratorBegin(const auto& registryAliveEntities) const - requires (ComponentStorageInfo::HAS_ENTITIES_REF == false && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH) - { - return FCSIteratorNoRef(this, registryAliveEntities.cbegin(), registryAliveEntities.cend()); - } - - template - requires (TypeValidForComponentStorage::Value) - decltype(auto) FastComponentStorage::EntitiesIteratorEnd(const auto&) const - requires (ComponentStorageInfo::HAS_ENTITIES_REF == false && ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH) - { - return IterableEnd(); - } -} diff --git a/src/LittleECS/Registry/IComponentStorage.h b/src/LittleECS/Registry/IComponentStorage.h index 5e6674d..9a6c1ed 100644 --- a/src/LittleECS/Registry/IComponentStorage.h +++ b/src/LittleECS/Registry/IComponentStorage.h @@ -46,12 +46,12 @@ namespace LECS::Detail public: virtual ~IComponentStorage() = default; - public: - virtual bool HasThisComponentV(EntityId entity) const = 0; - virtual void RemoveComponentOfEntityV(EntityId entity) = 0; - virtual const void* GetComponentAliasedPtrV(EntityId entity) const = 0; - virtual void* GetComponentAliasedPtrV(EntityId entity) = 0; - }; + public: + virtual bool HasThisComponentV(EntityId entity) const = 0; + virtual void RemoveComponentOfEntityV(EntityId entity) = 0; + virtual const void* GetComponentAliasedPtrV(EntityId entity) const = 0; + virtual void* GetComponentAliasedPtrV(EntityId entity) = 0; + }; template struct TypeValidForComponentStorage @@ -67,14 +67,13 @@ namespace LECS::Detail requires (TypeValidForComponentStorage::Value) class CompressedComponentStorage; - - template + template struct DefaultComponentStorageInfo { struct FastComponent { using StorageType = FastComponentStorage; - static constexpr Index::GlobalIndexOfComponent PAGE_SIZE = 1024; + static constexpr Index::GlobalIndexOfComponent PAGE_SIZE = 1024; static constexpr bool HAS_ENTITIES_REF = true; static constexpr bool USE_MAP_VERSION = false; static constexpr bool SEND_ENTITIES_POOL_ON_EACH = false; @@ -85,7 +84,7 @@ namespace LECS::Detail struct FastComponentWithoutREF { using StorageType = FastComponentStorage; - static constexpr Index::GlobalIndexOfComponent PAGE_SIZE = 1024; + static constexpr Index::GlobalIndexOfComponent PAGE_SIZE = 1024; static constexpr bool HAS_ENTITIES_REF = false; static constexpr bool USE_MAP_VERSION = false; static constexpr bool SEND_ENTITIES_POOL_ON_EACH = true; @@ -118,7 +117,7 @@ namespace LECS::Detail using Default = FastComponent; }; - template + template struct ComponentStorageInfo : public DefaultComponentStorageInfo::Default{}; } diff --git a/src/LittleECS/Registry/Registry-inl.h b/src/LittleECS/Registry/Registry-inl.h new file mode 100644 index 0000000..700ca30 --- /dev/null +++ b/src/LittleECS/Registry/Registry-inl.h @@ -0,0 +1,128 @@ +#pragma once + +#include "Registry.h" + +namespace LECS +{ + template + typename Detail::ComponentStorageInfo::StorageType* Registry::GetComponentStorageOrCreateIt() + { + ComponentId componentId = ComponentIdGenerator::GetTypeId(); + + if (m_ComponentIdToComponentData.contains(componentId) == true) + { + Detail::IComponentStorage* componentStorageBasic = m_ComponentIdToComponentData[componentId].ComponentStorage.get(); + return reinterpret_cast::StorageType*>(componentStorageBasic); + } + else + { + std::unique_ptr& componentStorageRef = + m_ComponentIdToComponentData[componentId].ComponentStorage = std::make_unique::StorageType>(); + Detail::IComponentStorage* componentStorageBasic = componentStorageRef.get(); + return reinterpret_cast::StorageType*>(componentStorageBasic); + } + + return nullptr; + } + + template + const typename Detail::ComponentStorageInfo::StorageType* Registry::GetComponentStorage() const + { + ComponentId componentId = ComponentIdGenerator::GetTypeId(); + + const auto componentStorage = m_ComponentIdToComponentData.find(componentId); + + LECS_ASSERT(componentStorage != m_ComponentIdToComponentData.end(), "This ComponentStorage is not part of this registry") + + const Detail::IComponentStorage* componentStorageBasic = componentStorage->second.ComponentStorage.get(); + return reinterpret_cast::StorageType*>(componentStorageBasic); + } + + template + ComponentType& Registry::Add(EntityId entity, Args&&... args) + { + typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorageOrCreateIt(); + LECS_ASSERT(componentStorage != nullptr, "This ComponentStorage is not part of this registry") + return componentStorage->AddComponentToEntity(entity, std::forward(args)...); + } + + template + bool Registry::Has(EntityId entity) + { + ComponentId componentId = ComponentIdGenerator::GetTypeId(); + + auto componentStoragefound = m_ComponentIdToComponentData.find(componentId); + + if (componentStoragefound == m_ComponentIdToComponentData.end()) + return false; + + Detail::IComponentStorage* componentStorageBasic = componentStoragefound->second.ComponentStorage.get(); + typename Detail::ComponentStorageInfo::StorageType* componentStorage = reinterpret_cast::StorageType*>(componentStorageBasic); + + if (componentStorage == nullptr) + return false; + + return componentStorage->HasThisComponent(entity); + } + + template + bool Registry::HasAll(EntityId entity) + { + if constexpr (sizeof...(ComponentTypes) == 0) + return HasComponent(entity); + else + return HasComponent(entity) && HasAllComponents(entity); + } + + template + const ComponentType& Registry::Get(EntityId entity) const + { + const typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); + LECS_ASSERT(componentStorage != nullptr, "This ComponentStorage is not part of this registry") + return componentStorage->GetComponentOfEntity(entity); + } + template + ComponentType& Registry::Get(EntityId entity) + { + typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); + LECS_ASSERT(componentStorage != nullptr, "This ComponentStorage is not part of this registry") + return componentStorage->GetComponentOfEntity(entity); + } + + template + const ComponentType* Registry::GetPtr(EntityId entity) const + { + const typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); + if (componentStorage == nullptr) + return nullptr; + return componentStorage->GetComponentOfEntityPtr(entity); + } + template + ComponentType* Registry::GetPtr(EntityId entity) + { + typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); + if (componentStorage == nullptr) + return nullptr; + return componentStorage->GetComponentOfEntityPtr(entity); + } + + template + std::tuple Registry::GetAll(EntityId entity) const + { + return std::tuple(Get(entity)...); + } + template + std::tuple Registry::GetAll(EntityId entity) + { + return std::tuple(Get(entity)...); + } + + // Function = std::function + template + void Registry::ForEachEntities(Function&& function) + { + for (EntityId entity : m_EntityIdGenerator.GetAlivesEntities()) + function(entity); + } + +} \ No newline at end of file diff --git a/src/LittleECS/Registry/Registry.h b/src/LittleECS/Registry/Registry.h index b3fa74d..5773c8c 100644 --- a/src/LittleECS/Registry/Registry.h +++ b/src/LittleECS/Registry/Registry.h @@ -2,11 +2,10 @@ #include "LittleECS/Detail/EntityIdGenerator.h" -#include "CompressedComponentStorage/CompressedComponentStorage.h" -#include "FastComponentStorage/FastComponentStorage.h" +#include "IComponentStorage.h" -#include "Entity/Entity.h" -#include "Entity/LiteEntity.h" +#include "LittleECS/Entity/Entity.h" +#include "LittleECS/Entity/LiteEntity.h" #include "Views/BasicView.h" @@ -15,166 +14,163 @@ namespace LECS { - class Registry - { - public: - struct ComponentData - { - std::unique_ptr ComponentStorage; - std::function OnConstruct; - std::function OnDestruct; - }; - using ComponentIdToComponentData = std::unordered_map; - using ComponentIdGenerator = Detail::CompilerComponentIdGenerator; - - public: - Registry() {} - - protected: - ComponentIdToComponentData m_ComponentIdToComponentData; - Detail::EntityIdGenerator m_EntityIdGenerator; - - // Entity Management - public: - const Detail::EntityIdGenerator& GetEntityIdGenerator() const - { - return m_EntityIdGenerator; - } - const ComponentIdToComponentData& GetComponentIdToComponentData() const - { - return m_ComponentIdToComponentData; - } - - bool RegistryHas(EntityId entity) const - { - return m_EntityIdGenerator.HasEntityId(entity); - } - - EntityId CreateEntityId() - { - return m_EntityIdGenerator.GetNewEntityId(); - } - - void DestroyEntityId(EntityId entity) - { - for (auto& container : m_ComponentIdToComponentData) - { - if (container.second.ComponentStorage->HasThisComponentV(entity)) - { - container.second.ComponentStorage->RemoveComponentOfEntityV(entity); - } - } - - m_EntityIdGenerator.EntityIdDelete(entity); - } - - Entity CreateEntityFrom(EntityId entity) - { - return Entity(this, entity); - } - - LiteEntity CreateLiteEntityFrom(EntityId entity) - { - return LiteEntity(this, entity); - } - - public: - template - typename Detail::ComponentStorageInfo::StorageType* GetComponentStorageOrCreateIt(); - - template - void CreateComponentStorage() - { - GetComponentStorageOrCreateIt(); - } - - template - const typename Detail::ComponentStorageInfo::StorageType* GetComponentStorage() const; - - template - typename Detail::ComponentStorageInfo::StorageType* GetComponentStorage() - { - return const_cast::StorageType*>(const_cast(this)->GetComponentStorage()); - } - - public: - template - ComponentType& Add(EntityId entity, Args&&... args); - - template - bool Has(EntityId entity); - - template - bool HasAll(EntityId entity); - - public: - template - const ComponentType& Get(EntityId entity) const; - template - ComponentType& Get(EntityId entity); - - template - const ComponentType* GetPtr(EntityId entity) const; - template - ComponentType* GetPtr(EntityId entity); - - template - std::tuple GetAll(EntityId entity) const; - template - std::tuple GetAll(EntityId entity); - - public: - template - BasicView View() - { - return BasicView(*this); - } - - public: - // Function = std::function - template - void ForEachEntities(Function&& function); - - // Function = std::function - template - void ForEachUniqueComponent(Function&& function); - // Function = std::function - template - void ForEachUniqueComponent(Function&& function) const; - // Function = std::function - template - void ForEachComponents(Function&& function); - // Function = std::function - template - void ForEachComponents(Function&& function) const; - - public: - const auto& EachEntities() - { - return m_EntityIdGenerator.GetAlivesEntities(); - } - - template - decltype(auto) EachEntitiesWith(); - template - decltype(auto) EachEntitiesWith() const; - - // TODO - // template - // decltype(auto) EachUniqueComponent(); - // template - // decltype(auto) EachUniqueComponent() const; - }; + class Registry + { + public: + struct ComponentData + { + std::unique_ptr ComponentStorage; + std::function OnConstruct; + std::function OnDestruct; + }; + using ComponentIdToComponentData = std::unordered_map; + using ComponentIdGenerator = Detail::CompilerComponentIdGenerator; + + public: + Registry() {} + + protected: + ComponentIdToComponentData m_ComponentIdToComponentData; + Detail::EntityIdGenerator m_EntityIdGenerator; + + // Entity Management + public: + const Detail::EntityIdGenerator& GetEntityIdGenerator() const + { + return m_EntityIdGenerator; + } + const ComponentIdToComponentData& GetComponentIdToComponentData() const + { + return m_ComponentIdToComponentData; + } + + bool RegistryHas(EntityId entity) const + { + return m_EntityIdGenerator.HasEntityId(entity); + } + + EntityId CreateEntityId() + { + return m_EntityIdGenerator.GetNewEntityId(); + } + + void DestroyEntityId(EntityId entity) + { + for (auto& container : m_ComponentIdToComponentData) + { + if (container.second.ComponentStorage->HasThisComponentV(entity)) + { + container.second.ComponentStorage->RemoveComponentOfEntityV(entity); + } + } + + m_EntityIdGenerator.EntityIdDelete(entity); + } + + Entity CreateEntityFrom(EntityId entity) + { + return Entity(this, entity); + } + + LiteEntity CreateLiteEntityFrom(EntityId entity) + { + return LiteEntity(this, entity); + } + + public: + template + typename Detail::ComponentStorageInfo::StorageType* GetComponentStorageOrCreateIt(); + + template + void CreateComponentStorage() + { + GetComponentStorageOrCreateIt(); + } + + template + const typename Detail::ComponentStorageInfo::StorageType* GetComponentStorage() const; + + template + typename Detail::ComponentStorageInfo::StorageType* GetComponentStorage() + { + return const_cast::StorageType*>(const_cast(this)->GetComponentStorage()); + } + + public: + template + ComponentType& Add(EntityId entity, Args&&... args); + + template + bool Has(EntityId entity); + + template + bool HasAll(EntityId entity); + + public: + template + const ComponentType& Get(EntityId entity) const; + template + ComponentType& Get(EntityId entity); + + template + const ComponentType* GetPtr(EntityId entity) const; + template + ComponentType* GetPtr(EntityId entity); + + template + std::tuple GetAll(EntityId entity) const; + template + std::tuple GetAll(EntityId entity); + + public: + template + BasicView View() + { + return BasicView(*this); + } + + public: + // Function = std::function + template + void ForEachEntities(Function&& function); + + // Function = std::function + template + void ForEachUniqueComponent(Function&& function); + // Function = std::function + template + void ForEachUniqueComponent(Function&& function) const; + // Function = std::function + template + void ForEachComponents(Function&& function); + // Function = std::function + template + void ForEachComponents(Function&& function) const; + + public: + const auto& EachEntities() + { + return m_EntityIdGenerator.GetAlivesEntities(); + } + + template + decltype(auto) EachEntitiesWith(); + template + decltype(auto) EachEntitiesWith() const; + + // TODO + // template + // decltype(auto) EachUniqueComponent(); + // template + // decltype(auto) EachUniqueComponent() const; + }; } -#include "Registry.inl" +#include "Registry-inl.h" +#include "RegistryForEach-inl.h" +#include "RegistryIterator-inl.h" -#include "RegistryForEach.h" -#include "RegistryIterator.h" +#include "Views/BasicView-inl-r.h" -#include "Entity/Entity.inl" -#include "Entity/LiteEntity.inl" - -#include "Views/BasicView.inl" -#include "Views/BasicViewForEach.h" -#include "Views/BasicViewIterator.h" +#include "LittleECS/Entity/Entity-inl-r.h" +#include "LittleECS/Entity/LiteEntity-inl-r.h" \ No newline at end of file diff --git a/src/LittleECS/Registry/Registry.inl b/src/LittleECS/Registry/Registry.inl deleted file mode 100644 index 2142edc..0000000 --- a/src/LittleECS/Registry/Registry.inl +++ /dev/null @@ -1,128 +0,0 @@ -#pragma once - -#include "Registry.h" - -namespace LECS -{ - template - typename Detail::ComponentStorageInfo::StorageType* Registry::GetComponentStorageOrCreateIt() - { - ComponentId componentId = ComponentIdGenerator::GetTypeId(); - - if (m_ComponentIdToComponentData.contains(componentId) == true) - { - Detail::IComponentStorage* componentStorageBasic = m_ComponentIdToComponentData[componentId].ComponentStorage.get(); - return reinterpret_cast::StorageType*>(componentStorageBasic); - } - else - { - std::unique_ptr& componentStorageRef = - m_ComponentIdToComponentData[componentId].ComponentStorage = std::make_unique::StorageType>(); - Detail::IComponentStorage* componentStorageBasic = componentStorageRef.get(); - return reinterpret_cast::StorageType*>(componentStorageBasic); - } - - return nullptr; - } - - template - const typename Detail::ComponentStorageInfo::StorageType* Registry::GetComponentStorage() const - { - ComponentId componentId = ComponentIdGenerator::GetTypeId(); - - const auto componentStorage = m_ComponentIdToComponentData.find(componentId); - - LECS_ASSERT(componentStorage != m_ComponentIdToComponentData.end(), "This ComponentStorage is not part of this registry") - - const Detail::IComponentStorage* componentStorageBasic = componentStorage->second.ComponentStorage.get(); - return reinterpret_cast::StorageType*>(componentStorageBasic); - } - - template - ComponentType& Registry::Add(EntityId entity, Args&&... args) - { - typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorageOrCreateIt(); - LECS_ASSERT(componentStorage != nullptr, "This ComponentStorage is not part of this registry") - return componentStorage->AddComponentToEntity(entity, std::forward(args)...); - } - - template - bool Registry::Has(EntityId entity) - { - ComponentId componentId = ComponentIdGenerator::GetTypeId(); - - auto componentStoragefound = m_ComponentIdToComponentData.find(componentId); - - if (componentStoragefound == m_ComponentIdToComponentData.end()) - return false; - - Detail::IComponentStorage* componentStorageBasic = componentStoragefound->second.ComponentStorage.get(); - typename Detail::ComponentStorageInfo::StorageType* componentStorage = reinterpret_cast::StorageType*>(componentStorageBasic); - - if (componentStorage == nullptr) - return false; - - return componentStorage->HasThisComponent(entity); - } - - template - bool Registry::HasAll(EntityId entity) - { - if constexpr (sizeof...(ComponentTypes) == 0) - return HasComponent(entity); - else - return HasComponent(entity) && HasAllComponents(entity); - } - - template - const ComponentType& Registry::Get(EntityId entity) const - { - const typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); - LECS_ASSERT(componentStorage != nullptr, "This ComponentStorage is not part of this registry") - return componentStorage->GetComponentOfEntity(entity); - } - template - ComponentType& Registry::Get(EntityId entity) - { - typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); - LECS_ASSERT(componentStorage != nullptr, "This ComponentStorage is not part of this registry") - return componentStorage->GetComponentOfEntity(entity); - } - - template - const ComponentType* Registry::GetPtr(EntityId entity) const - { - const typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); - if (componentStorage == nullptr) - return nullptr; - return componentStorage->GetComponentOfEntityPtr(entity); - } - template - ComponentType* Registry::GetPtr(EntityId entity) - { - typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); - if (componentStorage == nullptr) - return nullptr; - return componentStorage->GetComponentOfEntityPtr(entity); - } - - template - std::tuple Registry::GetAll(EntityId entity) const - { - return std::tuple(Get(entity)...); - } - template - std::tuple Registry::GetAll(EntityId entity) - { - return std::tuple(Get(entity)...); - } - - // Function = std::function - template - void Registry::ForEachEntities(Function&& function) - { - for (EntityId entity : m_EntityIdGenerator.GetAlivesEntities()) - function(entity); - } - -} \ No newline at end of file diff --git a/src/LittleECS/Registry/RegistryForEach-inl.h b/src/LittleECS/Registry/RegistryForEach-inl.h new file mode 100644 index 0000000..a3fc8ee --- /dev/null +++ b/src/LittleECS/Registry/RegistryForEach-inl.h @@ -0,0 +1,72 @@ +#pragma once + +#include "Registry.h" + +namespace LECS +{ + // Function = std::function + template + void Registry::ForEachUniqueComponent(Function&& function) + { + typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); + if (componentStorage == nullptr) + return; + + if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) + { + componentStorage->ForEachStorage(std::forward(function)); + } + else + { + componentStorage->ForEachStorage(std::forward(function), m_EntityIdGenerator.GetAlivesEntities()); + } + } + + // Function = std::function + template + void Registry::ForEachUniqueComponent(Function&& function) const + { + const typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); + if (componentStorage == nullptr) + return; + + if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) + { + componentStorage->ForEachStorage(std::forward(function)); + } + else + { + componentStorage->ForEachStorage(std::forward(function), m_EntityIdGenerator.GetAlivesEntities()); + } + } + + // Function = std::function + template + void Registry::ForEachComponents(Function&& function) + { + if constexpr (sizeof...(ComponentTypes) == 1) + { + return ForEachUniqueComponent(std::forward(function)); + } + else + { + BasicView view(*this); + view.template ForEachComponents(std::forward(function)); + } + } + + // Function = std::function + template + void Registry::ForEachComponents(Function&& function) const + { + if constexpr (sizeof...(ComponentTypes) == 1) + { + return ForEachUniqueComponent(std::forward(function)); + } + else + { + BasicConstView view(*this); + view.template ForEachComponents(std::forward(function)); + } + } +} diff --git a/src/LittleECS/Registry/RegistryForEach.h b/src/LittleECS/Registry/RegistryForEach.h deleted file mode 100644 index b91bff1..0000000 --- a/src/LittleECS/Registry/RegistryForEach.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include "Registry.h" - -namespace LECS -{ - // Function = std::function - template - void Registry::ForEachUniqueComponent(Function&& function) - { - typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); - if (componentStorage == nullptr) - return; - - if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) - { - componentStorage->ForEachStorage(std::forward(function)); - } - else - { - componentStorage->ForEachStorage(std::forward(function), m_EntityIdGenerator.GetAlivesEntities()); - } - } - - // Function = std::function - template - void Registry::ForEachUniqueComponent(Function&& function) const - { - const typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); - if (componentStorage == nullptr) - return; - - if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) - { - componentStorage->ForEachStorage(std::forward(function)); - } - else - { - componentStorage->ForEachStorage(std::forward(function), m_EntityIdGenerator.GetAlivesEntities()); - } - } - - // Function = std::function - template - void Registry::ForEachComponents(Function&& function) - { - if constexpr (sizeof...(ComponentTypes) == 1) - { - return ForEachUniqueComponent(std::forward(function)); - } - else - { - BasicView view(*this); - view.template ForEachComponents(std::forward(function)); - } - } - - // Function = std::function - template - void Registry::ForEachComponents(Function&& function) const - { - if constexpr (sizeof...(ComponentTypes) == 1) - { - return ForEachUniqueComponent(std::forward(function)); - } - else - { - BasicConstView view(*this); - view.template ForEachComponents(std::forward(function)); - } - } -} diff --git a/src/LittleECS/Registry/RegistryIterator.h b/src/LittleECS/Registry/RegistryIterator-inl.h similarity index 58% rename from src/LittleECS/Registry/RegistryIterator.h rename to src/LittleECS/Registry/RegistryIterator-inl.h index 1584654..20db40f 100644 --- a/src/LittleECS/Registry/RegistryIterator.h +++ b/src/LittleECS/Registry/RegistryIterator-inl.h @@ -6,32 +6,32 @@ namespace LECS { - template - decltype(auto) Registry::EachEntitiesWith() - { - typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); + template + decltype(auto) Registry::EachEntitiesWith() + { + typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); LECS_ASSERT(componentStorage, "Component storage can't be non referenced when getting iterators") - - if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) + + if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) return Detail::Iterable(componentStorage->EntitiesIteratorBegin(), componentStorage->EntitiesIteratorEnd()); - else + else return Detail::Iterable(componentStorage->EntitiesIteratorBegin(this->m_EntityIdGenerator.GetAlivesEntities()), - componentStorage->EntitiesIteratorEnd(this->m_EntityIdGenerator.GetAlivesEntities()) - ); - } - template - decltype(auto) Registry::EachEntitiesWith() const - { + componentStorage->EntitiesIteratorEnd(this->m_EntityIdGenerator.GetAlivesEntities()) + ); + } + template + decltype(auto) Registry::EachEntitiesWith() const + { const typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorage(); LECS_ASSERT(componentStorage, "Component storage can't be non referenced when getting iterators") - - if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) + + if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) return Detail::Iterable(componentStorage->EntitiesIteratorBegin(), componentStorage->EntitiesIteratorEnd()); - else + else return Detail::Iterable(componentStorage->EntitiesIteratorBegin(this->m_EntityIdGenerator.GetAlivesEntities()), componentStorage->EntitiesIteratorEnd(this->m_EntityIdGenerator.GetAlivesEntities()) - ); - } + ); + } } diff --git a/src/LittleECS/Registry/Views/BasicView-inl-r.h b/src/LittleECS/Registry/Views/BasicView-inl-r.h new file mode 100644 index 0000000..7f026ea --- /dev/null +++ b/src/LittleECS/Registry/Views/BasicView-inl-r.h @@ -0,0 +1,29 @@ +#pragma once + +#include "BasicView.h" + +#include "LittleECS/Registry/Registry.h" + +namespace LECS +{ + template + template + void BasicConstView::RefreshRegistryLink() + { + m_LinkToComponentContainer[I] = m_LinkedRegistry.GetComponentStorage(); + LECS_ASSERT(m_LinkToComponentContainer[I] != nullptr, "Can't create a view with an unreferenced storage"); + if constexpr (sizeof...(ComponentRest) > 0) + RefreshRegistryLink(); + } + + // Function = std::function + template + template + void BasicConstView::ForEachUniqueComponent(Function&& function) const + { + if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) + GetComponentStorageAt::Index>()->ForEachStorage(function); + else + GetComponentStorageAt::Index>()->ForEachStorage(function, m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities()); + } +} diff --git a/src/LittleECS/Registry/Views/BasicView.h b/src/LittleECS/Registry/Views/BasicView.h index c65cae2..dda96c4 100644 --- a/src/LittleECS/Registry/Views/BasicView.h +++ b/src/LittleECS/Registry/Views/BasicView.h @@ -2,8 +2,9 @@ #include "LittleECS/Registry/IComponentStorage.h" -#include "LittleECS/Detail/TypeParameterPack.h" +#include "LittleECS/Detail/TypeTraits.h" #include "LittleECS/Detail/ApplicableFunction.h" +#include "LittleECS/Detail/Iterable.h" #include #include @@ -55,7 +56,7 @@ namespace LECS template bool Has(EntityId entity) const { - auto storage = GetComponentStorageAt::Index>(); + auto storage = GetComponentStorageAt::Index>(); if (storage == nullptr) return false; return storage->HasThisComponent(entity); @@ -64,38 +65,38 @@ namespace LECS template bool HasAll(EntityId entity) const { - if constexpr (sizeof...(ComponentTypes) == 0) + if constexpr (sizeof...(ComponentTypes) == 0) return Has(entity); else return Has(entity) && HasAll(entity); } public: - template - const ComponentType& Get(EntityId entity) const - { - auto storage = GetComponentStorageAt::Index>(); + template + const ComponentType& Get(EntityId entity) const + { + auto storage = GetComponentStorageAt::Index>(); LECS_ASSERT(storage, "This entity doesn't have this component") return storage->GetComponentOfEntity(entity); - } + } template - const ComponentType* GetPtr(EntityId entity) const - { - auto storage = GetComponentStorageAt::Index>(); + const ComponentType* GetPtr(EntityId entity) const + { + auto storage = GetComponentStorageAt::Index>(); LECS_ASSERT(storage, "This entity doesn't have this component") return storage->GetComponentOfEntityPtr(entity); - } + } template - std::tuple GetAll(EntityId entity) const - { + std::tuple GetAll(EntityId entity) const + { return std::tuple(Get(entity)...); - } + } public: // Function = std::function - template + template requires (Detail::IsApplicable::Value) - void ForEachEntities(Function&& function) const + void ForEachEntities(Function&& function) const { return ForEachComponents(std::forward(function)); } @@ -119,7 +120,7 @@ namespace LECS template decltype(auto) EachUniqueComponent() const; - template + template decltype(auto) EachComponents() const; }; @@ -176,10 +177,10 @@ namespace LECS template ComponentType& Get(EntityId entity) { - auto storage = GetComponentStorageAt::Index>(); - LECS_ASSERT(storage, "This entity doesn't have this component") - return storage->GetComponentOfEntity(entity); - } + auto storage = GetComponentStorageAt::Index>(); + LECS_ASSERT(storage, "This entity doesn't have this component") + return storage->GetComponentOfEntity(entity); + } template const ComponentType& GetPtr(EntityId entity) const @@ -189,27 +190,27 @@ namespace LECS template ComponentType* GetPtr(EntityId entity) { - auto storage = GetComponentStorageAt::Index>(); - LECS_ASSERT(storage, "This entity doesn't have this component") - return &storage->GetComponentOfEntity(entity); - } + auto storage = GetComponentStorageAt::Index>(); + LECS_ASSERT(storage, "This entity doesn't have this component") + return &storage->GetComponentOfEntity(entity); + } template - std::tuple GetAll(EntityId entity) const - { + std::tuple GetAll(EntityId entity) const + { return Base::template GetAll(entity); - } - template - std::tuple GetAll(EntityId entity) - { + } + template + std::tuple GetAll(EntityId entity) + { return std::tuple(Get(entity)...); - } + } public: // Function = std::function - template + template requires (Detail::IsApplicable::Value) - void ForEachEntities(Function&& function) const + void ForEachEntities(Function&& function) const { return Base::template ForEachEntities(std::forward(function)); } @@ -251,7 +252,7 @@ namespace LECS { return Base::template EachUniqueComponent(); } - template + template decltype(auto) EachComponents() const { return Base::template EachComponents(); @@ -259,7 +260,10 @@ namespace LECS template decltype(auto) EachUniqueComponent(); - template + template decltype(auto) EachComponents(); }; } + +#include "BasicViewEach-inl.h" +#include "BasicViewForEach-inl.h" diff --git a/src/LittleECS/Registry/Views/BasicView.inl b/src/LittleECS/Registry/Views/BasicView.inl deleted file mode 100644 index 1b82fe5..0000000 --- a/src/LittleECS/Registry/Views/BasicView.inl +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "BasicView.h" - -namespace LECS -{ - template - template - void BasicConstView::RefreshRegistryLink() - { - m_LinkToComponentContainer[I] = m_LinkedRegistry.GetComponentStorage(); - LECS_ASSERT(m_LinkToComponentContainer[I] != nullptr, "Can't create a view with an unreferenced storage") - if constexpr (sizeof...(ComponentRest) > 0) - RefreshRegistryLink(); - } -} diff --git a/src/LittleECS/Registry/Views/BasicViewEach-inl.h b/src/LittleECS/Registry/Views/BasicViewEach-inl.h new file mode 100644 index 0000000..675b4b0 --- /dev/null +++ b/src/LittleECS/Registry/Views/BasicViewEach-inl.h @@ -0,0 +1,98 @@ +#pragma once + +#include "BasicView.h" +#include "BasicViewIterator.h" + +namespace LECS +{ + template + template + decltype(auto) BasicConstView::EachEntitiesWith() const + { + const typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorageAt::Index>(); + + LECS_ASSERT(componentStorage, "Component storage can't be non referenced when getting iterators") + + if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) + return Detail::Iterable(componentStorage->EntitiesIteratorBegin(), componentStorage->EntitiesIteratorEnd()); + else + return Detail::Iterable( + componentStorage->EntitiesIteratorBegin(this->m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities()), + componentStorage->EntitiesIteratorEnd(this->m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities()) + ); + } + + template + template + decltype(auto) BasicConstView::EachEntitiesWithAll() const + { + if constexpr (sizeof...(ComponentTypesEach) == 0) + return EachEntitiesWith(); + else + { + auto rangedComponent = this->EachEntitiesWith(); + return Detail::Iterable( + Detail::ViewEntitiesIterator(this, rangedComponent.begin(), rangedComponent.end()), + Detail::IterableEnd() + ); + } + } + + template + template + decltype(auto) BasicConstView::EachUniqueComponent() const + { + const typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorageAt::Index>(); + + LECS_ASSERT(componentStorage, "Component storage can't be non referenced when getting iterators") + + if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) + return Detail::Iterable(componentStorage->EntitiesIteratorBegin(), componentStorage->EntitiesIteratorEnd()); + else + return Detail::Iterable(componentStorage->EntitiesIteratorBegin(this->m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities()), + componentStorage->EntitiesIteratorEnd(this->m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities())); + } + + template + template + decltype(auto) BasicConstView::EachComponents() const + { + auto rangedComponent = EachEntitiesWith(); + auto entities = Detail::ViewEntitiesIterator(this, rangedComponent.begin(), rangedComponent.end()); + + return Detail::Iterable( + Detail::ViewComponentsIterator(this, entities, Detail::IterableEnd()), + Detail::IterableEnd() + ); + } +} + +namespace LECS +{ + template + template + decltype(auto) BasicView::EachUniqueComponent() + { + typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorageAt::Index>(); + + LECS_ASSERT(componentStorage, "Component storage can't be non referenced when getting iterators") + + if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) + return Detail::Iterable(componentStorage->EntitiesIteratorBegin(), componentStorage->EntitiesIteratorEnd()); + else + return Detail::Iterable(componentStorage->EntitiesIteratorBegin(this->m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities()), + componentStorage->EntitiesIteratorEnd(this->m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities())); + } + template + template + decltype(auto) BasicView::EachComponents() + { + auto rangedComponent = this->template EachEntitiesWith(); + auto entities = Detail::ViewEntitiesIterator(this, rangedComponent.begin(), rangedComponent.end()); + + return Detail::Iterable( + Detail::ViewComponentsIterator(this, entities, Detail::IterableEnd()), + Detail::IterableEnd() + ); + } +} diff --git a/src/LittleECS/Registry/Views/BasicViewForEach.h b/src/LittleECS/Registry/Views/BasicViewForEach-inl.h similarity index 83% rename from src/LittleECS/Registry/Views/BasicViewForEach.h rename to src/LittleECS/Registry/Views/BasicViewForEach-inl.h index 06247f0..1637cf8 100644 --- a/src/LittleECS/Registry/Views/BasicViewForEach.h +++ b/src/LittleECS/Registry/Views/BasicViewForEach-inl.h @@ -1,22 +1,12 @@ #pragma once #include "BasicView.h" +#include "BasicViewIterator.h" #include "LittleECS/Detail/ApplicableFunction.h" namespace LECS { - // Function = std::function - template - template - void BasicConstView::ForEachUniqueComponent(Function&& function) const - { - if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) - GetComponentStorageAt::Index>()->ForEachStorage(function); - else - GetComponentStorageAt::Index>()->ForEachStorage(function, m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities()); - } - // Function = std::function template template @@ -80,7 +70,7 @@ namespace LECS { std::apply(function, std::tuple_cat(std::tuple(entity), std::tuple(componentRanged), GetAll(entity))); } - else if constexpr (Detail::IsApplicable::Value) + else if constexpr (Detail::IsApplicable::Value) { std::apply(function, std::tuple_cat(std::tuple(componentRanged), GetAll(entity))); } diff --git a/src/LittleECS/Registry/Views/BasicViewIterator.h b/src/LittleECS/Registry/Views/BasicViewIterator.h index 92046ad..7454015 100644 --- a/src/LittleECS/Registry/Views/BasicViewIterator.h +++ b/src/LittleECS/Registry/Views/BasicViewIterator.h @@ -45,8 +45,8 @@ namespace LECS::Detail do { ++m_SubEntitiesIterator; - if (m_SubEntitiesIterator == m_SubEntitiesIteratorLast) - break; + if (m_SubEntitiesIterator == m_SubEntitiesIteratorLast) + break; if constexpr (sizeof...(IteratorComponentTypes) > 0) currentEntityValid = m_BasicViewLinked->template HasAll(operator*()); @@ -166,97 +166,3 @@ namespace LECS::Detail SubViewEntitiesIteratorLast m_SubViewEntitiesIteratorLast; }; } - -namespace LECS -{ - template - template - decltype(auto) BasicConstView::EachEntitiesWith() const - { - const typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorageAt::Index>(); - - LECS_ASSERT(componentStorage, "Component storage can't be non referenced when getting iterators") - - if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) - return Detail::Iterable(componentStorage->EntitiesIteratorBegin(), componentStorage->EntitiesIteratorEnd()); - else - return Detail::Iterable( - componentStorage->EntitiesIteratorBegin(this->m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities()), - componentStorage->EntitiesIteratorEnd(this->m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities()) - ); - } - - template - template - decltype(auto) BasicConstView::EachEntitiesWithAll() const - { - if constexpr (sizeof...(ComponentTypesEach) == 0) - return EachEntitiesWith(); - else - { - auto rangedComponent = this->EachEntitiesWith(); - return Detail::Iterable( - Detail::ViewEntitiesIterator(this, rangedComponent.begin(), rangedComponent.end()), - Detail::IterableEnd() - ); - } - } - - template - template - decltype(auto) BasicConstView::EachUniqueComponent() const - { - const typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorageAt::Index>(); - - LECS_ASSERT(componentStorage, "Component storage can't be non referenced when getting iterators") - - if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) - return Detail::Iterable(componentStorage->EntitiesIteratorBegin(), componentStorage->EntitiesIteratorEnd()); - else - return Detail::Iterable(componentStorage->EntitiesIteratorBegin(this->m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities()), - componentStorage->EntitiesIteratorEnd(this->m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities())); - } - - template - template - decltype(auto) BasicConstView::EachComponents() const - { - auto rangedComponent = EachEntitiesWith(); - auto entities = Detail::ViewEntitiesIterator(this, rangedComponent.begin(), rangedComponent.end()); - - return Detail::Iterable( - Detail::ViewComponentsIterator(this, entities, Detail::IterableEnd()), - Detail::IterableEnd() - ); - } -} - -namespace LECS -{ - template - template - decltype(auto) BasicView::EachUniqueComponent() - { - typename Detail::ComponentStorageInfo::StorageType* componentStorage = GetComponentStorageAt::Index>(); - - LECS_ASSERT(componentStorage, "Component storage can't be non referenced when getting iterators") - - if constexpr (Detail::ComponentStorageInfo::SEND_ENTITIES_POOL_ON_EACH == false) - return Detail::Iterable(componentStorage->EntitiesIteratorBegin(), componentStorage->EntitiesIteratorEnd()); - else - return Detail::Iterable(componentStorage->EntitiesIteratorBegin(this->m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities()), - componentStorage->EntitiesIteratorEnd(this->m_LinkedRegistry.GetEntityIdGenerator().GetAlivesEntities())); - } - template - template - decltype(auto) BasicView::EachComponents() - { - auto rangedComponent = this->template EachEntitiesWith(); - auto entities = Detail::ViewEntitiesIterator(this, rangedComponent.begin(), rangedComponent.end()); - - return Detail::Iterable( - Detail::ViewComponentsIterator(this, entities, Detail::IterableEnd()), - Detail::IterableEnd() - ); - } -} diff --git a/tests/Detail/BasicWorkflow.cpp b/tests/Detail/BasicWorkflow.cpp deleted file mode 100644 index a8306c5..0000000 --- a/tests/Detail/BasicWorkflow.cpp +++ /dev/null @@ -1,207 +0,0 @@ -#include "../BaseLittleECSTest.h" - -#include "LittleECS/Registry/Registry.h" - -#include "ProjectCore/Instrumentation/ProfilerManger/ProfilerManger.h" - -#include - -PCT_TEST_GROUP(LITTLE_ECS, BASIC_WORKFLOW); - -struct BasicFloatComponent -{ - BasicFloatComponent(float value = 0.0f) - : Value(value) - {} - - float Value; -}; - -struct BasicIntComponentFC -{ - BasicIntComponentFC(std::size_t value = 0) - : Value(value) - {} - - std::size_t Value; -}; -template <> -struct LECS::Detail::ComponentStorageInfo : public DefaultComponentStorageInfo::FastComponent {}; - -struct BasicIntComponentFCNREF -{ - BasicIntComponentFCNREF(std::size_t value = 0) - : Value(value) - {} - - std::size_t Value; -}; -template <> -struct LECS::Detail::ComponentStorageInfo : public DefaultComponentStorageInfo::FastComponentWithoutREF {}; - -struct BasicIntComponentCC -{ - BasicIntComponentCC(std::size_t value = 0) - : Value(value) - {} - - std::size_t Value; -}; -template <> -struct LECS::Detail::ComponentStorageInfo : public DefaultComponentStorageInfo::CommonComponent {}; - -struct BasicIntComponentRC -{ - BasicIntComponentRC(std::size_t value = 0) - : Value(value) - {} - - std::size_t Value; -}; -template <> -struct LECS::Detail::ComponentStorageInfo : public DefaultComponentStorageInfo::RareComponent {}; - -#define BasicWorkflow(Postfix_ComponentToUse) PCT_TEST_FUNC(BASIC_WORKFLOW, BASIC_WORK_FLOW_TEST##Postfix_ComponentToUse) \ - { \ - LECS::Registry registry; \ - const LECS::Registry& constRegistry = registry; \ - \ - LECS::EntityId entity1 = registry.CreateEntityId(); \ - LECS::EntityId entity2 = registry.CreateEntityId(); \ - LECS::EntityId entity3 = registry.CreateEntityId(); \ - PCT_NEQ(entity1.Id, entity2.Id); \ - PCT_NEQ(entity1.Id, entity3.Id); \ - PCT_NEQ(entity2.Id, entity3.Id); \ - \ - registry.Add(entity1, 7ull); \ - registry.Add(entity2, 101ull); \ - registry.Add(entity2, 101); \ - registry.Add(entity2, 101.0f); \ - \ - PCT_EQ(registry.Get(entity1).Value, 7ull); \ - PCT_EQ(registry.Get(entity2).Value, 101ull); \ - PCT_ASSERT(registry.Has(entity3) == false); \ - \ - registry.Add(entity1, 171.0f); \ - registry.Add(entity3, 5.0f); \ - \ - PCT_EQ(registry.Get(entity1).Value, 171.0f); \ - PCT_EQ(registry.Get(entity3).Value, 5.0f); \ - PCT_ASSERT(registry.Has(entity2) == false); \ - PCT_EQ(registry.Get(entity1).Value, 7ull); \ - PCT_EQ(registry.Get(entity2).Value, 101ull); \ - PCT_ASSERT(registry.Has(entity3) == false); \ - \ - registry.ForEachComponents([](BasicIntComponent##Postfix_ComponentToUse& k, BasicFloatComponent& v) \ - { \ - k = 325ull; \ - v = 22.0f; \ - }); \ - \ - constRegistry.ForEachComponents([&link](const BasicIntComponent##Postfix_ComponentToUse& k, const BasicFloatComponent& v) \ - { \ - PCT_EQ(k.Value, 325ull); \ - PCT_EQ(v.Value, 22.0f); \ - }); \ - \ - registry.ForEachComponents([](BasicIntComponent##Postfix_ComponentToUse& k) \ - { \ - k = 85ull; \ - }); \ - \ - constRegistry.ForEachComponents([&link](const BasicIntComponent##Postfix_ComponentToUse& k) \ - { \ - PCT_EQ(k.Value, 85ull); \ - }); \ - \ - PCT_EQ(registry.Get(entity1).Value, 85ull); \ - PCT_EQ(registry.Get(entity2).Value, 85ull); \ - PCT_ASSERT(registry.Has(entity3) == false); \ - PCT_EQ(registry.Get(entity1).Value, 22.0f); \ - PCT_EQ(registry.Get(entity3).Value, 5.0f); \ - PCT_ASSERT(registry.Has(entity2) == false); \ - \ - registry.ForEachUniqueComponent([](LECS::EntityId entity, BasicIntComponent##Postfix_ComponentToUse& k) \ - { \ - k = static_cast(entity.Id); \ - }); \ - \ - PCT_EQ(registry.Get(entity1).Value, entity1.Id); \ - PCT_ASSERT(registry.Has(entity2) == true); \ - PCT_ASSERT(registry.Has(entity3) == false); \ - \ - int entityCount = 0; \ - for (LECS::EntityId entity : registry.EachEntitiesWith()) \ - { \ - ++entityCount; \ - PCT_ASSERT(registry.Has(entity)); \ - } \ - PCT_EQ(entityCount, 2); \ - \ - auto view = registry.View(); \ - \ - entityCount = 0; \ - for (LECS::EntityId entity : view.EachEntitiesWith()) \ - { \ - ++entityCount; \ - PCT_ASSERT(registry.Has(entity)); \ - } \ - PCT_EQ(entityCount, 2); \ - \ - entityCount = 0; \ - for (auto [intComponent] : view.EachComponents()) \ - { \ - ++entityCount; \ - intComponent = 52ull; \ - } \ - PCT_EQ(entityCount, 2); \ - \ - entityCount = 0; \ - view.ForEachComponents([&entityCount, &link, ®istry](LECS::EntityId entity, BasicIntComponent##Postfix_ComponentToUse& k, BasicFloatComponent& v) \ - { \ - PCT_ASSERT(registry.Has(entity)); \ - PCT_ASSERT(registry.Has(entity)); \ - \ - ++entityCount; \ - }); \ - PCT_EQ(entityCount, 1); \ - \ - entityCount = 0; \ - view.ForEachComponents([&entityCount](BasicIntComponent##Postfix_ComponentToUse& k, BasicFloatComponent& v) \ - { \ - ++entityCount; \ - }); \ - PCT_EQ(entityCount, 1); \ - \ - entityCount = 0; \ - for (LECS::EntityId entity : view.EachEntitiesWithAll()) \ - { \ - PCT_ASSERT(registry.Has(entity)); \ - PCT_ASSERT(registry.Has(entity)); \ - ++entityCount; \ - } \ - PCT_EQ(entityCount, 1); \ - \ - entityCount = 0; \ - for (auto [intComponent, floatComponent] : view.EachComponents()) \ - { \ - PCT_EQ(intComponent.Value, 52ull); \ - PCT_EQ(floatComponent.Value, 22.0f); \ - ++entityCount; \ - } \ - PCT_EQ(entityCount, 1); \ - \ - PCT_EQ(registry.Get(entity1).Value, 52ull); \ - PCT_EQ(registry.Get(entity2).Value, 52ull); \ - PCT_ASSERT(registry.Has(entity3) == false); \ - registry.DestroyEntityId(entity2); \ - PCT_EQ(registry.Get(entity1).Value, 52ull); \ - PCT_ASSERT(registry.Has(entity2) == false); \ - PCT_ASSERT(registry.Has(entity3) == false); \ - } - - -BasicWorkflow(FC); -BasicWorkflow(FCNREF); -BasicWorkflow(CC); -BasicWorkflow(RC); diff --git a/tests/Tests.cpp b/tests/Tests.cpp deleted file mode 100644 index ec05ab8..0000000 --- a/tests/Tests.cpp +++ /dev/null @@ -1,8 +0,0 @@ - -#include "ProjectCore/Tester/TestSuite/AllTestSuite.h" - -int main() -{ - ProjectCore::Tester::TestSuitesManager::Verbose = false; - return ProjectCore::Tester::TestSuitesManager::ExecAllTestSuites(); -}