Compare commits
	
		
			3 Commits
		
	
	
		
			f077a29cf0
			...
			310a099f14
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 310a099f14 | |||
| 5c7231b7a3 | |||
| df9fc529e2 | 
							
								
								
									
										22
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| .vs/ | ||||
| *.o | ||||
| *.swp | ||||
| ~* | ||||
| *~ | ||||
| .idea/ | ||||
| cmake-build-debug/ | ||||
| cmake-build-debugandtest/ | ||||
| cmake-build-release/ | ||||
| *.stackdump | ||||
| *.coredump | ||||
| compile_commands.json | ||||
| /build* | ||||
| .clangd | ||||
| .cache | ||||
|  | ||||
| .DS_Store | ||||
| .AppleDouble | ||||
| .LSOverride | ||||
|  | ||||
| CMakeLists.txt.user* | ||||
| CMakeCache.txt | ||||
							
								
								
									
										41
									
								
								external/entt/entt/.clang-format
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								external/entt/entt/.clang-format
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| BasedOnStyle: llvm | ||||
| --- | ||||
| AccessModifierOffset: -4 | ||||
| AlignEscapedNewlines: DontAlign | ||||
| AllowShortBlocksOnASingleLine: Empty | ||||
| AllowShortEnumsOnASingleLine: true | ||||
| AllowShortFunctionsOnASingleLine: Empty | ||||
| AllowShortIfStatementsOnASingleLine: WithoutElse | ||||
| AllowShortLoopsOnASingleLine: true | ||||
| AlwaysBreakTemplateDeclarations: Yes | ||||
| BreakBeforeBinaryOperators: NonAssignment | ||||
| BreakBeforeTernaryOperators: true | ||||
| ColumnLimit: 0 | ||||
| DerivePointerAlignment: false | ||||
| IncludeCategories: | ||||
|   - Regex: '<[[:alnum:]_]+>' | ||||
|     Priority: 1 | ||||
|   - Regex: '<(gtest|gmock)/' | ||||
|     Priority: 2 | ||||
|   - Regex: '<[[:alnum:]_./]+>' | ||||
|     Priority: 3 | ||||
|   - Regex: '<entt/' | ||||
|     Priority: 4 | ||||
|   - Regex: '.*' | ||||
|     Priority: 5 | ||||
| IndentPPDirectives: AfterHash | ||||
| IndentWidth: 4 | ||||
| KeepEmptyLinesAtTheStartOfBlocks: false | ||||
| Language: Cpp | ||||
| PointerAlignment: Right | ||||
| SpaceAfterCStyleCast: false | ||||
| SpaceAfterTemplateKeyword: false | ||||
| SpaceAroundPointerQualifiers: After | ||||
| SpaceBeforeCaseColon: false | ||||
| SpaceBeforeCtorInitializerColon: false | ||||
| SpaceBeforeInheritanceColon: false | ||||
| SpaceBeforeParens: Never | ||||
| SpaceBeforeRangeBasedForLoopColon: false | ||||
| Standard: Latest | ||||
| TabWidth: 4 | ||||
| UseTab: Never | ||||
							
								
								
									
										4
									
								
								external/entt/entt/.github/FUNDING.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								external/entt/entt/.github/FUNDING.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| # These are supported funding model platforms | ||||
|  | ||||
| github: skypjack | ||||
| custom: https://www.paypal.me/skypjack | ||||
							
								
								
									
										55
									
								
								external/entt/entt/.github/workflows/analyzer.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								external/entt/entt/.github/workflows/analyzer.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| name: analyzer | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|       - wip | ||||
|  | ||||
| jobs: | ||||
|  | ||||
|   iwyu: | ||||
|     timeout-minutes: 30 | ||||
|  | ||||
|     env: | ||||
|       IWYU: 0.18 | ||||
|       LLVM: 14 | ||||
|  | ||||
|     runs-on: ubuntu-latest | ||||
|     continue-on-error: true | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|     - name: Install llvm/clang | ||||
|       # see: https://apt.llvm.org/ | ||||
|       run: | | ||||
|         wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - | ||||
|         sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-$LLVM main" | ||||
|         sudo apt update | ||||
|         sudo apt remove -y "llvm*" | ||||
|         sudo apt remove -y "libclang-dev*" | ||||
|         sudo apt remove -y "clang*" | ||||
|         sudo apt install -y llvm-$LLVM-dev | ||||
|         sudo apt install -y libclang-$LLVM-dev | ||||
|         sudo apt install -y clang-$LLVM | ||||
|     - name: Compile iwyu | ||||
|       # see: https://github.com/include-what-you-use/include-what-you-use | ||||
|       working-directory: build | ||||
|       run: | | ||||
|         git clone https://github.com/include-what-you-use/include-what-you-use.git --branch $IWYU --depth 1 | ||||
|         mkdir include-what-you-use/build | ||||
|         cd include-what-you-use/build | ||||
|         cmake -DCMAKE_C_COMPILER=clang-$LLVM -DCMAKE_CXX_COMPILER=clang++-$LLVM -DCMAKE_INSTALL_PREFIX=./ .. | ||||
|         make -j4 | ||||
|         bin/include-what-you-use --version | ||||
|     - name: Compile tests | ||||
|       working-directory: build | ||||
|       run: | | ||||
|         export PATH=$PATH:${GITHUB_WORKSPACE}/build/include-what-you-use/build/bin | ||||
|         cmake -DENTT_BUILD_TESTING=ON \ | ||||
|               -DENTT_BUILD_BENCHMARK=ON \ | ||||
|               -DENTT_BUILD_EXAMPLE=ON \ | ||||
|               -DENTT_BUILD_LIB=ON \ | ||||
|               -DENTT_BUILD_SNAPSHOT=ON \ | ||||
|               -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="include-what-you-use;-Xiwyu;--mapping_file=${GITHUB_WORKSPACE}/entt.imp;-Xiwyu;--no_fwd_decls;-Xiwyu;--verbose=1" .. | ||||
|         make -j4 | ||||
							
								
								
									
										169
									
								
								external/entt/entt/.github/workflows/build.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								external/entt/entt/.github/workflows/build.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | ||||
| name: build | ||||
|  | ||||
| on: [push, pull_request] | ||||
|  | ||||
| jobs: | ||||
|  | ||||
|   linux: | ||||
|     timeout-minutes: 15 | ||||
|  | ||||
|     strategy: | ||||
|       matrix: | ||||
|         compiler: | ||||
|           - pkg: g++-7 | ||||
|             exe: g++-7 | ||||
|           - pkg: g++-8 | ||||
|             exe: g++-8 | ||||
|           - pkg: g++-9 | ||||
|             exe: g++-9 | ||||
|           - pkg: g++-10 | ||||
|             exe: g++-10 | ||||
|           - pkg: clang-8 | ||||
|             exe: clang++-8 | ||||
|           - pkg: clang-9 | ||||
|             exe: clang++-9 | ||||
|           - pkg: clang-10 | ||||
|             exe: clang++-10 | ||||
|           - pkg: clang-11 | ||||
|             exe: clang++-11 | ||||
|           - pkg: clang-12 | ||||
|             exe: clang++-12 | ||||
|  | ||||
|     runs-on: ubuntu-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|     - name: Install compiler | ||||
|       run: | | ||||
|         sudo apt update | ||||
|         sudo apt install -y ${{ matrix.compiler.pkg }} | ||||
|     - name: Compile tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CXX: ${{ matrix.compiler.exe }} | ||||
|       run: | | ||||
|         cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON .. | ||||
|         make -j4 | ||||
|     - name: Run tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CTEST_OUTPUT_ON_FAILURE: 1 | ||||
|       run: ctest --timeout 30 -C Debug -j4 | ||||
|  | ||||
|   linux-extra: | ||||
|     timeout-minutes: 15 | ||||
|  | ||||
|     strategy: | ||||
|       matrix: | ||||
|         compiler: [g++, clang++] | ||||
|         id_type: ["std::uint32_t", "std::uint64_t"] | ||||
|         cxx_std: [cxx_std_17, cxx_std_20] | ||||
|  | ||||
|     runs-on: ubuntu-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|     - name: Compile tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CXX: ${{ matrix.compiler }} | ||||
|       run: | | ||||
|         cmake -DENTT_BUILD_TESTING=ON -DENTT_CXX_STD=${{ matrix.cxx_std }} -DENTT_ID_TYPE=${{ matrix.id_type }} .. | ||||
|         make -j4 | ||||
|     - name: Run tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CTEST_OUTPUT_ON_FAILURE: 1 | ||||
|       run: ctest --timeout 30 -C Debug -j4 | ||||
|  | ||||
|   windows: | ||||
|     timeout-minutes: 15 | ||||
|  | ||||
|     strategy: | ||||
|       matrix: | ||||
|         toolset: [default, v141, v142, clang-cl] | ||||
|         include: | ||||
|           - toolset: v141 | ||||
|             toolset_option: -T"v141" | ||||
|           - toolset: v142 | ||||
|             toolset_option: -T"v142" | ||||
|           - toolset: clang-cl | ||||
|             toolset_option: -T"ClangCl" | ||||
|  | ||||
|     runs-on: windows-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|     - name: Compile tests | ||||
|       working-directory: build | ||||
|       run: | | ||||
|         cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ${{ matrix.toolset_option }} .. | ||||
|         cmake --build . -j 4 | ||||
|     - name: Run tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CTEST_OUTPUT_ON_FAILURE: 1 | ||||
|       run: ctest --timeout 30 -C Debug -j4 | ||||
|  | ||||
|   windows-extra: | ||||
|     timeout-minutes: 15 | ||||
|  | ||||
|     strategy: | ||||
|       matrix: | ||||
|         id_type: ["std::uint32_t", "std::uint64_t"] | ||||
|         cxx_std: [cxx_std_17, cxx_std_20] | ||||
|  | ||||
|     runs-on: windows-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|     - name: Compile tests | ||||
|       working-directory: build | ||||
|       run: | | ||||
|         cmake -DENTT_BUILD_TESTING=ON -DENTT_CXX_STD=${{ matrix.cxx_std }} -DENTT_ID_TYPE=${{ matrix.id_type }} .. | ||||
|         cmake --build . -j 4 | ||||
|     - name: Run tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CTEST_OUTPUT_ON_FAILURE: 1 | ||||
|       run: ctest --timeout 30 -C Debug -j4 | ||||
|  | ||||
|   macos: | ||||
|     timeout-minutes: 15 | ||||
|     runs-on: macOS-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|     - name: Compile tests | ||||
|       working-directory: build | ||||
|       run: | | ||||
|         cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON .. | ||||
|         make -j4 | ||||
|     - name: Run tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CTEST_OUTPUT_ON_FAILURE: 1 | ||||
|       run: ctest --timeout 30 -C Debug -j4 | ||||
|  | ||||
|   macos-extra: | ||||
|     timeout-minutes: 15 | ||||
|  | ||||
|     strategy: | ||||
|       matrix: | ||||
|         id_type: ["std::uint32_t", "std::uint64_t"] | ||||
|         cxx_std: [cxx_std_17, cxx_std_20] | ||||
|  | ||||
|     runs-on: macOS-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|     - name: Compile tests | ||||
|       working-directory: build | ||||
|       run: | | ||||
|         cmake -DENTT_BUILD_TESTING=ON -DENTT_CXX_STD=${{ matrix.cxx_std }} -DENTT_ID_TYPE=${{ matrix.id_type }} .. | ||||
|         make -j4 | ||||
|     - name: Run tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CTEST_OUTPUT_ON_FAILURE: 1 | ||||
|       run: ctest --timeout 30 -C Debug -j4 | ||||
							
								
								
									
										38
									
								
								external/entt/entt/.github/workflows/coverage.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								external/entt/entt/.github/workflows/coverage.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| name: coverage | ||||
|  | ||||
| on: [push, pull_request] | ||||
|  | ||||
| jobs: | ||||
|  | ||||
|   codecov: | ||||
|     timeout-minutes: 15 | ||||
|     runs-on: ubuntu-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|     - name: Compile tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CXXFLAGS: "--coverage -fno-inline" | ||||
|         CXX: g++ | ||||
|       run: | | ||||
|         cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON .. | ||||
|         make -j4 | ||||
|     - name: Run tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CTEST_OUTPUT_ON_FAILURE: 1 | ||||
|       run: ctest --timeout 30 -C Debug -j4 | ||||
|     - name: Collect data | ||||
|       working-directory: build | ||||
|       run: | | ||||
|         sudo apt install lcov | ||||
|         lcov -c -d . -o coverage.info | ||||
|         lcov -l coverage.info | ||||
|     - name: Upload coverage to Codecov | ||||
|       uses: codecov/codecov-action@v2 | ||||
|       with: | ||||
|         token: ${{ secrets.CODECOV_TOKEN }} | ||||
|         files: build/coverage.info | ||||
|         name: EnTT | ||||
|         fail_ci_if_error: true | ||||
							
								
								
									
										39
									
								
								external/entt/entt/.github/workflows/deploy.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								external/entt/entt/.github/workflows/deploy.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| name: deploy | ||||
|  | ||||
| on: | ||||
|   release: | ||||
|     types: published | ||||
|  | ||||
| jobs: | ||||
|  | ||||
|   homebrew-entt: | ||||
|     timeout-minutes: 5 | ||||
|     runs-on: ubuntu-latest | ||||
|  | ||||
|     env: | ||||
|       GH_REPO: homebrew-entt | ||||
|       FORMULA: entt.rb | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|     - name: Clone repository | ||||
|       working-directory: build | ||||
|       env: | ||||
|         PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} | ||||
|       run: git clone https://$GITHUB_ACTOR:$PERSONAL_ACCESS_TOKEN@github.com/$GITHUB_ACTOR/$GH_REPO.git | ||||
|     - name: Prepare formula | ||||
|       working-directory: build | ||||
|       run: | | ||||
|         cd $GH_REPO | ||||
|         curl "https://github.com/${{ github.repository }}/archive/${{ github.ref }}.tar.gz" --location --fail --silent --show-error --output archive.tar.gz | ||||
|         sed -i -e '/url/s/".*"/"'$(echo "https://github.com/${{ github.repository }}/archive/${{ github.ref }}.tar.gz" | sed -e 's/[\/&]/\\&/g')'"/' $FORMULA | ||||
|         sed -i -e '/sha256/s/".*"/"'$(openssl sha256 archive.tar.gz | cut -d " " -f 2)'"/' $FORMULA | ||||
|     - name: Update remote | ||||
|       working-directory: build | ||||
|       run: | | ||||
|         cd $GH_REPO | ||||
|         git config --local user.email "action@github.com" | ||||
|         git config --local user.name "$GITHUB_ACTOR" | ||||
|         git add $FORMULA | ||||
|         git commit -m "Update to ${{ github.ref }}" | ||||
|         git push origin master | ||||
							
								
								
									
										31
									
								
								external/entt/entt/.github/workflows/sanitizer.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								external/entt/entt/.github/workflows/sanitizer.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| name: sanitizer | ||||
|  | ||||
| on: [push, pull_request] | ||||
|  | ||||
| jobs: | ||||
|  | ||||
|   clang: | ||||
|     timeout-minutes: 15 | ||||
|  | ||||
|     strategy: | ||||
|       matrix: | ||||
|         compiler: [clang++] | ||||
|         id_type: ["std::uint32_t", "std::uint64_t"] | ||||
|         cxx_std: [cxx_std_17, cxx_std_20] | ||||
|  | ||||
|     runs-on: ubuntu-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|     - name: Compile tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CXX: ${{ matrix.compiler }} | ||||
|       run: | | ||||
|         cmake -DENTT_USE_SANITIZER=ON -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON -DENTT_CXX_STD=${{ matrix.cxx_std }} -DENTT_ID_TYPE=${{ matrix.id_type }} .. | ||||
|         make -j4 | ||||
|     - name: Run tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CTEST_OUTPUT_ON_FAILURE: 1 | ||||
|       run: ctest --timeout 30 -C Debug -j4 | ||||
							
								
								
									
										13
									
								
								external/entt/entt/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								external/entt/entt/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| # Conan | ||||
| conan/test_package/build | ||||
|  | ||||
| # IDEs | ||||
| *.user | ||||
| .idea | ||||
| .vscode | ||||
| .vs | ||||
| CMakeSettings.json | ||||
| cpp.hint | ||||
|  | ||||
| # Bazel | ||||
| /bazel-* | ||||
							
								
								
									
										56
									
								
								external/entt/entt/AUTHORS
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								external/entt/entt/AUTHORS
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| # Author | ||||
|  | ||||
| skypjack | ||||
|  | ||||
| # Contributors | ||||
|  | ||||
| alexames | ||||
| BenediktConze | ||||
| bjadamson | ||||
| ceeac | ||||
| ColinH | ||||
| corystegel | ||||
| Croydon | ||||
| cschreib | ||||
| cugone | ||||
| dbacchet | ||||
| dBagrat | ||||
| djarek | ||||
| DNKpp | ||||
| DonKult | ||||
| drglove | ||||
| eliasdaler | ||||
| erez-o | ||||
| eugeneko | ||||
| gale83 | ||||
| ghost | ||||
| grdowns | ||||
| Green-Sky | ||||
| Innokentiy-Alaytsev | ||||
| Kerndog73 | ||||
| Koward | ||||
| Lawrencemm | ||||
| markand | ||||
| mhammerc | ||||
| Milerius | ||||
| Minimonium | ||||
| morbo84 | ||||
| m-waka | ||||
| netpoetica | ||||
| NixAJ | ||||
| Oortonaut | ||||
| Paolo-Oliverio | ||||
| pgruenbacher | ||||
| prowolf | ||||
| Qix- | ||||
| stefanofiorentino | ||||
| suVrik | ||||
| szunhammer | ||||
| The5-1 | ||||
| vblanco20-1 | ||||
| willtunnels | ||||
| WizardIke | ||||
| WoLfulus  | ||||
| w1th0utnam3 | ||||
| xissburg | ||||
| zaucy | ||||
							
								
								
									
										14
									
								
								external/entt/entt/BUILD.bazel
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								external/entt/entt/BUILD.bazel
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| _msvc_copts = ["/std:c++17"]	 | ||||
| _gcc_copts = ["-std=c++17"] | ||||
|  | ||||
| cc_library( | ||||
|     name = "entt", | ||||
|     visibility = ["//visibility:public"], | ||||
|     strip_include_prefix = "src", | ||||
|     hdrs = glob(["src/**/*.h", "src/**/*.hpp"]), | ||||
|     copts = select({ | ||||
|       "@bazel_tools//src/conditions:windows": _msvc_copts, | ||||
|       "@bazel_tools//src/conditions:windows_msvc": _msvc_copts, | ||||
|       "//conditions:default": _gcc_copts, | ||||
|     }), | ||||
| ) | ||||
							
								
								
									
										325
									
								
								external/entt/entt/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										325
									
								
								external/entt/entt/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,325 @@ | ||||
| # | ||||
| # EnTT | ||||
| # | ||||
|  | ||||
| cmake_minimum_required(VERSION 3.12.4) | ||||
|  | ||||
| # | ||||
| # Read project version | ||||
| # | ||||
|  | ||||
| set(ENTT_VERSION_REGEX "#define ENTT_VERSION_.*[ \t]+(.+)") | ||||
| file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/src/entt/config/version.h" ENTT_VERSION REGEX ${ENTT_VERSION_REGEX}) | ||||
| list(TRANSFORM ENTT_VERSION REPLACE ${ENTT_VERSION_REGEX} "\\1") | ||||
| string(JOIN "." ENTT_VERSION ${ENTT_VERSION}) | ||||
|  | ||||
| # | ||||
| # Project configuration | ||||
| # | ||||
|  | ||||
| project( | ||||
|     EnTT | ||||
|     VERSION ${ENTT_VERSION} | ||||
|     DESCRIPTION "Gaming meets modern C++ - a fast and reliable entity-component system (ECS) and much more" | ||||
|     HOMEPAGE_URL "https://github.com/skypjack/entt" | ||||
|     LANGUAGES C CXX | ||||
| ) | ||||
|  | ||||
| if(NOT CMAKE_BUILD_TYPE) | ||||
|     set(CMAKE_BUILD_TYPE Debug) | ||||
| endif() | ||||
|  | ||||
| message(VERBOSE "*") | ||||
| message(VERBOSE "* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})") | ||||
| message(VERBOSE "* Copyright (c) 2017-2022 Michele Caini <michele.caini@gmail.com>") | ||||
| message(VERBOSE "*") | ||||
|  | ||||
| # | ||||
| # CMake stuff | ||||
| # | ||||
|  | ||||
| list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) | ||||
|  | ||||
| # | ||||
| # Compiler stuff | ||||
| # | ||||
|  | ||||
| option(ENTT_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if available." OFF) | ||||
| option(ENTT_USE_SANITIZER "Enable sanitizers by adding -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined flags if available." OFF) | ||||
|  | ||||
| if(ENTT_USE_LIBCPP) | ||||
|     if(NOT WIN32) | ||||
|         include(CheckCXXSourceCompiles) | ||||
|         include(CMakePushCheckState) | ||||
|  | ||||
|         cmake_push_check_state() | ||||
|  | ||||
|         set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libc++") | ||||
|  | ||||
|         check_cxx_source_compiles(" | ||||
|             #include<type_traits> | ||||
|             int main() { return std::is_same_v<int, char>; } | ||||
|         " ENTT_HAS_LIBCPP) | ||||
|  | ||||
|         cmake_pop_check_state() | ||||
|     endif() | ||||
|  | ||||
|     if(NOT ENTT_HAS_LIBCPP) | ||||
|         message(VERBOSE "The option ENTT_USE_LIBCPP is set but libc++ is not available. The flag will not be added to the target.") | ||||
|     endif() | ||||
| endif() | ||||
|  | ||||
| if(ENTT_USE_SANITIZER) | ||||
|     if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") | ||||
|         set(ENTT_HAS_SANITIZER TRUE CACHE BOOL "" FORCE) | ||||
|         mark_as_advanced(ENTT_HAS_SANITIZER) | ||||
|     endif() | ||||
|  | ||||
|     if(NOT ENTT_HAS_SANITIZER) | ||||
|         message(VERBOSE "The option ENTT_USE_SANITIZER is set but sanitizer support is not available. The flags will not be added to the target.") | ||||
|     endif() | ||||
| endif() | ||||
|  | ||||
| # | ||||
| # Add EnTT target | ||||
| # | ||||
|  | ||||
| option(ENTT_INCLUDE_HEADERS "Add all EnTT headers to the EnTT target." OFF) | ||||
| option(ENTT_INCLUDE_NATVIS "Add EnTT natvis files to the EnTT target." OFF) | ||||
|  | ||||
| if(ENTT_INCLUDE_NATVIS) | ||||
|     if(MSVC) | ||||
|         set(ENTT_HAS_NATVIS TRUE CACHE BOOL "" FORCE) | ||||
|         mark_as_advanced(ENTT_HAS_NATVIS) | ||||
|     endif() | ||||
|  | ||||
|     if(NOT ENTT_HAS_NATVIS) | ||||
|         message(VERBOSE "The option ENTT_INCLUDE_NATVIS is set but natvis files are not supported. They will not be added to the target.") | ||||
|     endif() | ||||
| endif() | ||||
|  | ||||
| include(GNUInstallDirs) | ||||
|  | ||||
| add_library(EnTT INTERFACE) | ||||
| add_library(EnTT::EnTT ALIAS EnTT) | ||||
|  | ||||
| target_include_directories( | ||||
|     EnTT | ||||
|     INTERFACE | ||||
|         $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src> | ||||
|         $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||||
| ) | ||||
|  | ||||
| target_compile_features(EnTT INTERFACE cxx_std_17) | ||||
|  | ||||
| if(ENTT_INCLUDE_HEADERS) | ||||
|     target_sources( | ||||
|         EnTT | ||||
|         INTERFACE | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/config.h> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/macro.h> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/version.h> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_map.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_set.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/fwd.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/algorithm.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/any.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/attribute.h> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/compressed_pair.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/enum.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/family.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/fwd.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/hashed_string.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/ident.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/iterator.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/memory.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/monostate.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/tuple.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/type_info.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/type_traits.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/utility.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/component.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/entity.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/fwd.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/group.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/handle.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/helper.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/observer.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/organizer.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/registry.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/runtime_view.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/snapshot.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/sparse_set.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/storage.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/storage_mixin.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/view.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/adjacency_matrix.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/dot.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/flow.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/fwd.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/locator/locator.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/adl_pointer.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/container.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/context.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/factory.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/fwd.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/meta.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/node.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/pointer.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/policy.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/range.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/resolve.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/template.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/type_traits.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/utility.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/platform/android-ndk-r17.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/fwd.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/poly.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/fwd.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/process.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/scheduler.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/cache.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/fwd.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/loader.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/resource.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/delegate.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/dispatcher.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/emitter.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/fwd.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/sigh.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entt.hpp> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/fwd.hpp> | ||||
|     ) | ||||
| endif() | ||||
|  | ||||
| if(ENTT_HAS_NATVIS) | ||||
|     target_sources( | ||||
|         EnTT | ||||
|         INTERFACE | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/config.natvis> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/container.natvis> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/core.natvis> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/entity.natvis> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/graph.natvis> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/locator.natvis> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/meta.natvis> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/platform.natvis> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/poly.natvis> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/process.natvis> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/resource.natvis> | ||||
|             $<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/signal.natvis> | ||||
|     ) | ||||
| endif() | ||||
|  | ||||
| if(ENTT_HAS_SANITIZER) | ||||
|     target_compile_options(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) | ||||
|     target_link_libraries(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) | ||||
| endif() | ||||
|  | ||||
| if(ENTT_HAS_LIBCPP) | ||||
|     target_compile_options(EnTT BEFORE INTERFACE -stdlib=libc++) | ||||
| endif() | ||||
|  | ||||
| # | ||||
| # Install pkg-config file | ||||
| # | ||||
|  | ||||
| include(JoinPaths) | ||||
|  | ||||
| set(EnTT_PKGCONFIG ${CMAKE_CURRENT_BINARY_DIR}/entt.pc) | ||||
|  | ||||
| join_paths(EnTT_PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}") | ||||
|  | ||||
| configure_file( | ||||
|     ${EnTT_SOURCE_DIR}/cmake/in/entt.pc.in | ||||
|     ${EnTT_PKGCONFIG} | ||||
|     @ONLY | ||||
| ) | ||||
|  | ||||
| install( | ||||
|     FILES ${EnTT_PKGCONFIG} | ||||
|     DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig | ||||
| ) | ||||
|  | ||||
| # | ||||
| # Install EnTT | ||||
| # | ||||
|  | ||||
| include(CMakePackageConfigHelpers) | ||||
|  | ||||
| install( | ||||
|     TARGETS EnTT | ||||
|     EXPORT EnTTTargets | ||||
|     ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||||
| ) | ||||
|  | ||||
| write_basic_package_version_file( | ||||
|     EnTTConfigVersion.cmake | ||||
|     VERSION ${PROJECT_VERSION} | ||||
|     COMPATIBILITY AnyNewerVersion | ||||
| ) | ||||
|  | ||||
| configure_package_config_file( | ||||
|     ${EnTT_SOURCE_DIR}/cmake/in/EnTTConfig.cmake.in | ||||
|     EnTTConfig.cmake | ||||
|     INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake | ||||
| ) | ||||
|  | ||||
| export( | ||||
|     EXPORT EnTTTargets | ||||
|     FILE ${CMAKE_CURRENT_BINARY_DIR}/EnTTTargets.cmake | ||||
|     NAMESPACE EnTT:: | ||||
| ) | ||||
|  | ||||
| install( | ||||
|     EXPORT EnTTTargets | ||||
|     FILE EnTTTargets.cmake | ||||
|     DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake | ||||
|     NAMESPACE EnTT:: | ||||
| ) | ||||
|  | ||||
| install( | ||||
|     FILES | ||||
|         ${PROJECT_BINARY_DIR}/EnTTConfig.cmake | ||||
|         ${PROJECT_BINARY_DIR}/EnTTConfigVersion.cmake | ||||
|     DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake | ||||
| ) | ||||
|  | ||||
| install(DIRECTORY src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) | ||||
|  | ||||
| export(PACKAGE EnTT) | ||||
|  | ||||
| # | ||||
| # Tests | ||||
| # | ||||
|  | ||||
| option(ENTT_BUILD_TESTING "Enable building tests." OFF) | ||||
|  | ||||
| if(ENTT_BUILD_TESTING) | ||||
|     option(ENTT_FIND_GTEST_PACKAGE "Enable finding gtest package." OFF) | ||||
|     option(ENTT_BUILD_BENCHMARK "Build benchmark." OFF) | ||||
|     option(ENTT_BUILD_EXAMPLE "Build examples." OFF) | ||||
|     option(ENTT_BUILD_LIB "Build lib tests." OFF) | ||||
|     option(ENTT_BUILD_SNAPSHOT "Build snapshot test with Cereal." OFF) | ||||
|  | ||||
|     set(ENTT_ID_TYPE std::uint32_t CACHE STRING "Type of identifiers to use for the tests") | ||||
|     set(ENTT_CXX_STD cxx_std_17 CACHE STRING "C++ standard revision to use for the tests") | ||||
|  | ||||
|     include(CTest) | ||||
|     enable_testing() | ||||
|     add_subdirectory(test) | ||||
| endif() | ||||
|  | ||||
| # | ||||
| # Documentation | ||||
| # | ||||
|  | ||||
| option(ENTT_BUILD_DOCS "Enable building with documentation." OFF) | ||||
|  | ||||
| if(ENTT_BUILD_DOCS) | ||||
|     find_package(Doxygen 1.8) | ||||
|  | ||||
|     if(DOXYGEN_FOUND) | ||||
|         add_subdirectory(docs) | ||||
|     endif() | ||||
| endif() | ||||
							
								
								
									
										43
									
								
								external/entt/entt/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								external/entt/entt/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| # Contributing | ||||
|  | ||||
| First of all, thank you very much for taking the time to contribute to the | ||||
| `EnTT` library.<br/> | ||||
| How to do it mostly depends on the type of contribution: | ||||
|  | ||||
| * If you have a question, **please** ensure there isn't already an answer for | ||||
|   you by searching on GitHub under | ||||
|   [issues](https://github.com/skypjack/entt/issues). Do not forget to search | ||||
|   also through the closed ones. If you are unable to find a proper answer, feel | ||||
|   free to [open a new issue](https://github.com/skypjack/entt/issues/new). | ||||
|   Usually, questions are marked as such and closed in a few days. | ||||
|  | ||||
| * If you want to fix a typo in the inline documentation or in the README file, | ||||
|   if you want to add some new sections or if you want to help me with the | ||||
|   language by reviewing what I wrote so far (I'm not a native speaker after | ||||
|   all), **please** open a new | ||||
|   [pull request](https://github.com/skypjack/entt/pulls) with your changes. | ||||
|  | ||||
| * If you found a bug, **please** ensure there isn't already an answer for you by | ||||
|   searching on GitHub under [issues](https://github.com/skypjack/entt/issues). | ||||
|   If you are unable to find an open issue addressing the problem, feel free to | ||||
|   [open a new one](https://github.com/skypjack/entt/issues/new). **Please**, do | ||||
|   not forget to carefully describe how to reproduce the problem, then add all | ||||
|   the information about the system on which you are experiencing it and point | ||||
|   out the version of `EnTT` you are using (tag or commit). | ||||
|  | ||||
| * If you found a bug and you wrote a patch to fix it, open a new | ||||
|   [pull request](https://github.com/skypjack/entt/pulls) with your code. | ||||
|   **Please**, add some tests to avoid regressions in future if possible, it | ||||
|   would be really appreciated. Note that the `EnTT` library has a | ||||
|   [coverage at 100%](https://coveralls.io/github/skypjack/entt?branch=master) | ||||
|   (at least it was at 100% at the time I wrote this file) and this is the reason | ||||
|   for which you can be confident with using it in a production environment. | ||||
|  | ||||
| * If you want to propose a new feature and you know how to code it, **please** | ||||
|   do not issue directly a pull request. Before to do it, | ||||
|   [create a new issue](https://github.com/skypjack/entt/issues/new) to discuss | ||||
|   your proposal. Other users could be interested in your idea and the discussion | ||||
|   that will follow can refine it and therefore give us a better solution. | ||||
|  | ||||
| * If you want to request a new feature, I'm available for hiring. Take a look at | ||||
|   [my profile](https://github.com/skypjack) and feel free to write me. | ||||
							
								
								
									
										21
									
								
								external/entt/entt/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								external/entt/entt/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| The MIT License (MIT) | ||||
|  | ||||
| Copyright (c) 2017-2022 Michele Caini, author of EnTT | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copy of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copy or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
							
								
								
									
										431
									
								
								external/entt/entt/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										431
									
								
								external/entt/entt/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,431 @@ | ||||
|  | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| [](https://github.com/skypjack/entt/actions) | ||||
| [](https://codecov.io/gh/skypjack/entt) | ||||
| [](https://godbolt.org/z/zxW73f) | ||||
| [](http://entt.docsforge.com/) | ||||
| [](https://gitter.im/skypjack/entt) | ||||
| [](https://discord.gg/5BjPWBd) | ||||
| [](https://www.paypal.me/skypjack) | ||||
|  | ||||
| > `EnTT` has been a dream so far, we haven't found a single bug to date and it's | ||||
| > super easy to work with | ||||
| > | ||||
| > -- Every EnTT User Ever | ||||
|  | ||||
| `EnTT` is a header-only, tiny and easy to use library for game programming and | ||||
| much more written in **modern C++**.<br/> | ||||
| [Among others](https://github.com/skypjack/entt/wiki/EnTT-in-Action), it's used | ||||
| in [**Minecraft**](https://minecraft.net/en-us/attribution/) by Mojang, the | ||||
| [**ArcGIS Runtime SDKs**](https://developers.arcgis.com/arcgis-runtime/) by Esri | ||||
| and the amazing [**Ragdoll**](https://ragdolldynamics.com/).<br/> | ||||
| If you don't see your project in the list, please open an issue, submit a PR or | ||||
| add the [#entt](https://github.com/topics/entt) tag to your _topics_! :+1: | ||||
|  | ||||
| --- | ||||
|  | ||||
| Do you want to **keep up with changes** or do you have a **question** that | ||||
| doesn't require you to open an issue?<br/> | ||||
| Join the [gitter channel](https://gitter.im/skypjack/entt) and the | ||||
| [discord server](https://discord.gg/5BjPWBd), meet other users like you. The | ||||
| more we are, the better for everyone.<br/> | ||||
| Don't forget to check the | ||||
| [FAQs](https://github.com/skypjack/entt/wiki/Frequently-Asked-Questions) and the | ||||
| [wiki](https://github.com/skypjack/entt/wiki) too. Your answers may already be | ||||
| there. | ||||
|  | ||||
| Do you want to support `EnTT`? Consider becoming a | ||||
| [**sponsor**](https://github.com/users/skypjack/sponsorship). | ||||
| Many thanks to [these people](https://skypjack.github.io/sponsorship/) and | ||||
| **special** thanks to: | ||||
|  | ||||
| [](https://mojang.com) | ||||
| [](https://img.ly/) | ||||
|  | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
|   * [Code Example](#code-example) | ||||
|   * [Motivation](#motivation) | ||||
|   * [Performance](#performance) | ||||
| * [Integration](#integration) | ||||
|   * [Requirements](#requirements) | ||||
|   * [CMake](#cmake) | ||||
|   * [Natvis support](#natvis-support) | ||||
|   * [Packaging Tools](#packaging-tools) | ||||
|   * [pkg-config](#pkg-config) | ||||
| * [Documentation](#documentation) | ||||
| * [Tests](#tests) | ||||
| * [EnTT in Action](#entt-in-action) | ||||
| * [Contributors](#contributors) | ||||
| * [License](#license) | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| The entity-component-system (also known as _ECS_) is an architectural pattern | ||||
| used mostly in game development. For further details: | ||||
|  | ||||
| * [Entity Systems Wiki](http://entity-systems.wikidot.com/) | ||||
| * [Evolve Your Hierarchy](http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/) | ||||
| * [ECS on Wikipedia](https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system) | ||||
|  | ||||
| This project started off as a pure entity-component system. Over time the | ||||
| codebase has grown as more and more classes and functionalities were added.<br/> | ||||
| Here is a brief, yet incomplete list of what it offers today: | ||||
|  | ||||
| * Built-in **RTTI system** mostly similar to the standard one. | ||||
| * A `constexpr` utility for human-readable **resource names**. | ||||
| * Minimal **configuration system** built using the monostate pattern. | ||||
| * Incredibly fast **entity-component system** with its own _pay for what you | ||||
|   use_ policy, unconstrained component types with optional pointer stability and | ||||
|   hooks for storage customization. | ||||
| * Views and groups to iterate entities and components and allow different access | ||||
|   patterns, from **perfect SoA** to fully random. | ||||
| * A lot of **facilities** built on top of the entity-component system to help | ||||
|   the users and avoid reinventing the wheel. | ||||
| * General purpose **execution graph builder** for optimal scheduling. | ||||
| * The smallest and most basic implementation of a **service locator** ever seen. | ||||
| * A built-in, non-intrusive and macro-free runtime **reflection system**. | ||||
| * **Static polymorphism** made simple and within everyone's reach. | ||||
| * A few homemade containers, like a sparse set based **hash map**. | ||||
| * A **cooperative scheduler** for processes of any type. | ||||
| * All that is needed for **resource management** (cache, loaders, handles). | ||||
| * Delegates, **signal handlers** and a tiny event dispatcher. | ||||
| * A general purpose **event emitter** as a CRTP idiom based class template. | ||||
| * And **much more**! Check out the | ||||
|   [**wiki**](https://github.com/skypjack/entt/wiki). | ||||
|  | ||||
| Consider this list a work in progress as well as the project. The whole API is | ||||
| fully documented in-code for those who are brave enough to read it.<br/> | ||||
| Please, do note that all tools are also DLL-friendly now and run smoothly across | ||||
| boundaries. | ||||
|  | ||||
| One thing known to most is that `EnTT` is also used in **Minecraft**.<br/> | ||||
| Given that the game is available literally everywhere, I can confidently say  | ||||
| that the library has been sufficiently tested on every platform that can come to  | ||||
| mind. | ||||
|  | ||||
| ## Code Example | ||||
|  | ||||
| ```cpp | ||||
| #include <entt/entt.hpp> | ||||
|  | ||||
| struct position { | ||||
|     float x; | ||||
|     float y; | ||||
| }; | ||||
|  | ||||
| struct velocity { | ||||
|     float dx; | ||||
|     float dy; | ||||
| }; | ||||
|  | ||||
| void update(entt::registry ®istry) { | ||||
|     auto view = registry.view<const position, velocity>(); | ||||
|  | ||||
|     // use a callback | ||||
|     view.each([](const auto &pos, auto &vel) { /* ... */ }); | ||||
|  | ||||
|     // use an extended callback | ||||
|     view.each([](const auto entity, const auto &pos, auto &vel) { /* ... */ }); | ||||
|  | ||||
|     // use a range-for | ||||
|     for(auto [entity, pos, vel]: view.each()) { | ||||
|         // ... | ||||
|     } | ||||
|  | ||||
|     // use forward iterators and get only the components of interest | ||||
|     for(auto entity: view) { | ||||
|         auto &vel = view.get<velocity>(entity); | ||||
|         // ... | ||||
|     } | ||||
| } | ||||
|  | ||||
| int main() { | ||||
|     entt::registry registry; | ||||
|  | ||||
|     for(auto i = 0u; i < 10u; ++i) { | ||||
|         const auto entity = registry.create(); | ||||
|         registry.emplace<position>(entity, i * 1.f, i * 1.f); | ||||
|         if(i % 2 == 0) { registry.emplace<velocity>(entity, i * .1f, i * .1f); } | ||||
|     } | ||||
|  | ||||
|     update(registry); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ## Motivation | ||||
|  | ||||
| I started developing `EnTT` for the _wrong_ reason: my goal was to design an | ||||
| entity-component system to beat another well known open source library both in | ||||
| terms of performance and possibly memory usage.<br/> | ||||
| In the end, I did it, but it wasn't very satisfying. Actually it wasn't | ||||
| satisfying at all. The fastest and nothing more, fairly little indeed. When I | ||||
| realized it, I tried hard to keep intact the great performance of `EnTT` and to | ||||
| add all the features I wanted to see in *my own library* at the same time. | ||||
|  | ||||
| Nowadays, `EnTT` is finally what I was looking for: still faster than its | ||||
| _competitors_, lower memory usage in the average case, a really good API and an | ||||
| amazing set of features. And even more, of course. | ||||
|  | ||||
| ## Performance | ||||
|  | ||||
| The proposed entity-component system is incredibly fast to iterate entities and | ||||
| components, this is a fact. Some compilers make a lot of optimizations because | ||||
| of how `EnTT` works, some others aren't that good. In general, if we consider | ||||
| real world cases, `EnTT` is somewhere between a bit and much faster than many of | ||||
| the other solutions around, although I couldn't check them all for obvious | ||||
| reasons. | ||||
|  | ||||
| If you are interested, you can compile the `benchmark` test in release mode (to | ||||
| enable compiler optimizations, otherwise it would make little sense) by setting | ||||
| the `ENTT_BUILD_BENCHMARK` option of `CMake` to `ON`, then evaluate yourself | ||||
| whether you're satisfied with the results or not. | ||||
|  | ||||
| Honestly I got tired of updating the README file whenever there is an | ||||
| improvement.<br/> | ||||
| There are already a lot of projects out there that use `EnTT` as a basis for | ||||
| comparison (this should already tell you a lot). Many of these benchmarks are | ||||
| completely wrong, many others are simply incomplete, good at omitting some | ||||
| information and using the wrong function to compare a given feature. Certainly | ||||
| there are also good ones but they age quickly if nobody updates them, especially | ||||
| when the library they are dealing with is actively developed. | ||||
|  | ||||
| The choice to use `EnTT` should be based on its carefully designed API, its | ||||
| set of features and the general performance, **not** because some single | ||||
| benchmark shows it to be the fastest tool available. | ||||
|  | ||||
| In the future I'll likely try to get even better performance while still adding | ||||
| new features, mainly for fun.<br/> | ||||
| If you want to contribute and/or have suggestions, feel free to make a PR or | ||||
| open an issue to discuss your idea. | ||||
|  | ||||
| # Integration | ||||
|  | ||||
| `EnTT` is a header-only library. This means that including the `entt.hpp` header | ||||
| is enough to include the library as a whole and use it. For those who are | ||||
| interested only in the entity-component system, consider to include the sole | ||||
| `entity/registry.hpp` header instead.<br/> | ||||
| It's a matter of adding the following line to the top of a file: | ||||
|  | ||||
| ```cpp | ||||
| #include <entt/entt.hpp> | ||||
| ``` | ||||
|  | ||||
| Use the line below to include only the entity-component system instead: | ||||
|  | ||||
| ```cpp | ||||
| #include <entt/entity/registry.hpp> | ||||
| ``` | ||||
|  | ||||
| Then pass the proper `-I` argument to the compiler to add the `src` directory to | ||||
| the include paths. | ||||
|  | ||||
| ## Requirements | ||||
|  | ||||
| To be able to use `EnTT`, users must provide a full-featured compiler that | ||||
| supports at least C++17.<br/> | ||||
| The requirements below are mandatory to compile the tests and to extract the | ||||
| documentation: | ||||
|  | ||||
| * `CMake` version 3.7 or later. | ||||
| * `Doxygen` version 1.8 or later. | ||||
|  | ||||
| Alternatively, [Bazel](https://bazel.build) is also supported as a build system | ||||
| (credits to [zaucy](https://github.com/zaucy) who offered to maintain it).<br/> | ||||
| In the documentation below I'll still refer to `CMake`, this being the official | ||||
| build system of the library. | ||||
|  | ||||
| ## CMake | ||||
|  | ||||
| To use `EnTT` from a `CMake` project, just link an existing target to the | ||||
| `EnTT::EnTT` alias.<br/> | ||||
| The library offers everything you need for locating (as in `find_package`), | ||||
| embedding (as in `add_subdirectory`), fetching (as in `FetchContent`) or using | ||||
| it in many of the ways that you can think of and that involve `CMake`.<br/> | ||||
| Covering all possible cases would require a treaty and not a simple README file, | ||||
| but I'm confident that anyone reading this section also knows what it's about | ||||
| and can use `EnTT` from a `CMake` project without problems. | ||||
|  | ||||
| ## Natvis support | ||||
|  | ||||
| When using `CMake`, just enable the option `ENTT_INCLUDE_NATVIS` and enjoy | ||||
| it.<br/> | ||||
| Otherwise, most of the tools are covered via Natvis and all files can be found | ||||
| in the `natvis` directory, divided by module.<br/> | ||||
| If you spot errors or have suggestions, any contribution is welcome! | ||||
|  | ||||
| ## Packaging Tools | ||||
|  | ||||
| `EnTT` is available for some of the most known packaging tools. In particular: | ||||
|  | ||||
| * [`Conan`](https://github.com/conan-io/conan-center-index), the C/C++ Package | ||||
|   Manager for Developers. | ||||
|  | ||||
| * [`vcpkg`](https://github.com/Microsoft/vcpkg), Microsoft VC++ Packaging | ||||
|   Tool.<br/> | ||||
|   You can download and install `EnTT` in just a few simple steps: | ||||
|  | ||||
|   ``` | ||||
|   $ git clone https://github.com/Microsoft/vcpkg.git | ||||
|   $ cd vcpkg | ||||
|   $ ./bootstrap-vcpkg.sh | ||||
|   $ ./vcpkg integrate install | ||||
|   $ vcpkg install entt | ||||
|   ``` | ||||
|  | ||||
|   Or you can use the `experimental` feature to test the latest changes: | ||||
|  | ||||
|   ``` | ||||
|   vcpkg install entt[experimental] --head | ||||
|   ``` | ||||
|  | ||||
|   The `EnTT` port in `vcpkg` is kept up to date by Microsoft team members and | ||||
|   community contributors.<br/> | ||||
|   If the version is out of date, please | ||||
|   [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the | ||||
|   `vcpkg` repository. | ||||
|  | ||||
| * [`Homebrew`](https://github.com/skypjack/homebrew-entt), the missing package | ||||
|   manager for macOS.<br/> | ||||
|   Available as a homebrew formula. Just type the following to install it: | ||||
|  | ||||
|   ``` | ||||
|   brew install skypjack/entt/entt | ||||
|   ``` | ||||
|  | ||||
| * [`build2`](https://build2.org), build toolchain for developing and packaging C | ||||
|   and C++ code.<br/> | ||||
|   In order to use the [`entt`](https://cppget.org/entt) package in a `build2` | ||||
|   project, add the following line or a similar one to the `manifest` file: | ||||
|  | ||||
|   ``` | ||||
|   depends: entt ^3.0.0 | ||||
|   ``` | ||||
|  | ||||
|   Also check that the configuration refers to a valid repository, so that the | ||||
|   package can be found by `build2`: | ||||
|  | ||||
|   * [`cppget.org`](https://cppget.org), the open-source community central | ||||
|     repository, accessible as `https://pkg.cppget.org/1/stable`. | ||||
|  | ||||
|   * [Package source repository](https://github.com/build2-packaging/entt): | ||||
|     accessible as either `https://github.com/build2-packaging/entt.git` or | ||||
|     `ssh://git@github.com/build2-packaging/entt.git`. | ||||
|     Feel free to [report issues](https://github.com/build2-packaging/entt) with | ||||
|     this package. | ||||
|  | ||||
|   Both can be used with `bpkg add-repo` or added in a project | ||||
|   `repositories.manifest`. See the official | ||||
|   [documentation](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-repositories) | ||||
|   for more details. | ||||
|  | ||||
| Consider this list a work in progress and help me to make it longer if you like. | ||||
|  | ||||
| ## pkg-config | ||||
|  | ||||
| `EnTT` also supports `pkg-config` (for some definition of _supports_ at least). | ||||
| A suitable file called `entt.pc` is generated and installed in a proper | ||||
| directory when running `CMake`.<br/> | ||||
| This should also make it easier to use with tools such as `Meson` or similar. | ||||
|  | ||||
| # Documentation | ||||
|  | ||||
| The documentation is based on [doxygen](http://www.doxygen.nl/). To build it: | ||||
|  | ||||
|     $ cd build | ||||
|     $ cmake .. -DENTT_BUILD_DOCS=ON | ||||
|     $ make | ||||
|  | ||||
| The API reference will be created in HTML format within the directory | ||||
| `build/docs/html`. To navigate it with your favorite browser: | ||||
|  | ||||
|     $ cd build | ||||
|     $ your_favorite_browser docs/html/index.html | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| The same version is also available [online](https://skypjack.github.io/entt/) | ||||
| for the latest release, that is the last stable tag. If you are looking for | ||||
| something more pleasing to the eye, consider reading the nice-looking version | ||||
| available on [docsforge](https://entt.docsforge.com/): same documentation, much | ||||
| more pleasant to read.<br/> | ||||
| Moreover, there exists a [wiki](https://github.com/skypjack/entt/wiki) dedicated | ||||
| to the project where users can find all related documentation pages. | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Tests | ||||
|  | ||||
| To compile and run the tests, `EnTT` requires *googletest*.<br/> | ||||
| `cmake` will download and compile the library before compiling anything else. | ||||
| In order to build the tests, set the `CMake` option `ENTT_BUILD_TESTING` to | ||||
| `ON`. | ||||
|  | ||||
| To build the most basic set of tests: | ||||
|  | ||||
| * `$ cd build` | ||||
| * `$ cmake -DENTT_BUILD_TESTING=ON ..` | ||||
| * `$ make` | ||||
| * `$ make test` | ||||
|  | ||||
| Note that benchmarks are not part of this set. | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # EnTT in Action | ||||
|  | ||||
| `EnTT` is widely used in private and commercial applications. I cannot even | ||||
| mention most of them because of some signatures I put on some documents time | ||||
| ago. Fortunately, there are also people who took the time to implement open | ||||
| source projects based on `EnTT` and did not hold back when it came to | ||||
| documenting them. | ||||
|  | ||||
| [Here](https://github.com/skypjack/entt/wiki/EnTT-in-Action) you can find an | ||||
| incomplete list of games, applications and articles that can be used as a | ||||
| reference. | ||||
|  | ||||
| If you know of other resources out there that are about `EnTT`, feel free to | ||||
| open an issue or a PR and I'll be glad to add them to the list. | ||||
|  | ||||
| # Contributors | ||||
|  | ||||
| Requests for features, PRs, suggestions ad feedback are highly appreciated. | ||||
|  | ||||
| If you find you can help and want to contribute to the project with your | ||||
| experience or you do want to get part of the project for some other reason, feel | ||||
| free to contact me directly (you can find the mail in the | ||||
| [profile](https://github.com/skypjack)).<br/> | ||||
| I can't promise that each and every contribution will be accepted, but I can | ||||
| assure that I'll do my best to take them all as soon as possible. | ||||
|  | ||||
| If you decide to participate, please see the guidelines for | ||||
| [contributing](CONTRIBUTING.md) before to create issues or pull | ||||
| requests.<br/> | ||||
| Take also a look at the | ||||
| [contributors list](https://github.com/skypjack/entt/blob/master/AUTHORS) to | ||||
| know who has participated so far. | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # License | ||||
|  | ||||
| Code and documentation Copyright (c) 2017-2022 Michele Caini.<br/> | ||||
| Colorful logo Copyright (c) 2018-2021 Richard Caseres. | ||||
|  | ||||
| Code released under | ||||
| [the MIT license](https://github.com/skypjack/entt/blob/master/LICENSE).<br/> | ||||
| Documentation released under | ||||
| [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).<br/> | ||||
| All logos released under | ||||
| [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/). | ||||
							
								
								
									
										27
									
								
								external/entt/entt/TODO
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								external/entt/entt/TODO
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| * debugging tools (#60): the issue online already contains interesting tips on this, look at it | ||||
| * work stealing job system (see #100) + mt scheduler based on const awareness for types | ||||
|  | ||||
| EXAMPLES | ||||
| * filter on runtime values/variables (not only types) | ||||
| * support to polymorphic types (see #859) | ||||
|  | ||||
| DOC: | ||||
| * storage<void> | ||||
| * custom storage/view | ||||
| * examples (and credits) from @alanjfs :) | ||||
| * update entity doc when the storage based model is in place | ||||
|  | ||||
| TODO (high prio): | ||||
| * remove the static storage from the const assure in the registry | ||||
|  | ||||
| WIP: | ||||
| * get rid of observers, storage based views made them pointless - document alternatives | ||||
| * add storage getter for filters to views and groups | ||||
| * exploit the tombstone mechanism to allow enabling/disabling entities (see bump, compact and clear for further details) | ||||
| * basic_storage::bind for cross-registry setups (see and remove todo from entity_copy.cpp) | ||||
| * process scheduler: reviews, use free lists internally | ||||
| * dedicated entity storage, in-place O(1) release/destroy for non-orphaned entities, out-of-sync model | ||||
| * entity-only and exclude-only views (both solved with entity storage and storage<void>) | ||||
| * custom allocators all over (registry, ...) | ||||
| * add test for maximum number of entities reached | ||||
| * deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views | ||||
							
								
								
									
										1
									
								
								external/entt/entt/WORKSPACE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								external/entt/entt/WORKSPACE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| workspace(name = "com_github_skypjack_entt") | ||||
							
								
								
									
										2
									
								
								external/entt/entt/build/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								external/entt/entt/build/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| * | ||||
| !.gitignore | ||||
							
								
								
									
										5
									
								
								external/entt/entt/cmake/in/EnTTConfig.cmake.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								external/entt/entt/cmake/in/EnTTConfig.cmake.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| @PACKAGE_INIT@ | ||||
|  | ||||
| set(EnTT_VERSION "@PROJECT_VERSION@") | ||||
| include("${CMAKE_CURRENT_LIST_DIR}/EnTTTargets.cmake") | ||||
| check_required_components("@PROJECT_NAME@") | ||||
							
								
								
									
										8
									
								
								external/entt/entt/cmake/in/entt.pc.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								external/entt/entt/cmake/in/entt.pc.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| prefix=@CMAKE_INSTALL_PREFIX@ | ||||
| includedir=@EnTT_PKGCONFIG_INCLUDEDIR@ | ||||
|  | ||||
| Name: EnTT | ||||
| Description: Gaming meets modern C++ | ||||
| Url: https://github.com/skypjack/entt | ||||
| Version: @ENTT_VERSION@ | ||||
| Cflags: -I${includedir} | ||||
							
								
								
									
										23
									
								
								external/entt/entt/cmake/modules/JoinPaths.cmake
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								external/entt/entt/cmake/modules/JoinPaths.cmake
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| # This module provides function for joining paths | ||||
| # known from most languages | ||||
| # | ||||
| # SPDX-License-Identifier: (MIT OR CC0-1.0) | ||||
| # Copyright 2020 Jan Tojnar | ||||
| # https://github.com/jtojnar/cmake-snips | ||||
| # | ||||
| # Modelled after Python<6F>s os.path.join | ||||
| # https://docs.python.org/3.7/library/os.path.html#os.path.join | ||||
| # Windows not supported | ||||
| function(join_paths joined_path first_path_segment) | ||||
|     set(temp_path "${first_path_segment}") | ||||
|     foreach(current_segment IN LISTS ARGN) | ||||
|         if(NOT ("${current_segment}" STREQUAL "")) | ||||
|             if(IS_ABSOLUTE "${current_segment}") | ||||
|                 set(temp_path "${current_segment}") | ||||
|             else() | ||||
|                 set(temp_path "${temp_path}/${current_segment}") | ||||
|             endif() | ||||
|         endif() | ||||
|     endforeach() | ||||
|     set(${joined_path} "${temp_path}" PARENT_SCOPE) | ||||
| endfunction() | ||||
							
								
								
									
										37
									
								
								external/entt/entt/conan/build.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								external/entt/entt/conan/build.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| #!/usr/bin/env python | ||||
| # -*- coding: utf-8 -*- | ||||
| from cpt.packager import ConanMultiPackager | ||||
| import os | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     username = os.getenv("GITHUB_ACTOR") | ||||
|     tag_version = os.getenv("GITHUB_REF") | ||||
|     tag_package = os.getenv("GITHUB_REPOSITORY") | ||||
|     login_username = os.getenv("CONAN_LOGIN_USERNAME") | ||||
|     package_version = tag_version.replace("refs/tags/v", "") | ||||
|     package_name = tag_package.replace("skypjack/", "") | ||||
|     reference = "{}/{}".format(package_name, package_version) | ||||
|     channel = os.getenv("CONAN_CHANNEL", "stable") | ||||
|     upload = os.getenv("CONAN_UPLOAD") | ||||
|     stable_branch_pattern = os.getenv("CONAN_STABLE_BRANCH_PATTERN", r"v\d+\.\d+\.\d+.*") | ||||
|     test_folder = os.getenv("CPT_TEST_FOLDER", os.path.join("conan", "test_package")) | ||||
|     upload_only_when_stable = os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", True) | ||||
|     disable_shared = os.getenv("CONAN_DISABLE_SHARED_BUILD", "False") | ||||
|  | ||||
|     builder = ConanMultiPackager(username=username, | ||||
|                                  reference=reference, | ||||
|                                  channel=channel, | ||||
|                                  login_username=login_username, | ||||
|                                  upload=upload, | ||||
|                                  stable_branch_pattern=stable_branch_pattern, | ||||
|                                  upload_only_when_stable=upload_only_when_stable, | ||||
|                                  test_folder=test_folder) | ||||
|     builder.add() | ||||
|  | ||||
|     filtered_builds = [] | ||||
|     for settings, options, env_vars, build_requires, reference in builder.items: | ||||
|         if disable_shared == "False" or not options["{}:shared".format(package_name)]: | ||||
|              filtered_builds.append([settings, options, env_vars, build_requires]) | ||||
|     builder.builds = filtered_builds | ||||
|  | ||||
|     builder.run() | ||||
							
								
								
									
										7
									
								
								external/entt/entt/conan/ci/build.sh
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								external/entt/entt/conan/ci/build.sh
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| set -e | ||||
| set -x | ||||
|  | ||||
| conan user | ||||
| python conan/build.py | ||||
							
								
								
									
										6
									
								
								external/entt/entt/conan/ci/install.sh
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								external/entt/entt/conan/ci/install.sh
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| set -e | ||||
| set -x | ||||
|  | ||||
| pip install -U conan_package_tools conan | ||||
							
								
								
									
										13
									
								
								external/entt/entt/conan/test_package/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								external/entt/entt/conan/test_package/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| cmake_minimum_required(VERSION 3.7.2) | ||||
| project(test_package) | ||||
|  | ||||
| set(CMAKE_VERBOSE_MAKEFILE TRUE) | ||||
|  | ||||
| set(CMAKE_CXX_STANDARD 17) | ||||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||||
|  | ||||
| include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) | ||||
| conan_basic_setup() | ||||
|  | ||||
| add_executable(${PROJECT_NAME} test_package.cpp) | ||||
| target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS}) | ||||
							
								
								
									
										19
									
								
								external/entt/entt/conan/test_package/conanfile.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								external/entt/entt/conan/test_package/conanfile.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| #!/usr/bin/env python | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| from conans import ConanFile, CMake | ||||
| import os | ||||
|  | ||||
|  | ||||
| class TestPackageConan(ConanFile): | ||||
|     settings = "os", "compiler", "build_type", "arch" | ||||
|     generators = "cmake" | ||||
|  | ||||
|     def build(self): | ||||
|         cmake = CMake(self) | ||||
|         cmake.configure() | ||||
|         cmake.build() | ||||
|  | ||||
|     def test(self): | ||||
|         bin_path = os.path.join("bin", "test_package") | ||||
|         self.run(bin_path, run_environment=True) | ||||
							
								
								
									
										56
									
								
								external/entt/entt/conan/test_package/test_package.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								external/entt/entt/conan/test_package/test_package.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| #include <entt/entt.hpp> | ||||
| #include <cstdint> | ||||
|  | ||||
| struct position { | ||||
|     float x; | ||||
|     float y; | ||||
| }; | ||||
|  | ||||
| struct velocity { | ||||
|     float dx; | ||||
|     float dy; | ||||
| }; | ||||
|  | ||||
| void update(entt::registry ®istry) { | ||||
|     auto view = registry.view<position, velocity>(); | ||||
|  | ||||
|     for(auto entity: view) { | ||||
|         // gets only the components that are going to be used ... | ||||
|  | ||||
|         auto &vel = view.get<velocity>(entity); | ||||
|  | ||||
|         vel.dx = 0.; | ||||
|         vel.dy = 0.; | ||||
|  | ||||
|         // ... | ||||
|     } | ||||
| } | ||||
|  | ||||
| void update(std::uint64_t dt, entt::registry ®istry) { | ||||
|     registry.view<position, velocity>().each([dt](auto &pos, auto &vel) { | ||||
|         // gets all the components of the view at once ... | ||||
|  | ||||
|         pos.x += vel.dx * dt; | ||||
|         pos.y += vel.dy * dt; | ||||
|  | ||||
|         // ... | ||||
|     }); | ||||
| } | ||||
|  | ||||
| int main() { | ||||
|     entt::registry registry; | ||||
|     std::uint64_t dt = 16; | ||||
|  | ||||
|     for(auto i = 0; i < 10; ++i) { | ||||
|         auto entity = registry.create(); | ||||
|         registry.emplace<position>(entity, i * 1.f, i * 1.f); | ||||
|         if(i % 2 == 0) { registry.emplace<velocity>(entity, i * .1f, i * .1f); } | ||||
|     } | ||||
|  | ||||
|     update(dt, registry); | ||||
|     update(registry); | ||||
|  | ||||
|     // ... | ||||
|  | ||||
|     return EXIT_SUCCESS; | ||||
| } | ||||
							
								
								
									
										27
									
								
								external/entt/entt/conanfile.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								external/entt/entt/conanfile.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| #!/usr/bin/env python | ||||
| # -*- coding: utf-8 -*- | ||||
| from conans import ConanFile | ||||
|  | ||||
|  | ||||
| class EnttConan(ConanFile): | ||||
|     name = "entt" | ||||
|     description = "Gaming meets modern C++ - a fast and reliable entity-component system (ECS) and much more " | ||||
|     topics = ("conan," "entt", "gaming", "entity", "ecs") | ||||
|     url = "https://github.com/skypjack/entt" | ||||
|     homepage = url | ||||
|     author = "Michele Caini <michele.caini@gmail.com>" | ||||
|     license = "MIT" | ||||
|     exports = ["LICENSE"] | ||||
|     exports_sources = ["src/*"] | ||||
|     no_copy_source = True | ||||
|  | ||||
|     def package(self): | ||||
|         self.copy(pattern="LICENSE", dst="licenses") | ||||
|         self.copy(pattern="*", dst="include", src="src", keep_path=True) | ||||
|  | ||||
|     def package_info(self): | ||||
|         if not self.in_local_cache: | ||||
|             self.cpp_info.includedirs = ["src"] | ||||
|  | ||||
|     def package_id(self): | ||||
|         self.info.header_only() | ||||
							
								
								
									
										40
									
								
								external/entt/entt/docs/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								external/entt/entt/docs/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| # | ||||
| # Doxygen configuration (documentation) | ||||
| # | ||||
|  | ||||
| set(DOXY_DEPS_DIRECTORY ${EnTT_SOURCE_DIR}/deps) | ||||
| set(DOXY_SOURCE_DIRECTORY ${EnTT_SOURCE_DIR}/src) | ||||
| set(DOXY_DOCS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) | ||||
| set(DOXY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) | ||||
|  | ||||
| configure_file(doxy.in doxy.cfg @ONLY) | ||||
|  | ||||
| add_custom_target( | ||||
|     docs ALL | ||||
|     COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.cfg | ||||
|     WORKING_DIRECTORY ${EnTT_SOURCE_DIR} | ||||
|     VERBATIM | ||||
|     SOURCES | ||||
|         dox/extra.dox | ||||
|         md/config.md | ||||
|         md/container.md | ||||
|         md/core.md | ||||
|         md/entity.md | ||||
|         md/faq.md | ||||
|         md/lib.md | ||||
|         md/links.md | ||||
|         md/locator.md | ||||
|         md/meta.md | ||||
|         md/poly.md | ||||
|         md/process.md | ||||
|         md/reference.md | ||||
|         md/resource.md | ||||
|         md/signal.md | ||||
|         md/unreal.md | ||||
|         doxy.in | ||||
| ) | ||||
|  | ||||
| install( | ||||
|     DIRECTORY ${DOXY_OUTPUT_DIRECTORY}/html | ||||
|     DESTINATION share/${PROJECT_NAME}-${PROJECT_VERSION}/ | ||||
| ) | ||||
							
								
								
									
										5
									
								
								external/entt/entt/docs/dox/extra.dox
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								external/entt/entt/docs/dox/extra.dox
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| /** | ||||
|  * @namespace entt | ||||
|  * | ||||
|  * @brief `EnTT` default namespace. | ||||
|  */ | ||||
							
								
								
									
										2682
									
								
								external/entt/entt/docs/doxy.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2682
									
								
								external/entt/entt/docs/doxy.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										121
									
								
								external/entt/entt/docs/md/config.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								external/entt/entt/docs/md/config.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| # Crash Course: configuration | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
| * [Definitions](#definitions) | ||||
|   * [ENTT_NOEXCEPTION](#entt_noexception) | ||||
|   * [ENTT_USE_ATOMIC](#entt_use_atomic) | ||||
|   * [ENTT_ID_TYPE](#entt_id_type) | ||||
|   * [ENTT_SPARSE_PAGE](#entt_sparse_page) | ||||
|   * [ENTT_PACKED_PAGE](#entt_packed_page) | ||||
|   * [ENTT_ASSERT](#entt_assert) | ||||
|     * [ENTT_ASSERT_CONSTEXPR](#entt_assert_constexpr) | ||||
|     * [ENTT_DISABLE_ASSERT](#entt_disable_assert) | ||||
|   * [ENTT_NO_ETO](#entt_no_eto) | ||||
|   * [ENTT_STANDARD_CPP](#entt_standard_cpp) | ||||
|  | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| `EnTT` has become almost completely customizable over time, in many | ||||
| respects. These variables are just one of the many ways to customize how it | ||||
| works.<br/> | ||||
| In the vast majority of cases, users will have no interest in changing the | ||||
| default parameters. For all other cases, the list of possible configurations | ||||
| with which it's possible to adjust the behavior of the library at runtime can be | ||||
| found below. | ||||
|  | ||||
| # Definitions | ||||
|  | ||||
| All options are intended as parameters to the compiler (or user-defined macros | ||||
| within the compilation units, if preferred).<br/> | ||||
| Each parameter can result in internal library definitions. It's not recommended | ||||
| to try to also modify these definitions, since there is no guarantee that they | ||||
| will remain stable over time unlike the options below. | ||||
|  | ||||
| ## ENTT_NOEXCEPTION | ||||
|  | ||||
| Define this variable without assigning any value to it to turn off exception | ||||
| handling in `EnTT`.<br/> | ||||
| This is roughly equivalent to setting the compiler flag `-fno-exceptions` but is | ||||
| also limited to this library only. | ||||
|  | ||||
| ## ENTT_USE_ATOMIC | ||||
|  | ||||
| In general, `EnTT` doesn't offer primitives to support multi-threading. Many of | ||||
| the features can be split over multiple threads without any explicit control and | ||||
| the user is the one who knows if a synchronization point is required.<br/> | ||||
| However, some features aren't easily accessible to users and are made | ||||
| thread-safe by means of this definition. | ||||
|  | ||||
| ## ENTT_ID_TYPE | ||||
|  | ||||
| `entt::id_type` is directly controlled by this definition and widely used within | ||||
| the library.<br/> | ||||
| By default, its type is `std::uint32_t`. However, users can define a different | ||||
| default type if necessary. | ||||
|  | ||||
| ## ENTT_SPARSE_PAGE | ||||
|  | ||||
| It's known that the ECS module of `EnTT` is based on _sparse sets_. What is less | ||||
| known perhaps is that the sparse arrays are paged to reduce memory usage.<br/> | ||||
| Default size of pages (that is, the number of elements they contain) is 4096 but | ||||
| users can adjust it if appropriate. In all case, the chosen value **must** be a | ||||
| power of 2. | ||||
|  | ||||
| ## ENTT_PACKED_PAGE | ||||
|  | ||||
| As it happens with sparse arrays, packed arrays are also paginated. However, in | ||||
| this case the aim isn't to reduce memory usage but to have pointer stability | ||||
| upon component creation.<br/> | ||||
| Default size of pages (that is, the number of elements they contain) is 1024 but | ||||
| users can adjust it if appropriate. In all case, the chosen value **must** be a | ||||
| power of 2. | ||||
|  | ||||
| ## ENTT_ASSERT | ||||
|  | ||||
| For performance reasons, `EnTT` doesn't use exceptions or any other control | ||||
| structures. In fact, it offers many features that result in undefined behavior | ||||
| if not used correctly.<br/> | ||||
| To get around this, the library relies on a lot of asserts for the purpose of | ||||
| detecting errors in debug builds. By default, it uses `assert` internally. Users | ||||
| are allowed to overwrite its behavior by setting this variable. | ||||
|  | ||||
| ### ENTT_ASSERT_CONSTEXPR | ||||
|  | ||||
| Usually, an assert within a `constexpr` function isn't a big deal. However, in | ||||
| case of extreme customizations, it might be useful to differentiate.<br/> | ||||
| For this purpose, `EnTT` introduces an admittedly badly named variable to make | ||||
| the job easier in this regard. By default, this variable forwards its arguments | ||||
| to `ENTT_ASSERT`. | ||||
|  | ||||
| ### ENTT_DISABLE_ASSERT | ||||
|  | ||||
| Assertions may in turn affect performance to an extent when enabled. Whether | ||||
| `ENTT_ASSERT` and `ENTT_ASSERT_CONSTEXPR` are redefined or not, all asserts can | ||||
| be disabled at once by means of this definition.<br/> | ||||
| Note that `ENTT_DISABLE_ASSERT` takes precedence over the redefinition of the | ||||
| other variables and is therefore meant to disable all controls no matter what. | ||||
|  | ||||
| ## ENTT_NO_ETO | ||||
|  | ||||
| In order to reduce memory consumption and increase performance, empty types are | ||||
| never instantiated nor stored by the ECS module of `EnTT`.<br/> | ||||
| Use this variable to treat these types like all others and therefore to create a | ||||
| dedicated storage for them. | ||||
|  | ||||
| ## ENTT_STANDARD_CPP | ||||
|  | ||||
| `EnTT` mixes non-standard language features with others that are perfectly | ||||
| compliant to offer some of its functionalities.<br/> | ||||
| This definition prevents the library from using non-standard techniques, that | ||||
| is, functionalities that aren't fully compliant with the standard C++.<br/> | ||||
| While there are no known portability issues at the time of this writing, this | ||||
| should make the library fully portable anyway if needed. | ||||
							
								
								
									
										67
									
								
								external/entt/entt/docs/md/container.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								external/entt/entt/docs/md/container.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| # Crash Course: containers | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
| * [Containers](#containers) | ||||
|   * [Dense map](#dense-map) | ||||
|   * [Dense set](#dense-set) | ||||
|  | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| The standard C++ library offers a wide range of containers and it's really | ||||
| difficult to do better (although it's very easy to do worse, as many examples | ||||
| available online demonstrate).<br/> | ||||
| `EnTT` doesn't try in any way to replace what is offered by the standard. Quite | ||||
| the opposite, given the widespread use that is made of standard containers.<br/> | ||||
| However, the library also tries to fill a gap in features and functionality by | ||||
| making available some containers initially developed for internal use. | ||||
|  | ||||
| This section of the library is likely to grow larger over time. However, for the | ||||
| moment it's quite small and mainly aimed at satisfying some internal needs.<br/> | ||||
| For all containers made available, full test coverage and stability over time is | ||||
| guaranteed as usual. | ||||
|  | ||||
| # Containers | ||||
|  | ||||
| ## Dense map | ||||
|  | ||||
| The dense map made available in `EnTT` is a hash map that aims to return a | ||||
| packed array of elements, so as to reduce the number of jumps in memory during | ||||
| iterations.<br/> | ||||
| The implementation is based on _sparse sets_ and each bucket is identified by an | ||||
| implicit list within the packed array itself. | ||||
|  | ||||
| The interface is very close to its counterpart in the standard library, that is, | ||||
| `std::unordered_map`.<br/> | ||||
| However, both local and non-local iterators returned by a dense map belong to | ||||
| the input iterator category although they respectively model the concepts of a | ||||
| _forward iterator_ type and a _random access iterator_ type.<br/> | ||||
| This is because they return a pair of references rather than a reference to a | ||||
| pair. In other words, dense maps return a so called _proxy iterator_ the value | ||||
| type of which is: | ||||
|  | ||||
| * `std::pair<const Key &, Type &>` for non-const iterator types. | ||||
| * `std::pair<const Key &, const Type &>` for const iterator types. | ||||
|  | ||||
| This is quite different from what any standard library map returns and should be | ||||
| taken into account when looking for a drop-in replacement. | ||||
|  | ||||
| ## Dense set | ||||
|  | ||||
| The dense set made available in `EnTT` is a hash set that aims to return a | ||||
| packed array of elements, so as to reduce the number of jumps in memory during | ||||
| iterations.<br/> | ||||
| The implementation is based on _sparse sets_ and each bucket is identified by an | ||||
| implicit list within the packed array itself. | ||||
|  | ||||
| The interface is in all respects similar to its counterpart in the standard | ||||
| library, that is, `std::unordered_set`.<br/> | ||||
| Therefore, there is no need to go into the API description. | ||||
							
								
								
									
										1011
									
								
								external/entt/entt/docs/md/core.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1011
									
								
								external/entt/entt/docs/md/core.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2252
									
								
								external/entt/entt/docs/md/entity.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2252
									
								
								external/entt/entt/docs/md/entity.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										215
									
								
								external/entt/entt/docs/md/faq.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								external/entt/entt/docs/md/faq.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,215 @@ | ||||
| # Frequently Asked Questions | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
| * [FAQ](#faq) | ||||
|   * [Why is my debug build on Windows so slow?](#why-is-my-debug-build-on-windows-so-slow) | ||||
|   * [How can I represent hierarchies with my components?](#how-can-i-represent-hierarchies-with-my-components) | ||||
|   * [Custom entity identifiers: yay or nay?](#custom-entity-identifiers-yay-or-nay) | ||||
|   * [Warning C4307: integral constant overflow](#warning-C4307-integral-constant-overflow) | ||||
|   * [Warning C4003: the min, the max and the macro](#warning-C4003-the-min-the-max-and-the-macro) | ||||
|   * [The standard and the non-copyable types](#the-standard-and-the-non-copyable-types) | ||||
|   * [Which functions trigger which signals](#which-functions-trigger-which-signals) | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| This is a constantly updated section where I'm trying to put the answers to the | ||||
| most frequently asked questions.<br/> | ||||
| If you don't find your answer here, there are two cases: nobody has done it yet | ||||
| or this section needs updating. In both cases, you can | ||||
| [open a new issue](https://github.com/skypjack/entt/issues/new) or enter either | ||||
| the [gitter channel](https://gitter.im/skypjack/entt) or the | ||||
| [discord server](https://discord.gg/5BjPWBd) to ask for help.<br/> | ||||
| Probably someone already has an answer for you and we can then integrate this | ||||
| part of the documentation. | ||||
|  | ||||
| # FAQ | ||||
|  | ||||
| ## Why is my debug build on Windows so slow? | ||||
|  | ||||
| `EnTT` is an experimental project that I also use to keep me up-to-date with the | ||||
| latest revision of the language and the standard library. For this reason, it's | ||||
| likely that some classes you're working with are using standard containers under | ||||
| the hood.<br/> | ||||
| Unfortunately, it's known that the standard containers aren't particularly | ||||
| performing in debugging (the reasons for this go beyond this document) and are | ||||
| even less so on Windows apparently. Fortunately this can also be mitigated a | ||||
| lot, achieving good results in many cases. | ||||
|  | ||||
| First of all, there are two things to do in a Windows project: | ||||
|  | ||||
| * Disable the [`/JMC`](https://docs.microsoft.com/cpp/build/reference/jmc) | ||||
|   option (_Just My Code_ debugging), available starting with Visual Studio 2017 | ||||
|   version 15.8. | ||||
|  | ||||
| * Set the [`_ITERATOR_DEBUG_LEVEL`](https://docs.microsoft.com/cpp/standard-library/iterator-debug-level) | ||||
|   macro to 0. This will disable checked iterators and iterator debugging. | ||||
|  | ||||
| Moreover, set the `ENTT_DISABLE_ASSERT` variable or redefine the `ENTT_ASSERT` | ||||
| macro to disable internal debug checks in `EnTT`: | ||||
|  | ||||
| ```cpp | ||||
| #define ENTT_ASSERT(...) ((void)0) | ||||
| ``` | ||||
|  | ||||
| These asserts are introduced to help the users but they require to access to the | ||||
| underlying containers and therefore risk ruining the performance in some cases. | ||||
|  | ||||
| With these changes, debug performance should increase enough in most cases. If | ||||
| you want something more, you can also switch to an optimization level `O0` or | ||||
| preferably `O1`. | ||||
|  | ||||
| ## How can I represent hierarchies with my components? | ||||
|  | ||||
| This is one of the first questions that anyone makes when starting to work with | ||||
| the entity-component-system architectural pattern.<br/> | ||||
| There are several approaches to the problem and the best one depends mainly on | ||||
| the real problem one is facing. In all cases, how to do it doesn't strictly | ||||
| depend on the library in use, but the latter certainly allows or not different | ||||
| techniques depending on how the data are laid out. | ||||
|  | ||||
| I tried to describe some of the approaches that fit well with the model of | ||||
| `EnTT`. [This](https://skypjack.github.io/2019-06-25-ecs-baf-part-4/) is the | ||||
| first post of a series that tries to _explore_ the problem. More will probably | ||||
| come in future.<br/> | ||||
| In addition, `EnTT` also offers the possibility to create stable storage types | ||||
| and therefore have pointer stability for one, all or some components. This is by | ||||
| far the most convenient solution when it comes to creating hierarchies and | ||||
| whatnot. See the documentation for the ECS part of the library and in particular | ||||
| what concerns the `component_traits` class for further details. | ||||
|  | ||||
| ## Custom entity identifiers: yay or nay? | ||||
|  | ||||
| Custom entity identifiers are definitely a good idea in two cases at least: | ||||
|  | ||||
| * If `std::uint32_t` isn't large enough for your purposes, since this is the | ||||
|   underlying type of `entt::entity`. | ||||
|  | ||||
| * If you want to avoid conflicts when using multiple registries. | ||||
|  | ||||
| Identifiers can be defined through enum classes and class types that define an | ||||
| `entity_type` member of type `std::uint32_t` or `std::uint64_t`.<br/> | ||||
| In fact, this is a definition equivalent to that of `entt::entity`: | ||||
|  | ||||
| ```cpp | ||||
| enum class entity: std::uint32_t {}; | ||||
| ``` | ||||
|  | ||||
| There is no limit to the number of identifiers that can be defined. | ||||
|  | ||||
| ## Warning C4307: integral constant overflow | ||||
|  | ||||
| According to [this](https://github.com/skypjack/entt/issues/121) issue, using a | ||||
| hashed string under VS (toolset v141) could generate a warning.<br/> | ||||
| First of all, I want to reassure you: it's expected and harmless. However, it | ||||
| can be annoying. | ||||
|  | ||||
| To suppress it and if you don't want to suppress all the other warnings as well, | ||||
| here is a workaround in the form of a macro: | ||||
|  | ||||
| ```cpp | ||||
| #if defined(_MSC_VER) | ||||
| #define HS(str) __pragma(warning(suppress:4307)) entt::hashed_string{str} | ||||
| #else | ||||
| #define HS(str) entt::hashed_string{str} | ||||
| #endif | ||||
| ``` | ||||
|  | ||||
| With an example of use included: | ||||
|  | ||||
| ```cpp | ||||
| constexpr auto identifier = HS("my/resource/identifier"); | ||||
| ``` | ||||
|  | ||||
| Thanks to [huwpascoe](https://github.com/huwpascoe) for the courtesy. | ||||
|  | ||||
| ## Warning C4003: the min, the max and the macro | ||||
|  | ||||
| On Windows, a header file defines two macros `min` and `max` which may result in | ||||
| conflicts with their counterparts in the standard library and therefore in | ||||
| errors during compilation. | ||||
|  | ||||
| It's a pretty big problem but fortunately it's not a problem of `EnTT` and there | ||||
| is a fairly simple solution to it.<br/> | ||||
| It consists in defining the `NOMINMAX` macro before including any other header | ||||
| so as to get rid of the extra definitions: | ||||
|  | ||||
| ```cpp | ||||
| #define NOMINMAX | ||||
| ``` | ||||
|  | ||||
| Please refer to [this](https://github.com/skypjack/entt/issues/96) issue for | ||||
| more details. | ||||
|  | ||||
| ## The standard and the non-copyable types | ||||
|  | ||||
| `EnTT` uses internally the trait `std::is_copy_constructible_v` to check if a | ||||
| component is actually copyable. However, this trait doesn't really check whether | ||||
| a type is actually copyable. Instead, it just checks that a suitable copy | ||||
| constructor and copy operator exist.<br/> | ||||
| This can lead to surprising results due to some idiosyncrasies of the standard. | ||||
|  | ||||
| For example, `std::vector` defines a copy constructor that is conditionally | ||||
| enabled depending on whether the value type is copyable or not. As a result, | ||||
| `std::is_copy_constructible_v` returns true for the following specialization: | ||||
|  | ||||
| ```cpp | ||||
| struct type { | ||||
|     std::vector<std::unique_ptr<action>> vec; | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| However, the copy constructor is effectively disabled upon specialization. | ||||
| Therefore, trying to assign an instance of this type to an entity may trigger a | ||||
| compilation error.<br/> | ||||
| As a workaround, users can mark the type explicitly as non-copyable. This also | ||||
| suppresses the implicit generation of the move constructor and operator, which | ||||
| will therefore have to be defaulted accordingly: | ||||
|  | ||||
| ```cpp | ||||
| struct type { | ||||
|     type(const type &) = delete; | ||||
|     type(type &&) = default; | ||||
|  | ||||
|     type & operator=(const type &) = delete; | ||||
|     type & operator=(type &&) = default; | ||||
|  | ||||
|     std::vector<std::unique_ptr<action>> vec; | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| Note that aggregate initialization is also disabled as a consequence.<br/> | ||||
| Fortunately, this type of trick is quite rare. The bad news is that there is no | ||||
| way to deal with it at the library level, this being due to the design of the | ||||
| language. On the other hand, the fact that the language itself also offers a way | ||||
| to mitigate the problem makes it manageable. | ||||
|  | ||||
| ## Which functions trigger which signals | ||||
|  | ||||
| The `registry` class offers three signals that are emitted following specific | ||||
| operations. Maybe not everyone knows what these operations are, though.<br/> | ||||
| If this isn't clear, below you can find a _vademecum_ for this purpose: | ||||
|  | ||||
| * `on_created` is invoked when a component is first added (neither modified nor  | ||||
|   replaced) to an entity. | ||||
|  | ||||
| * `on_update` is called whenever an existing component is modified or replaced. | ||||
|  | ||||
| * `on_destroyed` is called when a component is explicitly or implicitly removed  | ||||
|   from an entity. | ||||
|  | ||||
| Among the most controversial functions can be found `emplace_or_replace` and | ||||
| `destroy`. However, following the above rules, it's quite simple to know what  | ||||
| will happen.<br/> | ||||
| In the first case, `on_created` is invoked if the entity has not the component, | ||||
| otherwise the latter is replaced and therefore `on_update` is triggered. As for | ||||
| the second case, components are removed from their entities and thus freed when | ||||
| they are recycled. It means that `on_destroyed` is triggered for every component  | ||||
| owned by the entity that is destroyed. | ||||
							
								
								
									
										299
									
								
								external/entt/entt/docs/md/graph.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								external/entt/entt/docs/md/graph.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,299 @@ | ||||
| # Crash Course: graph | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
| * [Data structures](#data-structures) | ||||
|   * [Adjacency matrix](#adjacency-matrix) | ||||
|   * [Graphviz dot language](#graphviz-dot-language) | ||||
| * [Flow builder](#flow-builder) | ||||
|   * [Tasks and resources](#tasks-and-resources) | ||||
|   * [Fake resources and order of execution](#fake-resources-and-order-of-execution) | ||||
|   * [Sync points](#sync-points) | ||||
|   * [Execution graph](#execution-graph) | ||||
|  | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| `EnTT` doesn't aim to offer everything one needs to work with graphs. Therefore, | ||||
| anyone looking for this in the _graph_ submodule will be disappointed.<br/> | ||||
| Quite the opposite is true. This submodule is minimal and contains only the data | ||||
| structures and algorithms strictly necessary for the development of some tools | ||||
| such as the _flow builder_. | ||||
|  | ||||
| # Data structures | ||||
|  | ||||
| As anticipated in the introduction, the aim isn't to offer all possible data | ||||
| structures suitable for representing and working with graphs. Many will likely | ||||
| be added or refined over time, however I want to discourage anyone expecting | ||||
| tight scheduling on the subject.<br/> | ||||
| The data structures presented in this section are mainly useful for the | ||||
| development and support of some tools which are also part of the same submodule. | ||||
|  | ||||
| ## Adjacency matrix | ||||
|  | ||||
| The adjacency matrix is designed to represent either a directed or an undirected | ||||
| graph: | ||||
|  | ||||
| ```cpp | ||||
| entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{}; | ||||
| ``` | ||||
|  | ||||
| The `directed_tag` type _creates_ the graph as directed. There is also an | ||||
| `undirected_tag` counterpart which creates it as undirected.<br/> | ||||
| The interface deviates slightly from the typical double indexing of C and offers | ||||
| an API that is perhaps more familiar to a C++ programmer. Therefore, the access | ||||
| and modification of an element will take place via the `contains`, `insert` and | ||||
| `erase` functions rather than a double call to an `operator[]`: | ||||
|  | ||||
| ```cpp | ||||
| if(adjacency_matrix.contains(0u, 1u)) { | ||||
|     adjacency_matrix.erase(0u, 1u); | ||||
| } else { | ||||
|     adjacency_matrix.insert(0u, 1u); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Both `insert` and` erase` are idempotent functions which have no effect if the | ||||
| element already exists or has already been deleted.<br/> | ||||
| The first one returns an `std::pair` containing the iterator to the element and | ||||
| a boolean value indicating whether the element has been inserted or was already | ||||
| present. The second one instead returns the number of deleted elements (0 or 1). | ||||
|  | ||||
| An adjacency matrix must be initialized with the number of elements (vertices) | ||||
| when constructing it but can also be resized later using the `resize` function: | ||||
|  | ||||
| ```cpp | ||||
| entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u}; | ||||
| ``` | ||||
|  | ||||
| To visit all vertices, the class offers a function named `vertices` that returns | ||||
| an iterable object suitable for the purpose: | ||||
|  | ||||
| ```cpp | ||||
| for(auto &&vertex: adjacency_matrix.vertices()) { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Note that the same result can be obtained with the following snippet, since the | ||||
| vertices are unsigned integral values: | ||||
|  | ||||
| ```cpp | ||||
| for(auto last = adjacency_matrix.size(), pos = {}; pos < last; ++pos) { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| As for visiting the edges, a few functions are available.<br/> | ||||
| When the purpose is to visit all the edges of a given adjacency matrix, the | ||||
| `edges` function returns an iterable object that can be used to get them as | ||||
| pairs of vertices: | ||||
|  | ||||
| ```cpp | ||||
| for(auto [lhs, rhs]: adjacency_matrix.edges()) { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| On the other hand, if the goal is to visit all the in- or out-edges of a given | ||||
| vertex, the `in_edges` and `out_edges` functions are meant for that: | ||||
|  | ||||
| ```cpp | ||||
| for(auto [lhs, rhs]: adjacency_matrix.out_edges(3u)) { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| As might be expected, these functions expect the vertex to visit (that is, to | ||||
| return the in- or out-edges for) as an argument.<br/> | ||||
| Finally, the adjacency matrix is an allocator-aware container and offers most of | ||||
| the functionality one would expect from this type of containers, such as `clear` | ||||
| or 'get_allocator` and so on. | ||||
|  | ||||
| ## Graphviz dot language | ||||
|  | ||||
| As it's one of the most popular formats, the library offers minimal support for | ||||
| converting a graph to a Graphviz dot snippet.<br/> | ||||
| The simplest way is to pass both an output stream and a graph to the `dot` | ||||
| function: | ||||
|  | ||||
| ```cpp | ||||
| std::ostringstream output{}; | ||||
| entt::dot(output, adjacency_matrix); | ||||
| ``` | ||||
|  | ||||
| However, there is also the option of providing a callback to which the vertices | ||||
| are passed and which can be used to add (`dot`) properties to the output from | ||||
| time to time: | ||||
|  | ||||
| ```cpp | ||||
| std::ostringstream output{}; | ||||
| entt::dot(output, adjacency_matrix, [](auto &output, auto vertex) { | ||||
|     out << "label=\"v\"" << vertex << ",shape=\"box\""; | ||||
| }); | ||||
| ``` | ||||
|  | ||||
| This second mode is particularly convenient when the user wants to associate | ||||
| data managed externally to the graph being converted. | ||||
|  | ||||
| # Flow builder | ||||
|  | ||||
| A flow builder is used to create execution graphs from tasks and resources.<br/> | ||||
| The implementation is as generic as possible and doesn't bind to any other part | ||||
| of the library. | ||||
|  | ||||
| This class is designed as a sort of _state machine_ to which a specific task is | ||||
| attached for which the resources accessed in read-only or read-write mode are | ||||
| specified.<br/> | ||||
| Most of the functions in the API also return the flow builder itself, according | ||||
| to what is the common sense API when it comes to builder classes. | ||||
|  | ||||
| Once all tasks have been registered and resources assigned to them, an execution | ||||
| graph in the form of an adjacency matrix is returned to the user.<br/> | ||||
| This graph contains all the tasks assigned to the flow builder in the form of | ||||
| _vertices_. The _vertex_ itself can be used as an index to get the identifier | ||||
| passed during registration. | ||||
|  | ||||
| ## Tasks and resources | ||||
|  | ||||
| Although these terms are used extensively in the documentation, the flow builder | ||||
| has no real concept of tasks and resources.<br/> | ||||
| This class works mainly with _identifiers_, that is, values of type `id_type`. | ||||
| That is, both tasks and resources are identified by integral values.<br/> | ||||
| This allows not to couple the class itself to the rest of the library or to any | ||||
| particular data structure. On the other hand, it requires the user to keep track | ||||
| of the association between identifiers and operations or actual data. | ||||
|  | ||||
| Once a flow builder has been created (which requires no constructor arguments), | ||||
| the first thing to do is to bind a task. This will indicate to the builder who | ||||
| intends to consume the resources that will be specified immediately after: | ||||
|  | ||||
| ```cpp | ||||
| entt::flow builder{}; | ||||
| builder.bind("task_1"_hs); | ||||
| ``` | ||||
|  | ||||
| Note that the example uses the `EnTT` hashed string to generate an identifier | ||||
| for the task.<br/> | ||||
| Indeed, the use of `id_type` as an identifier type is not by accident. In fact, | ||||
| it matches well with the internal hashed string class. Moreover, it's also the | ||||
| same type returned by the hash function of the internal RTTI system, in case the | ||||
| user wants to rely on that.<br/> | ||||
| However, being an integral value, it leaves the user full freedom to rely on his | ||||
| own tools if he deems it necessary. | ||||
|  | ||||
| Once a task has been associated with the flow builder, it can be assigned | ||||
| read-only or read-write resources, as appropriate: | ||||
|  | ||||
| ```cpp | ||||
| builder | ||||
|     .bind("task_1"_hs) | ||||
|         .ro("resource_1"_hs) | ||||
|         .ro("resource_2"_hs) | ||||
|     .bind("task_2"_hs) | ||||
|         .rw("resource_2"_hs) | ||||
| ``` | ||||
|  | ||||
| As mentioned, many functions return the builder itself and it's therefore easy | ||||
| to concatenate the different calls.<br/> | ||||
| Also in the case of resources, these are identified by numeric values of type | ||||
| `id_type`. As above, the choice is not entirely random. This goes well with the | ||||
| tools offered by the library while leaving room for maximum flexibility. | ||||
|  | ||||
| Finally, both the `ro` and` rw` functions also offer an overload that accepts a | ||||
| pair of iterators, so that one can pass a range of resources in one go. | ||||
|  | ||||
| ## Fake resources and order of execution | ||||
|  | ||||
| The flow builder doesn't offer the ability to specify when a task should execute | ||||
| before or after another task.<br/> | ||||
| In fact, the order of _registration_ on the resources also determines the order | ||||
| in which the tasks are processed during the generation of the execution graph. | ||||
|  | ||||
| However, there is a way to force the execution order of two processes.<br/> | ||||
| Briefly, since accessing a resource in opposite modes requires sequential rather | ||||
| than parallel scheduling, it's possible to make use of fake resources to force | ||||
| the order execution: | ||||
|  | ||||
| ```cpp | ||||
| builder | ||||
|     .bind("task_1"_hs) | ||||
|         .ro("resource_1"_hs) | ||||
|         .rw("fake"_hs) | ||||
|     .bind("task_2"_hs) | ||||
|         .ro("resource_2"_hs) | ||||
|         .ro("fake"_hs) | ||||
|     .bind("task_3"_hs) | ||||
|         .ro("resource_2"_hs) | ||||
|         .ro("fake"_hs) | ||||
| ``` | ||||
|  | ||||
| This snippet forces the execution of `task_2` and `task_3` **after** `task_1`. | ||||
| This is due to the fact that the latter sets a read-write requirement on a fake | ||||
| resource that the other tasks also want to access in read-only mode.<br/> | ||||
| Similarly, it's possible to force a task to run after a certain group: | ||||
|  | ||||
| ```cpp | ||||
| builder | ||||
|     .bind("task_1"_hs) | ||||
|         .ro("resource_1"_hs) | ||||
|         .ro("fake"_hs) | ||||
|     .bind("task_2"_hs) | ||||
|         .ro("resource_1"_hs) | ||||
|         .ro("fake"_hs) | ||||
|     .bind("task_3"_hs) | ||||
|         .ro("resource_2"_hs) | ||||
|         .rw("fake"_hs) | ||||
| ``` | ||||
|  | ||||
| In this case, since there are a number of processes that want to read a specific | ||||
| resource, they will do so in parallel by forcing `task_3` to run after all the | ||||
| others tasks. | ||||
|  | ||||
| ## Sync points | ||||
|  | ||||
| Sometimes it's useful to assign the role of _sync point_ to a node.<br/> | ||||
| Whether it accesses new resources or is simply a watershed, the procedure for | ||||
| assigning this role to a vertex is always the same: first it's tied to the flow | ||||
| builder, then the `sync` function is invoked: | ||||
|  | ||||
| ```cpp | ||||
| builder.bind("sync_point"_hs).sync(); | ||||
| ``` | ||||
|  | ||||
| The choice to assign an _identity_ to this type of nodes lies in the fact that, | ||||
| more often than not, they also perform operations on resources.<br/> | ||||
| If this isn't the case, it will still be possible to create no-op vertices to | ||||
| which empty tasks are assigned. | ||||
|  | ||||
| ## Execution graph | ||||
|  | ||||
| Once both the resources and their consumers have been properly registered, the | ||||
| purpose of this tool is to generate an execution graph that takes into account | ||||
| all specified constraints to return the best scheduling for the vertices: | ||||
|  | ||||
| ```cpp | ||||
| entt::adjacency_matrix<entt::directed_tag> graph = builder.graph(); | ||||
| ``` | ||||
|  | ||||
| The search for the main vertices, that is those without in-edges, is usually the | ||||
| first thing required: | ||||
|  | ||||
| ```cpp | ||||
| for(auto &&vertex: graph) { | ||||
|     if(auto in_edges = graph.in_edges(vertex); in_edges.begin() == in_edges.end()) { | ||||
|         // ... | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Starting from them, using the other functions appropriately (such as `out_edges` | ||||
| to retrieve the children of a given task or `edges` to access their identifiers) | ||||
| it will be possible to instantiate an execution graph. | ||||
							
								
								
									
										99
									
								
								external/entt/entt/docs/md/lib.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								external/entt/entt/docs/md/lib.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| # Push EnTT across boundaries | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Working across boundaries](#working-across-boundaries) | ||||
|   * [Smooth until proven otherwise](#smooth-until-proven-otherwise) | ||||
|   * [Meta context](#meta-context) | ||||
|   * [Memory management](#memory-management) | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Working across boundaries | ||||
|  | ||||
| `EnTT` has historically had a limit when used across boundaries on Windows in | ||||
| general and on GNU/Linux when default visibility was set to hidden. The | ||||
| limitation was mainly due to a custom utility used to assign unique, sequential | ||||
| identifiers with different types.<br/> | ||||
| Fortunately, nowadays using `EnTT` across boundaries is much easier. | ||||
|  | ||||
| ## Smooth until proven otherwise | ||||
|  | ||||
| Many classes in `EnTT` make extensive use of type erasure for their purposes. | ||||
| This isn't a problem on itself (in fact, it's the basis of an API so convenient | ||||
| to use). However, a way is needed to recognize the objects whose type has been | ||||
| erased on the other side of a boundary.<br/> | ||||
| The `type_hash` class template is how identifiers are generated and thus made | ||||
| available to the rest of the library. In general, this class doesn't arouse much | ||||
| interest. The only exception is when a conflict between identifiers occurs | ||||
| (definitely uncommon though) or when the default solution proposed by `EnTT` | ||||
| isn't suitable for the user's purposes.<br/> | ||||
| The section dedicated to `type_info` contains all the details to get around the | ||||
| issue in a concise and elegant way. Please refer to the specific documentation. | ||||
|  | ||||
| When working with linked libraries, compile definitions `ENTT_API_EXPORT` and | ||||
| `ENTT_API_IMPORT` can be used where there is a need to import or export symbols, | ||||
| so as to make everything work nicely across boundaries.<br/> | ||||
| On the other hand, everything should run smoothly when working with plugins or | ||||
| shared libraries that don't export any symbols. | ||||
|  | ||||
| For anyone who needs more details, the test suite contains multiple examples | ||||
| covering the most common cases (see the `lib` directory for all details).<br/> | ||||
| It goes without saying that it's impossible to cover **all** possible cases. | ||||
| However, what is offered should hopefully serve as a basis for all of them. | ||||
|  | ||||
| ## Meta context | ||||
|  | ||||
| The runtime reflection system deserves a special mention when it comes to using | ||||
| it across boundaries.<br/> | ||||
| Since it's linked already to a static context to which the elements are attached | ||||
| and different contexts don't relate to each other, they must be _shared_ to | ||||
| allow the use of meta types across boundaries. | ||||
|  | ||||
| Fortunately, sharing a context is also trivial to do. First of all, the local | ||||
| one is acquired in the main space: | ||||
|  | ||||
| ```cpp | ||||
| auto handle = entt::locator<entt::meta_ctx>::handle(); | ||||
| ``` | ||||
|  | ||||
| Then, it's passed to the receiving space that sets it as its default context, | ||||
| thus discarding or storing aside the local one: | ||||
|  | ||||
| ```cpp | ||||
| entt::locator<entt::meta_ctx>::reset(handle); | ||||
| ``` | ||||
|  | ||||
| From now on, both spaces refer to the same context and on it are attached all | ||||
| new meta types, no matter where they are created.<br/> | ||||
| Note that resetting the main context doesn't also propagate changes across | ||||
| boundaries. In other words, resetting a context results in the decoupling of the | ||||
| two sides and therefore a divergence in the contents. | ||||
|  | ||||
| ## Memory Management | ||||
|  | ||||
| There is another subtle problem due to memory management that can lead to | ||||
| headaches.<br/> | ||||
| It can occur where there are pools of objects (such as components or events) | ||||
| dynamically created on demand. This is usually not a problem when working with | ||||
| linked libraries that rely on the same dynamic runtime. However, it can occur in | ||||
| the case of plugins or statically linked runtimes. | ||||
|  | ||||
| As an example, imagine creating an instance of `registry` in the main executable | ||||
| and sharing it with a plugin. If the latter starts working with a component that | ||||
| is unknown to the former, a dedicated pool is created within the registry on | ||||
| first use.<br/> | ||||
| As one can guess, this pool is instantiated on a different side of the boundary | ||||
| from the `registry`. Therefore, the instance is now managing memory from | ||||
| different spaces and this can quickly lead to crashes if not properly addressed. | ||||
|  | ||||
| To overcome the risk, it's recommended to use well-defined interfaces that make | ||||
| fundamental types pass through the boundaries, isolating the instances of the | ||||
| `EnTT` classes from time to time and as appropriate.<br/> | ||||
| Refer to the test suite for some examples, read the documentation available | ||||
| online about this type of issues or consult someone who has already had such | ||||
| experiences to avoid problems. | ||||
							
								
								
									
										266
									
								
								external/entt/entt/docs/md/links.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								external/entt/entt/docs/md/links.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,266 @@ | ||||
| # EnTT in Action | ||||
|  | ||||
| `EnTT` is widely used in private and commercial applications. I cannot even | ||||
| mention most of them because of some signatures I put on some documents time | ||||
| ago. Fortunately, there are also people who took the time to implement open | ||||
| source projects based on `EnTT` and didn't hold back when it came to documenting | ||||
| them. | ||||
|  | ||||
| Below an incomplete list of games, applications and articles that can be used as | ||||
| a reference. Where I put the word _apparently_ means that the use of `EnTT` is | ||||
| documented but the authors didn't make explicit announcements or contacted me | ||||
| directly. | ||||
|  | ||||
| I hope this list can grow much more in the future: | ||||
|  | ||||
| * Games: | ||||
|   * [Minecraft](https://minecraft.net/en-us/attribution/) by | ||||
|     [Mojang](https://mojang.com/): of course, **that** Minecraft, see the | ||||
|     open source attributions page for more details. | ||||
|   * [Minecraft Earth](https://www.minecraft.net/en-us/about-earth) by | ||||
|     [Mojang](https://mojang.com/): an augmented reality game for mobile, that | ||||
|     lets users bring Minecraft into the real world. | ||||
|   * [Ember Sword](https://embersword.com/): a modern Free-to-Play MMORPG with a | ||||
|     player-driven economy, a classless combat system, and scarce, tradable | ||||
|     cosmetic collectibles. | ||||
|   * Apparently [Diablo II: Resurrected](https://diablo2.blizzard.com/) by | ||||
|     [Blizzard](https://www.blizzard.com/): monsters, heroes, items, spells, all | ||||
|     resurrected. Thanks unknown insider. | ||||
|   * [Apparently](https://www.youtube.com/watch?v=P8xvOA3ikrQ&t=1105s) | ||||
|     [Call of Duty: Vanguard](https://www.callofduty.com/vanguard) by | ||||
|     [Sledgehammer Games](https://www.sledgehammergames.com/): I can neither | ||||
|     confirm nor deny but there is a license I know in the credits. | ||||
|   * Apparently [D&D Dark Alliance](https://darkalliance.wizards.com) by | ||||
|     [Wizards of the Coast](https://company.wizards.com): your party, their | ||||
|     funeral. | ||||
|   * [TiltedOnline](https://github.com/tiltedphoques/TiltedOnline) by | ||||
|     [Tilted Phoques](https://github.com/tiltedphoques): Skyrim and Fallout 4 mod | ||||
|     to play online. | ||||
|   * [Antkeeper](https://github.com/antkeeper/antkeeper-source): an ant colony | ||||
|     simulation [game](https://antkeeper.com/). | ||||
|   * [Openblack](https://github.com/openblack/openblack): open source | ||||
|     reimplementation of the game _Black & White_ (2001). | ||||
|   * [Land of the Rair](https://github.com/LandOfTheRair/core2): the new backend | ||||
|     of [a retro-style MUD](https://rair.land/) for the new age. | ||||
|   * [Face Smash](https://play.google.com/store/apps/details?id=com.gamee.facesmash): | ||||
|     a game to play with your face. | ||||
|   * [EnTT Pacman](https://github.com/Kerndog73/EnTT-Pacman): an example of how | ||||
|     to make Pacman with `EnTT`. | ||||
|   * [Wacman](https://github.com/carlfindahl/wacman): a pacman clone with OpenGL. | ||||
|   * [Classic Tower Defence](https://github.com/kerndog73/Classic-Tower-Defence): | ||||
|     a tiny little tower defence game featuring a homemade font. | ||||
|     [Check it out](https://indi-kernick.itch.io/classic-tower-defence). | ||||
|   * [The Machine](https://github.com/Kerndog73/The-Machine): a box pushing | ||||
|     puzzler with logic gates and other cool stuff. | ||||
|     [Check it out](https://indi-kernick.itch.io/the-machine-web-version). | ||||
|   * [EnTTPong](https://github.com/DomRe/EnttPong): a basic game made to showcase | ||||
|     different parts of `EnTT` and C++17. | ||||
|   * [Randballs](https://github.com/gale93/randballs): simple `SFML` and `EnTT` | ||||
|     playground. | ||||
|   * [EnTT Tower Defense](https://github.com/Daivuk/tddod): a data oriented tower | ||||
|     defense example. | ||||
|   * [EnTT Breakout](https://github.com/vblanco20-1/entt-breakout): simple | ||||
|     example of a breakout game, using `SDL` and `EnTT`. | ||||
|   * [Arcade puzzle game with EnTT](https://github.com/MasonRG/ArcadePuzzleGame): | ||||
|     arcade puzzle game made in C++ using the `SDL2` and `EnTT` libraries. | ||||
|   * [Snake with EnTT](https://github.com/MasonRG/SnakeGame): simple snake game | ||||
|     made in C++ with the `SDL2` and `EnTT` libraries. | ||||
|   * [Mirrors lasers and robots](https://github.com/guillaume-haerinck/imac-tower-defense): | ||||
|     a small tower defense game based on mirror orientation. | ||||
|   * [PopHead](https://github.com/SPC-Some-Polish-Coders/PopHead/): 2D, Zombie, | ||||
|     RPG game made from scratch in C++. | ||||
|   * [Robotligan](https://github.com/Trisslotten/robotligan): multiplayer | ||||
|     football game. | ||||
|   * [DungeonSlayer](https://github.com/alohaeee/DungeonSlayer): 2D game made | ||||
|     from scratch in C++. | ||||
|   * [3DGame](https://github.com/kwarkGorny/3DGame): 2.5D top-down space shooter. | ||||
|   * [Pulcher](https://github.com/AODQ/pulcher): 2D cross-platform game inspired | ||||
|     by Quake. | ||||
|   * [Destroid](https://github.com/tyrannicaltoucan/destroid): _one-bazillionth_ | ||||
|     arcade game about shooting dirty rocks in space, inspired by Asteroids. | ||||
|   * [Wanderer](https://github.com/albin-johansson/wanderer): a 2D exploration | ||||
|     based indie game. | ||||
|   * [Spelunky<EFBFBD> Classic remake](https://github.com/dbeef/spelunky-psp): a truly | ||||
|     multiplatform experience with a rewrite from scratch. | ||||
|   * [CubbyTower](https://github.com/utilForever/CubbyTower): a simple tower | ||||
|     defense game using C++ with Entity Component System (ECS). | ||||
|   * [Runeterra](https://github.com/utilForever/Runeterra): Legends of Runeterra | ||||
|     simulator using C++ with some reinforcement learning. | ||||
|   * [Black Sun](https://store.steampowered.com/app/1670930/Black_Sun/): fly your | ||||
|     space ship through a large 2D open world. | ||||
|   * [PokeMaster](https://github.com/utilForever/PokeMaster): Pokemon Battle | ||||
|     simulator using C++ with some reinforcement learning. | ||||
|   * [HomeHearth](https://youtu.be/GrEWl8npL9Y): choose your hero, protect the | ||||
|     town, before it's too late. | ||||
|   * [City Builder Game](https://github.com/PhiGei2000/CityBuilderGame): a simple | ||||
|     city-building game using C++ and OpenGL. | ||||
|   * [BattleSub](https://github.com/bfeldpw/battlesub): two player 2D submarine | ||||
|     game with some fluid dynamics. | ||||
|   * [Crimson Rush](https://github.com/WilKam01/LuaCGame): a dungeon-crawler and | ||||
|     rougelike inspired game about exploring and surviving as long as possible. | ||||
|   * [Space Fight](https://github.com/cholushkin/SpaceFight): one screen | ||||
|     multi-player arcade shooter game prototype. | ||||
|   * [Confetti Party](https://github.com/hexerei/entt-confetti): C++ sample | ||||
|     application as a starting point using `EnTT` and `SDL2`. | ||||
|  | ||||
| * Engines and the like: | ||||
|   * [Aether Engine](https://hadean.com/spatial-simulation/) | ||||
|     [v1.1+](https://docs.hadean.com/v1.1/Licenses/) by | ||||
|     [Hadean](https://hadean.com/): a library designed for spatially partitioning | ||||
|     agent-based simulations. | ||||
|   * [Fling Engine](https://github.com/flingengine/FlingEngine): a Vulkan game | ||||
|     engine with a focus on data oriented design. | ||||
|   * [NovusCore](https://github.com/novuscore/NovusCore): a modern take on World | ||||
|     of Warcraft emulation. | ||||
|   * [Chrysalis](https://github.com/ivanhawkes/Chrysalis): action RPG SDK for | ||||
|     CRYENGINE games. | ||||
|   * [LM-Engine](https://github.com/Lawrencemm/LM-Engine): the Vim of game | ||||
|     engines. | ||||
|   * [Edyn](https://github.com/xissburg/edyn): a real-time physics engine | ||||
|     organized as an ECS. | ||||
|   * [MushMachine](https://github.com/MadeOfJelly/MushMachine): engine... | ||||
|     vrooooommm. | ||||
|   * [Antara Gaming SDK](https://github.com/KomodoPlatform/antara-gaming-sdk): | ||||
|     the Komodo Gaming Software Development Kit. | ||||
|   * [XVP](https://ravingbots.com/xvp-expansive-vehicle-physics-for-unreal-engine/): | ||||
|     [_eXpansive Vehicle Physics_](https://github.com/raving-bots/xvp/wiki/Plugin-integration-guide) | ||||
|     plugin for Unreal Engine. | ||||
|   * [Apparently](https://teamwisp.github.io/credits/) | ||||
|     [Wisp](https://teamwisp.github.io/product/) by | ||||
|     [Team Wisp](https://teamwisp.github.io/): an advanced real-time ray tracing | ||||
|     renderer built for the demands of video game artists. | ||||
|   * [shiva](https://github.com/Milerius/shiva): modern C++ engine with | ||||
|     modularity. | ||||
|   * [ImGui/EnTT editor](https://github.com/Green-Sky/imgui_entt_entity_editor): | ||||
|     a drop-in, single-file entity editor for `EnTT` that uses `ImGui` as | ||||
|     graphical backend (with | ||||
|     [demo code](https://github.com/Green-Sky/imgui_entt_entity_editor_demo)). | ||||
|   * [SgOgl](https://github.com/stwe/SgOgl): a game engine library for OpenGL | ||||
|     developed for educational purposes. | ||||
|   * [Lumos](https://github.com/jmorton06/Lumos): game engine written in C++ | ||||
|     using OpenGL and Vulkan. | ||||
|   * [Silvanus](https://github.com/hobbyistmaker/silvanus): Silvanus Fusion 360 | ||||
|     Box Generator. | ||||
|   * [Lina Engine](https://github.com/inanevin/LinaEngine): an open-source, | ||||
|     modular, tiny and fast C++ game engine, aimed to develop 3D desktop games. | ||||
|   * [Spike](https://github.com/FahimFuad/Spike): a powerful game engine which | ||||
|     can run on a toaster. | ||||
|   * [Helena Framework](https://github.com/NIKEA-SOFT/HelenaFramework): a modern | ||||
|     framework in C++17 for backend development. | ||||
|   * [Unity/EnTT](https://github.com/TongTungGiang/unity-entt): tech demo of a | ||||
|     native simulation layer using `EnTT` and `Unity` as a rendering engine. | ||||
|   * [OverEngine](https://github.com/OverShifted/OverEngine): an over-engineered | ||||
|     game engine. | ||||
|   * [Electro](https://github.com/Electro-Technologies/Electro): high performance | ||||
|     3D game engine with a high emphasis on rendering. | ||||
|   * [Kawaii](https://github.com/Mathieu-Lala/Kawaii_Engine): a modern data | ||||
|     oriented game engine. | ||||
|   * [Becketron](https://github.com/Doctor-Foxling/Becketron): a game engine | ||||
|     written mostly in C++. | ||||
|   * [Spatial Engine](https://github.com/luizgabriel/Spatial.Engine): a | ||||
|     cross-platform engine created on top of google's filament rendering engine. | ||||
|   * [Kaguya](https://github.com/KaiH0717/Kaguya): D3D12 Rendering Engine. | ||||
|   * [OpenAWE](https://github.com/OpenAWE-Project/OpenAWE): open implementation | ||||
|     of the Alan Wake Engine. | ||||
|   * [Nazara Engine](https://github.com/DigitalPulseSoftware/NazaraEngine): fast, | ||||
|     cross-platform, object-oriented API to help in daily developer life. | ||||
|   * [Billy Engine](https://github.com/billy4479/BillyEngine): some kind of a 2D | ||||
|     engine based on `SDL2` and `EnTT`. | ||||
|   * [Ducktape](https://github.com/DucktapeEngine/Ducktape): an open source C++ | ||||
|     2D & 3D game engine that focuses on being fast and powerful. | ||||
|  | ||||
| * Articles, videos and blog posts: | ||||
|   * [Some posts](https://skypjack.github.io/tags/#entt) on my personal | ||||
|     [blog](https://skypjack.github.io/) are about `EnTT`, for those who want to | ||||
|     know **more** on this project. | ||||
|   * [Game Engine series](https://www.youtube.com/c/TheChernoProject/videos) by | ||||
|     [The Cherno](https://github.com/TheCherno) (not only about `EnTT` but also | ||||
|     on the use of an ECS in general): | ||||
|     - [Intro to EnTT](https://www.youtube.com/watch?v=D4hz0wEB978). | ||||
|     - [Entities and Components](https://www.youtube.com/watch?v=-B1iu4QJTUc). | ||||
|     - [The ENTITY Class](https://www.youtube.com/watch?v=GfSzeAcsBb0). | ||||
|     - [Camera Systems](https://www.youtube.com/watch?v=ubZn7BlrnTU). | ||||
|     - [Scene Camera](https://www.youtube.com/watch?v=UKVFRRufKzo). | ||||
|     - [Native Scripting](https://www.youtube.com/watch?v=iIUhg88MK5M). | ||||
|     - [Native Scripting (now with virtual functions!)](https://www.youtube.com/watch?v=1cHEcrIn8IQ). | ||||
|     - [Scene Hierarchy Panel](https://www.youtube.com/watch?v=wziDnE8guvI). | ||||
|     - [Properties Panel](https://www.youtube.com/watch?v=NBpB0qscF3E). | ||||
|     - [Camera Component UI](https://www.youtube.com/watch?v=RIMt_6agUiU). | ||||
|     - [Drawing Component UI](https://www.youtube.com/watch?v=u3yq8s3KuSE). | ||||
|     - [Transform Component UI](https://www.youtube.com/watch?v=8JqcXYbzPJc). | ||||
|     - [Adding/Removing Entities and Components UI](https://www.youtube.com/watch?v=PsyGmsIgp9M). | ||||
|     - [Saving and Loading Scenes](https://www.youtube.com/watch?v=IEiOP7Y-Mbc). | ||||
|     - ... And so on. | ||||
|       [Check out](https://www.youtube.com/channel/UCQ-W1KE9EYfdxhL6S4twUNw) the | ||||
|       _Game Engine Series_ by The Cherno for more videos. | ||||
|   * [Space Battle: Huge edition](http://victor.madtriangles.com/code%20experiment/2018/06/11/post-ecs-battle-huge.html): | ||||
|     huge space battle built entirely from scratch. | ||||
|   * [Space Battle](https://github.com/vblanco20-1/ECS_SpaceBattle): huge space | ||||
|     battle built on `UE4`. | ||||
|   * [Experimenting with ECS in UE4](http://victor.madtriangles.com/code%20experiment/2018/03/25/post-ue4-ecs-battle.html): | ||||
|     interesting article about `UE4` and `EnTT`. | ||||
|   * [Implementing ECS architecture in UE4](https://forums.unrealengine.com/development-discussion/c-gameplay-programming/1449913-implementing-ecs-architecture-in-ue4-giant-space-battle): | ||||
|     giant space battle. | ||||
|   * [Conan Adventures (SFML and EnTT in C++)](https://leinnan.github.io/blog/conan-adventuressfml-and-entt-in-c.html): | ||||
|     create projects in modern C++ using `SFML`, `EnTT`, `Conan` and `CMake`. | ||||
|   * [Adding EnTT ECS to Chrysalis](https://www.tauradius.com/post/adding-an-ecs-to-chrysalis/): | ||||
|     a blog entry (and its  | ||||
|     [follow-up](https://www.tauradius.com/post/chrysalis-update-2020-08-02/))  | ||||
|     about the integration of `EnTT` into `Chrysalis`, an action RPG SDK for | ||||
|     CRYENGINE games. | ||||
|   * [Creating Minecraft in One Week with C++ and Vulkan](https://vazgriz.com/189/creating-minecraft-in-one-week-with-c-and-vulkan/): | ||||
|     a crack at recreating Minecraft in one week using a custom C++ engine and | ||||
|     Vulkan ([code included](https://github.com/vazgriz/VoxelGame)). | ||||
|   * [Ability Creator](https://www.erichildebrand.net/blog/ability-creator-project-retrospect): | ||||
|     project retrospect by [Eric Hildebrand](https://www.erichildebrand.net/). | ||||
|   * [EnTT Entity Component System Gaming Library](https://gamefromscratch.com/entt-entity-component-system-gaming-library/): | ||||
|     `EnTT` on GameFromScratch.com. | ||||
|   * [Custom C++ server for UE5](https://youtu.be/fbXZVNCOvjM) optimized for | ||||
|     MMO(RPG)s and its [follow-up](https://youtu.be/yGlZeopx2hU) episode about | ||||
|     player bots and full external ECS: a series definitely worth looking at. | ||||
|  | ||||
| * Any Other Business: | ||||
|   * [ArcGIS Runtime SDKs](https://developers.arcgis.com/arcgis-runtime/) by | ||||
|     [Esri](https://www.esri.com/): they use `EnTT` for the internal ECS and the | ||||
|     cross platform C++ rendering engine. The SDKs are utilized by a lot of | ||||
|     enterprise custom apps, as well as by Esri for its own public applications | ||||
|     such as | ||||
|     [Explorer](https://play.google.com/store/apps/details?id=com.esri.explorer), | ||||
|     [Collector](https://play.google.com/store/apps/details?id=com.esri.arcgis.collector) | ||||
|     and | ||||
|     [Navigator](https://play.google.com/store/apps/details?id=com.esri.navigator). | ||||
|   * [FASTSUITE Edition 2](https://www.fastsuite.com/en_EN/fastsuite/fastsuite-edition-2.html) | ||||
|     by [Cenit](http://www.cenit.com/en_EN/about-us/overview.html): they use | ||||
|     `EnTT` to drive their simulation, that is, the communication between robot | ||||
|     controller emulator and renderer. | ||||
|   * [Ragdoll](https://ragdolldynamics.com/): real-time physics for Autodesk Maya | ||||
|     2020. | ||||
|   * [Project Lagrange](https://github.com/adobe/lagrange): a robust geometry | ||||
|     processing library by [Adobe](https://github.com/adobe). | ||||
|   * [AtomicDEX](https://github.com/KomodoPlatform/atomicDEX-Desktop): a secure | ||||
|     wallet and non-custodial decentralized exchange rolled into one application. | ||||
|   * [Apparently](https://www.linkedin.com/in/skypjack/) | ||||
|     [NIO](https://www.nio.io/): there was a collaboration to make some changes | ||||
|     to `EnTT`, at the time used for internal projects. | ||||
|   * [Apparently](https://www.linkedin.com/jobs/view/architekt-c%2B%2B-at-tieto-1219512333/) | ||||
|     [Tieto](https://www.tieto.com/): they published a job post where `EnTT` was | ||||
|     listed on their software stack. | ||||
|   * [Sequentity](https://github.com/alanjfs/sequentity): A MIDI-like | ||||
|     sequencer/tracker for C++ and `ImGui` (with `Magnum` and `EnTT`). | ||||
|   * [EnTT meets Sol2](https://github.com/skaarj1989/entt-meets-sol2): freely | ||||
|     available examples of how to combine `EnTT` and `Sol2`. | ||||
|   * [Godot meets EnTT](https://github.com/portaloffreedom/godot_entt_example/): | ||||
|     a simple example on how to use `EnTT` within | ||||
|     [`Godot`](https://godotengine.org/). | ||||
|   * [Godot and GameNetworkingSockets meet EnTT](https://github.com/portaloffreedom/godot_entt_net_example): | ||||
|     a simple example on how to use `EnTT` and | ||||
|     [`GameNetworkingSockets`](https://github.com/ValveSoftware/GameNetworkingSockets) | ||||
|     within [`Godot`](https://godotengine.org/). | ||||
|   * [MatchOneEntt](https://github.com/mhaemmerle/MatchOneEntt): port of | ||||
|     [Match One](https://github.com/sschmid/Match-One) for `Entitas-CSharp`. | ||||
|   * GitHub contains also | ||||
|     [many other examples](https://github.com/search?o=desc&q=%22skypjack%2Fentt%22&s=indexed&type=Code) | ||||
|     of use of `EnTT` from which to take inspiration if interested. | ||||
|  | ||||
| If you know of other resources out there that are about `EnTT`, feel free to | ||||
| open an issue or a PR and I'll be glad to add them to this page. | ||||
							
								
								
									
										88
									
								
								external/entt/entt/docs/md/locator.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								external/entt/entt/docs/md/locator.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| # Crash Course: service locator | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
| * [Service locator](#service-locator) | ||||
|   * [Opaque handles](#opaque-handles) | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| Usually, service locators are tightly bound to the services they expose and it's | ||||
| hard to define a general purpose solution.<br/> | ||||
| This tiny class tries to fill the gap and gets rid of the burden of defining a | ||||
| different specific locator for each application. | ||||
|  | ||||
| # Service locator | ||||
|  | ||||
| The service locator API tries to mimic that of `std::optional` and adds some | ||||
| extra functionalities on top of it such as allocator support.<br/> | ||||
| There are a couple of functions to set up a service, namely `emplace` and | ||||
| `allocate_emplace`: | ||||
|  | ||||
| ```cpp | ||||
| entt::locator<interface>::emplace<service>(argument); | ||||
| entt::locator<interface>::allocate_emplace<service>(allocator, argument); | ||||
| ``` | ||||
|  | ||||
| The difference is that the latter expects an allocator as the first argument and | ||||
| uses it to allocate the service itself.<br/> | ||||
| Once a service is set up, it's retrieved using the `value` function: | ||||
|  | ||||
| ```cpp | ||||
| interface &service = entt::locator<interface>::value(); | ||||
| ``` | ||||
|  | ||||
| Since the service may not be set (and therefore this function may result in an | ||||
| undefined behavior), the `has_value` and `value_or` functions are also available | ||||
| to test a service locator and to get a fallback service in case there is none: | ||||
|  | ||||
| ```cpp | ||||
| if(entt::locator<interface>::has_value()) { | ||||
|     // ... | ||||
| } | ||||
|  | ||||
| interface &service = entt::locator<interface>::value_or<fallback_impl>(argument); | ||||
| ``` | ||||
|  | ||||
| All arguments are used only if necessary, that is, if a service doesn't already | ||||
| exist and therefore the fallback service is constructed and returned. In all | ||||
| other cases, they are discarded.<br/> | ||||
| Finally, to reset a service, use the `reset` function. | ||||
|  | ||||
| ## Opaque handles | ||||
|  | ||||
| Sometimes it's useful to _transfer_ a copy of a service to another locator. For | ||||
| example, when working across boundaries it's common to _share_ a service with a | ||||
| dynamically loaded module.<br/> | ||||
| Options aren't much in this case. Among these is the possibility of _exporting_ | ||||
| services and assigning them to a different locator. | ||||
|  | ||||
| This is what the `handle` and `reset` functions are meant for.<br/> | ||||
| The former returns an opaque object useful for _exporting_ (or rather, obtaining | ||||
| a reference to) a service. The latter also accepts an optional argument to a | ||||
| handle which then allows users to reset a service by initializing it with an | ||||
| opaque handle: | ||||
|  | ||||
| ```cpp | ||||
| auto handle = entt::locator<interface>::handle(); | ||||
| entt::locator<interface>::reset(handle); | ||||
| ``` | ||||
|  | ||||
| It's worth noting that it's possible to get handles for uninitialized services | ||||
| and use them with other locators. Of course, all a user will get is to have an | ||||
| uninitialized service elsewhere as well. | ||||
|  | ||||
| Note that exporting a service allows users to _share_ the object currently set | ||||
| in a locator. Replacing it won't replace the element even where a service has | ||||
| been configured with a handle to the previous item.<br/> | ||||
| In other words, if an audio service is replaced with a null object to silence an | ||||
| application and the original service was shared, this operation won't propagate | ||||
| to the other locators. Therefore, a module that share the ownership of the | ||||
| original audio service is still able to emit sounds. | ||||
							
								
								
									
										1023
									
								
								external/entt/entt/docs/md/meta.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1023
									
								
								external/entt/entt/docs/md/meta.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										359
									
								
								external/entt/entt/docs/md/poly.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								external/entt/entt/docs/md/poly.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,359 @@ | ||||
| # Crash Course: poly | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
|   * [Other libraries](#other-libraries) | ||||
| * [Concept and implementation](#concept-and-implementation) | ||||
|   * [Deduced interface](#deduced-interface) | ||||
|   * [Defined interface](#defined-interface) | ||||
|   * [Fulfill a concept](#fulfill-a-concept) | ||||
| * [Inheritance](#inheritance) | ||||
| * [Static polymorphism in the wild](#static-polymorphism-in-the-wild) | ||||
| * [Storage size and alignment requirement](#storage-size-and-alignment-requirement) | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| Static polymorphism is a very powerful tool in C++, albeit sometimes cumbersome | ||||
| to obtain.<br/> | ||||
| This module aims to make it simple and easy to use. | ||||
|  | ||||
| The library allows to define _concepts_ as interfaces to fulfill with concrete | ||||
| classes without having to inherit from a common base.<br/> | ||||
| This is, among others, one of the advantages of static polymorphism in general | ||||
| and of a generic wrapper like that offered by the `poly` class template in | ||||
| particular.<br/> | ||||
| What users get is an object that can be passed around as such and not through a | ||||
| reference or a pointer, as happens when it comes to working with dynamic | ||||
| polymorphism. | ||||
|  | ||||
| Since the `poly` class template makes use of `entt::any` internally, it also | ||||
| supports most of its feature. Among the most important, the possibility to | ||||
| create aliases to existing and thus unmanaged objects. This allows users to | ||||
| exploit the static polymorphism while maintaining ownership of objects.<br/> | ||||
| Likewise, the `poly` class template also benefits from the small buffer | ||||
| optimization offered by the `entt::any` class and therefore minimizes the number | ||||
| of allocations, avoiding them altogether where possible. | ||||
|  | ||||
| ## Other libraries | ||||
|  | ||||
| There are some very interesting libraries regarding static polymorphism.<br/> | ||||
| Among all, the two that I prefer are: | ||||
|  | ||||
| * [`dyno`](https://github.com/ldionne/dyno): runtime polymorphism done right. | ||||
| * [`Poly`](https://github.com/facebook/folly/blob/master/folly/docs/Poly.md): | ||||
|   a class template that makes it easy to define a type-erasing polymorphic | ||||
|   object wrapper. | ||||
|  | ||||
| The former is admittedly an experimental library, with many interesting ideas. | ||||
| I've some doubts about the usefulness of some feature in real world projects, | ||||
| but perhaps my lack of experience comes into play here. In my opinion, its only | ||||
| flaw is the API which I find slightly more cumbersome than other solutions.<br/> | ||||
| The latter was undoubtedly a source of inspiration for this module, although I | ||||
| opted for different choices in the implementation of both the final API and some | ||||
| feature. | ||||
|  | ||||
| Either way, the authors are gurus of the C++ community, people I only have to | ||||
| learn from. | ||||
|  | ||||
| # Concept and implementation | ||||
|  | ||||
| The first thing to do to create a _type-erasing polymorphic object wrapper_ (to | ||||
| use the terminology introduced by Eric Niebler) is to define a _concept_ that | ||||
| types will have to adhere to.<br/> | ||||
| For this purpose, the library offers a single class that supports both deduced | ||||
| and fully defined interfaces. Although having interfaces deduced automatically | ||||
| is convenient and allows users to write less code in most cases, this has some | ||||
| limitations and it's therefore useful to be able to get around the deduction by | ||||
| providing a custom definition for the static virtual table. | ||||
|  | ||||
| Once the interface is defined, it will be sufficient to provide a generic | ||||
| implementation to fulfill the concept.<br/> | ||||
| Also in this case, the library allows customizations based on types or families | ||||
| of types, so as to be able to go beyond the generic case where necessary. | ||||
|  | ||||
| ## Deduced interface | ||||
|  | ||||
| This is how a concept with a deduced interface is introduced: | ||||
|  | ||||
| ```cpp | ||||
| struct Drawable: entt::type_list<> { | ||||
|     template<typename Base> | ||||
|     struct type: Base { | ||||
|         void draw() { this->template invoke<0>(*this); } | ||||
|     }; | ||||
|  | ||||
|     // ... | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| It's recognizable by the fact that it inherits from an empty type list.<br/> | ||||
| Functions can also be const, accept any number of parameters and return a type | ||||
| other than `void`: | ||||
|  | ||||
| ```cpp | ||||
| struct Drawable: entt::type_list<> { | ||||
|     template<typename Base> | ||||
|     struct type: Base { | ||||
|         bool draw(int pt) const { return this->template invoke<0>(*this, pt); } | ||||
|     }; | ||||
|  | ||||
|     // ... | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| In this case, all parameters must be passed to `invoke` after the reference to | ||||
| `this` and the return value is whatever the internal call returns.<br/> | ||||
| As for `invoke`, this is a name that is injected into the _concept_ through | ||||
| `Base`, from which one must necessarily inherit. Since it's also a dependent | ||||
| name, the `this-> template` form is unfortunately necessary due to the rules of | ||||
| the language. However, there exists also an alternative that goes through an | ||||
| external call: | ||||
|  | ||||
| ```cpp | ||||
| struct Drawable: entt::type_list<> { | ||||
|     template<typename Base> | ||||
|     struct type: Base { | ||||
|         void draw() const { entt::poly_call<0>(*this); } | ||||
|     }; | ||||
|  | ||||
|     // ... | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| Once the _concept_ is defined, users must provide a generic implementation of it | ||||
| in order to tell the system how any type can satisfy its requirements. This is | ||||
| done via an alias template within the concept itself.<br/> | ||||
| The index passed as a template parameter to either `invoke` or `poly_call` | ||||
| refers to how this alias is defined. | ||||
|  | ||||
| ## Defined interface | ||||
|  | ||||
| A fully defined concept is no different to one for which the interface is | ||||
| deduced, with the only difference that the list of types is not empty this time: | ||||
|  | ||||
| ```cpp | ||||
| struct Drawable: entt::type_list<void()> { | ||||
|     template<typename Base> | ||||
|     struct type: Base { | ||||
|         void draw() { entt::poly_call<0>(*this); } | ||||
|     }; | ||||
|  | ||||
|     // ... | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| Again, parameters and return values other than `void` are allowed. Also, the | ||||
| function type must be const when the method to bind to it is const: | ||||
|  | ||||
| ```cpp | ||||
| struct Drawable: entt::type_list<bool(int) const> { | ||||
|     template<typename Base> | ||||
|     struct type: Base { | ||||
|         bool draw(int pt) const { return entt::poly_call<0>(*this, pt); } | ||||
|     }; | ||||
|  | ||||
|     // ... | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| Why should a user fully define a concept if the function types are the same as | ||||
| the deduced ones?<br> | ||||
| Because, in fact, this is exactly the limitation that can be worked around by | ||||
| manually defining the static virtual table. | ||||
|  | ||||
| When things are deduced, there is an implicit constraint.<br/> | ||||
| If the concept exposes a member function called `draw` with function type | ||||
| `void()`, a concept can be satisfied: | ||||
|  | ||||
| * Either by a class that exposes a member function with the same name and the | ||||
|   same signature. | ||||
|  | ||||
| * Or through a lambda that makes use of existing member functions from the | ||||
|   interface itself. | ||||
|  | ||||
| In other words, it's not possible to make use of functions not belonging to the | ||||
| interface, even if they are present in the types that fulfill the concept.<br/> | ||||
| Similarly, it's not possible to deduce a function in the static virtual table | ||||
| with a function type different from that of the associated member function in | ||||
| the interface itself. | ||||
|  | ||||
| Explicitly defining a static virtual table suppresses the deduction step and | ||||
| allows maximum flexibility when providing the implementation for a concept. | ||||
|  | ||||
| ## Fulfill a concept | ||||
|  | ||||
| The `impl` alias template of a concept is used to define how it's fulfilled: | ||||
|  | ||||
| ```cpp | ||||
| struct Drawable: entt::type_list<> { | ||||
|     // ... | ||||
|  | ||||
|     template<typename Type> | ||||
|     using impl = entt::value_list<&Type::draw>; | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| In this case, it's stated that the `draw` method of a generic type will be | ||||
| enough to satisfy the requirements of the `Drawable` concept.<br/> | ||||
| Both member functions and free functions are supported to fulfill concepts: | ||||
|  | ||||
| ```cpp | ||||
| template<typename Type> | ||||
| void print(Type &self) { self.print(); } | ||||
|  | ||||
| struct Drawable: entt::type_list<void()> { | ||||
|     // ... | ||||
|  | ||||
|     template<typename Type> | ||||
|     using impl = entt::value_list<&print<Type>>; | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| Likewise, as long as the parameter types and return type support conversions to | ||||
| and from those of the function type referenced in the static virtual table, the | ||||
| actual implementation may differ in its function type since it's erased | ||||
| internally.<br/> | ||||
| Moreover, the `self` parameter isn't strictly required by the system and can be | ||||
| left out for free functions if not required. | ||||
|  | ||||
| Refer to the inline documentation for more details. | ||||
|  | ||||
| # Inheritance | ||||
|  | ||||
| _Concept inheritance_ is straightforward due to how poly looks like in `EnTT`. | ||||
| Therefore, it's quite easy to build hierarchies of concepts if necessary.<br/> | ||||
| The only constraint is that all concepts in a hierarchy must belong to the same | ||||
| _family_, that is, they must be either all deduced or all defined. | ||||
|  | ||||
| For a deduced concept, inheritance is achieved in a few steps: | ||||
|  | ||||
| ```cpp | ||||
| struct DrawableAndErasable: entt::type_list<> { | ||||
|     template<typename Base> | ||||
|     struct type: typename Drawable::template type<Base> { | ||||
|         static constexpr auto base = std::tuple_size_v<typename entt::poly_vtable<Drawable>::type>; | ||||
|         void erase() { entt::poly_call<base + 0>(*this); } | ||||
|     }; | ||||
|  | ||||
|     template<typename Type> | ||||
|     using impl = entt::value_list_cat_t< | ||||
|         typename Drawable::impl<Type>, | ||||
|         entt::value_list<&Type::erase> | ||||
|     >; | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| The static virtual table is empty and must remain so.<br/> | ||||
| On the other hand, `type` no longer inherits from `Base` and instead forwards | ||||
| its template parameter to the type exposed by the _base class_. Internally, the | ||||
| size of the static virtual table of the base class is used as an offset for the | ||||
| local indexes.<br/> | ||||
| Finally, by means of the `value_list_cat_t` utility, the implementation consists | ||||
| in appending the new functions to the previous list. | ||||
|  | ||||
| As for a defined concept instead, also the list of types must be extended, in a | ||||
| similar way to what is shown for the implementation of the above concept.<br/> | ||||
| To do this, it's useful to declare a function that allows to convert a _concept_ | ||||
| into its underlying `type_list` object: | ||||
|  | ||||
| ```cpp | ||||
| template<typename... Type> | ||||
| entt::type_list<Type...> as_type_list(const entt::type_list<Type...> &); | ||||
| ``` | ||||
|  | ||||
| The definition isn't strictly required, since the function will only be used | ||||
| through a `decltype` as it follows: | ||||
|  | ||||
| ```cpp | ||||
| struct DrawableAndErasable: entt::type_list_cat_t< | ||||
|     decltype(as_type_list(std::declval<Drawable>())), | ||||
|     entt::type_list<void()> | ||||
| > { | ||||
|     // ... | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| Similar to above, `type_list_cat_t` is used to concatenate the underlying static | ||||
| virtual table with the new function types.<br/> | ||||
| Everything else is the same as already shown instead. | ||||
|  | ||||
| # Static polymorphism in the wild | ||||
|  | ||||
| Once the _concept_ and implementation have been introduced, it will be possible | ||||
| to use the `poly` class template to contain instances that meet the | ||||
| requirements: | ||||
|  | ||||
| ```cpp | ||||
| using drawable = entt::poly<Drawable>; | ||||
|  | ||||
| struct circle { | ||||
|     void draw() { /* ... */ } | ||||
| }; | ||||
|  | ||||
| struct square { | ||||
|     void draw() { /* ... */ } | ||||
| }; | ||||
|  | ||||
| // ... | ||||
|  | ||||
| drawable instance{circle{}}; | ||||
| instance->draw(); | ||||
|  | ||||
| instance = square{}; | ||||
| instance->draw(); | ||||
| ``` | ||||
|  | ||||
| The `poly` class template offers a wide range of constructors, from the default | ||||
| one (which will return an uninitialized `poly` object) to the copy and move | ||||
| constructors, as well as the ability to create objects in-place.<br/> | ||||
| Among others, there is also a constructor that allows users to wrap unmanaged | ||||
| objects in a `poly` instance (either const or non-const ones): | ||||
|  | ||||
| ```cpp | ||||
| circle shape; | ||||
| drawable instance{std::in_place_type<circle &>, shape}; | ||||
| ``` | ||||
|  | ||||
| Similarly, it's possible to create non-owning copies of `poly` from an existing | ||||
| object: | ||||
|  | ||||
| ```cpp | ||||
| drawable other = instance.as_ref(); | ||||
| ``` | ||||
|  | ||||
| In both cases, although the interface of the `poly` object doesn't change, it | ||||
| won't construct any element or take care of destroying the referenced objects. | ||||
|  | ||||
| Note also how the underlying concept is accessed via a call to `operator->` and | ||||
| not directly as `instance.draw()`.<br/> | ||||
| This allows users to decouple the API of the wrapper from that of the concept. | ||||
| Therefore, where `instance.data()` will invoke the `data` member function of the | ||||
| poly object, `instance->data()` will map directly to the functionality exposed | ||||
| by the underlying concept. | ||||
|  | ||||
| # Storage size and alignment requirement | ||||
|  | ||||
| Under the hood, the `poly` class template makes use of `entt::any`. Therefore, | ||||
| it can take advantage of the possibility of defining at compile-time the size of | ||||
| the storage suitable for the small buffer optimization as well as the alignment | ||||
| requirements: | ||||
|  | ||||
| ```cpp | ||||
| entt::basic_poly<Drawable, sizeof(double[4]), alignof(double[4])> | ||||
| ``` | ||||
|  | ||||
| The default size is `sizeof(double[2])`, which seems like a good compromise | ||||
| between a buffer that is too large and one unable to hold anything larger than | ||||
| an integer. The alignment requirement is optional instead and by default such | ||||
| that it's the most stringent (the largest) for any object whose size is at most | ||||
| equal to the one provided.<br/> | ||||
| It's worth noting that providing a size of 0 (which is an accepted value in all | ||||
| respects) will force the system to dynamically allocate the contained objects in | ||||
| all cases. | ||||
							
								
								
									
										212
									
								
								external/entt/entt/docs/md/process.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								external/entt/entt/docs/md/process.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,212 @@ | ||||
| # Crash Course: cooperative scheduler | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
| * [The process](#the-process) | ||||
|   * [Adaptor](#adaptor) | ||||
| * [The scheduler](#the-scheduler) | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| Sometimes processes are a useful tool to work around the strict definition of a | ||||
| system and introduce logic in a different way, usually without resorting to the | ||||
| introduction of other components. | ||||
|  | ||||
| `EnTT` offers a minimal support to this paradigm by introducing a few classes | ||||
| that users can use to define and execute cooperative processes. | ||||
|  | ||||
| # The process | ||||
|  | ||||
| A typical process must inherit from the `process` class template that stays true | ||||
| to the CRTP idiom. Moreover, derived classes must specify what's the intended | ||||
| type for elapsed times. | ||||
|  | ||||
| A process should expose publicly the following member functions whether needed | ||||
| (note that it isn't required to define a function unless the derived class wants | ||||
| to _override_ the default behavior): | ||||
|  | ||||
| * `void update(Delta, void *);` | ||||
|  | ||||
|   It's invoked once per tick until a process is explicitly aborted or it | ||||
|   terminates either with or without errors. Even though it's not mandatory to | ||||
|   declare this member function, as a rule of thumb each process should at | ||||
|   least define it to work properly. The `void *` parameter is an opaque pointer | ||||
|   to user data (if any) forwarded directly to the process during an update. | ||||
|  | ||||
| * `void init();` | ||||
|  | ||||
|   It's invoked when the process joins the running queue of a scheduler. This | ||||
|   happens as soon as it's attached to the scheduler if the process is a top | ||||
|   level one, otherwise when it replaces its parent if the process is a | ||||
|   continuation. | ||||
|  | ||||
| * `void succeeded();` | ||||
|  | ||||
|   It's invoked in case of success, immediately after an update and during the | ||||
|   same tick. | ||||
|  | ||||
| * `void failed();` | ||||
|  | ||||
|   It's invoked in case of errors, immediately after an update and during the | ||||
|   same tick. | ||||
|  | ||||
| * `void aborted();` | ||||
|  | ||||
|   It's invoked only if a process is explicitly aborted. There is no guarantee | ||||
|   that it executes in the same tick, this depends solely on whether the | ||||
|   process is aborted immediately or not. | ||||
|  | ||||
| Derived classes can also change the internal state of a process by invoking | ||||
| `succeed` and `fail`, as well as `pause` and `unpause` the process itself. All | ||||
| these are protected member functions made available to be able to manage the | ||||
| life cycle of a process from a derived class. | ||||
|  | ||||
| Here is a minimal example for the sake of curiosity: | ||||
|  | ||||
| ```cpp | ||||
| struct my_process: entt::process<my_process, std::uint32_t> { | ||||
|     using delta_type = std::uint32_t; | ||||
|  | ||||
|     my_process(delta_type delay) | ||||
|         : remaining{delay} | ||||
|     {} | ||||
|  | ||||
|     void update(delta_type delta, void *) { | ||||
|         remaining -= std::min(remaining, delta); | ||||
|  | ||||
|         // ... | ||||
|  | ||||
|         if(!remaining) { | ||||
|             succeed(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     delta_type remaining; | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| ## Adaptor | ||||
|  | ||||
| Lambdas and functors can't be used directly with a scheduler for they are not | ||||
| properly defined processes with managed life cycles.<br/> | ||||
| This class helps in filling the gap and turning lambdas and functors into | ||||
| full-featured processes usable by a scheduler. | ||||
|  | ||||
| The function call operator has a signature similar to the one of the `update` | ||||
| function of a process but for the fact that it receives two extra arguments to | ||||
| call whenever a process is terminated with success or with an error: | ||||
|  | ||||
| ```cpp | ||||
| void(Delta delta, void *data, auto succeed, auto fail); | ||||
| ``` | ||||
|  | ||||
| Parameters have the following meaning: | ||||
|  | ||||
| * `delta` is the elapsed time. | ||||
| * `data` is an opaque pointer to user data if any, `nullptr` otherwise. | ||||
| * `succeed` is a function to call when a process terminates with success. | ||||
| * `fail` is a function to call when a process terminates with errors. | ||||
|  | ||||
| Both `succeed` and `fail` accept no parameters at all. | ||||
|  | ||||
| Note that usually users shouldn't worry about creating adaptors at all. A | ||||
| scheduler creates them internally each and every time a lambda or a functor is | ||||
| used as a process. | ||||
|  | ||||
| # The scheduler | ||||
|  | ||||
| A cooperative scheduler runs different processes and helps managing their life | ||||
| cycles. | ||||
|  | ||||
| Each process is invoked once per tick. If it terminates, it's removed | ||||
| automatically from the scheduler and it's never invoked again. Otherwise it's | ||||
| a good candidate to run one more time the next tick.<br/> | ||||
| A process can also have a child. In this case, the parent process is replaced | ||||
| with its child when it terminates and only if it returns with success. In case | ||||
| of errors, both the parent process and its child are discarded. This way, it's | ||||
| easy to create chain of processes to run sequentially. | ||||
|  | ||||
| Using a scheduler is straightforward. To create it, users must provide only the | ||||
| type for the elapsed times and no arguments at all: | ||||
|  | ||||
| ```cpp | ||||
| entt::scheduler<std::uint32_t> scheduler; | ||||
| ``` | ||||
|  | ||||
| It has member functions to query its internal data structures, like `empty` or | ||||
| `size`, as well as a `clear` utility to reset it to a clean state: | ||||
|  | ||||
| ```cpp | ||||
| // checks if there are processes still running | ||||
| const auto empty = scheduler.empty(); | ||||
|  | ||||
| // gets the number of processes still running | ||||
| entt::scheduler<std::uint32_t>::size_type size = scheduler.size(); | ||||
|  | ||||
| // resets the scheduler to its initial state and discards all the processes | ||||
| scheduler.clear(); | ||||
| ``` | ||||
|  | ||||
| To attach a process to a scheduler there are mainly two ways: | ||||
|  | ||||
| * If the process inherits from the `process` class template, it's enough to | ||||
|   indicate its type and submit all the parameters required to construct it to | ||||
|   the `attach` member function: | ||||
|  | ||||
|   ```cpp | ||||
|   scheduler.attach<my_process>(1000u); | ||||
|   ``` | ||||
|  | ||||
| * Otherwise, in case of a lambda or a functor, it's enough to provide an | ||||
|   instance of the class to the `attach` member function: | ||||
|  | ||||
|   ```cpp | ||||
|   scheduler.attach([](auto...){ /* ... */ }); | ||||
|   ``` | ||||
|  | ||||
| In both cases, the return value is an opaque object that offers a `then` member | ||||
| function to use to create chains of processes to run sequentially.<br/> | ||||
| As a minimal example of use: | ||||
|  | ||||
| ```cpp | ||||
| // schedules a task in the form of a lambda function | ||||
| scheduler.attach([](auto delta, void *, auto succeed, auto fail) { | ||||
|     // ... | ||||
| }) | ||||
| // appends a child in the form of another lambda function | ||||
| .then([](auto delta, void *, auto succeed, auto fail) { | ||||
|     // ... | ||||
| }) | ||||
| // appends a child in the form of a process class | ||||
| .then<my_process>(1000u); | ||||
| ``` | ||||
|  | ||||
| To update a scheduler and therefore all its processes, the `update` member | ||||
| function is the way to go: | ||||
|  | ||||
| ```cpp | ||||
| // updates all the processes, no user data are provided | ||||
| scheduler.update(delta); | ||||
|  | ||||
| // updates all the processes and provides them with custom data | ||||
| scheduler.update(delta, &data); | ||||
| ``` | ||||
|  | ||||
| In addition to these functions, the scheduler offers an `abort` member function | ||||
| that can be used to discard all the running processes at once: | ||||
|  | ||||
| ```cpp | ||||
| // aborts all the processes abruptly ... | ||||
| scheduler.abort(true); | ||||
|  | ||||
| // ... or gracefully during the next tick | ||||
| scheduler.abort(); | ||||
| ``` | ||||
							
								
								
									
										75
									
								
								external/entt/entt/docs/md/reference.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								external/entt/entt/docs/md/reference.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| # Similar projects | ||||
|  | ||||
| There are many projects similar to `EnTT`, both open source and not.<br/> | ||||
| Some even borrowed some ideas from this library and expressed them in different | ||||
| languages.<br/> | ||||
| Others developed different architectures from scratch and therefore offer | ||||
| alternative solutions with their pros and cons. | ||||
|  | ||||
| Below an incomplete list of those that I've come across so far.<br/> | ||||
| If some terms or designs aren't clear, I recommend referring to the | ||||
| [_ECS Back and Forth_](https://skypjack.github.io/tags/#ecs) series for all the | ||||
| details. | ||||
|  | ||||
| I hope this list can grow much more in the future: | ||||
|  | ||||
| * C: | ||||
|   * [destral_ecs](https://github.com/roig/destral_ecs): a single-file ECS based | ||||
|     on sparse sets. | ||||
|   * [Diana](https://github.com/discoloda/Diana): an ECS that uses sparse sets to | ||||
|     keep track of entities in systems. | ||||
|   * [Flecs](https://github.com/SanderMertens/flecs): a multithreaded archetype | ||||
|     ECS based on semi-contiguous arrays rather than chunks. | ||||
|   * [lent](https://github.com/nem0/lent): the Donald Trump of the ECS libraries. | ||||
|  | ||||
| * C++: | ||||
|   * [decs](https://github.com/vblanco20-1/decs): a chunk based archetype ECS. | ||||
|   * [ecst](https://github.com/SuperV1234/ecst): a multithreaded compile-time | ||||
|     ECS that uses sparse sets to keep track of entities in systems. | ||||
|   * [EntityX](https://github.com/alecthomas/entityx): a bitset based ECS that | ||||
|     uses a single large matrix of components indexed with entities. | ||||
|   * [Gaia-ECS](https://github.com/richardbiely/gaia-ecs): a chunk based | ||||
|     archetype ECS. | ||||
|   * [Polypropylene](https://github.com/pmbittner/Polypropylene): a hybrid | ||||
|     solution between an ECS and dynamic mixins. | ||||
|  | ||||
| * C# | ||||
|   * [Entitas](https://github.com/sschmid/Entitas-CSharp): the ECS framework for | ||||
|     C# and Unity, where _reactive systems_ were invented. | ||||
|   * [LeoECS](https://github.com/Leopotam/ecs): simple lightweight C# Entity | ||||
|     Component System framework. | ||||
|   * [Svelto.ECS](https://github.com/sebas77/Svelto.ECS): a very interesting | ||||
|     platform agnostic and table based ECS framework. | ||||
|  | ||||
| * Go: | ||||
|   * [gecs](https://github.com/tutumagi/gecs): a sparse sets based ECS inspired  | ||||
|     by `EnTT`. | ||||
|  | ||||
| * Javascript: | ||||
|   * [\@javelin/ecs](https://github.com/3mcd/javelin/tree/master/packages/ecs): | ||||
|     an archetype ECS in TypeScript. | ||||
|   * [ecsy](https://github.com/MozillaReality/ecsy): I haven't had the time to | ||||
|     investigate the underlying design of `ecsy` but it looks cool anyway. | ||||
|  | ||||
| * Perl: | ||||
|   * [Game::Entities](https://gitlab.com/jjatria/perl-game-entities): a simple | ||||
|     entity registry for ECS designs inspired by `EnTT`. | ||||
|  | ||||
| * Raku: | ||||
|   * [Game::Entities](https://gitlab.com/jjatria/raku-game-entities): a simple | ||||
|     entity registry for ECS designs inspired by `EnTT`. | ||||
|  | ||||
| * Rust: | ||||
|   * [Legion](https://github.com/TomGillen/legion): a chunk based archetype ECS. | ||||
|   * [Shipyard](https://github.com/leudz/shipyard): it borrows some ideas from | ||||
|     `EnTT` and offers a sparse sets based ECS with grouping functionalities. | ||||
|   * [Sparsey](https://github.com/LechintanTudor/sparsey): sparse set based ECS | ||||
|     written in Rust. | ||||
|   * [Specs](https://github.com/amethyst/specs): a parallel ECS based mainly on | ||||
|     hierarchical bitsets that allows different types of storage as needed. | ||||
|  | ||||
| * Zig | ||||
|   * [zig-ecs](https://github.com/prime31/zig-ecs): a _zig-ification_ of `EnTT`. | ||||
|  | ||||
| If you know of other resources out there that can be of interest for the reader, | ||||
| feel free to open an issue or a PR and I'll be glad to add them to this page. | ||||
							
								
								
									
										191
									
								
								external/entt/entt/docs/md/resource.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								external/entt/entt/docs/md/resource.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,191 @@ | ||||
| # Crash Course: resource management | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
| * [The resource, the loader and the cache](#the-resource-the-loader-and-the-cache) | ||||
|   * [Resource handle](#resource-handle) | ||||
|   * [Loaders](#loader) | ||||
|   * [The cache class](#the-cache) | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| Resource management is usually one of the most critical parts of a game. | ||||
| Solutions are often tuned to the particular application. There exist several | ||||
| approaches and all of them are perfectly fine as long as they fit the | ||||
| requirements of the piece of software in which they are used.<br/> | ||||
| Examples are loading everything on start, loading on request, predictive | ||||
| loading, and so on. | ||||
|  | ||||
| `EnTT` doesn't pretend to offer a _one-fits-all_ solution for the different | ||||
| cases.<br/> | ||||
| Instead, the library comes with a minimal, general purpose resource cache that | ||||
| might be useful in many cases. | ||||
|  | ||||
| # The resource, the loader and the cache | ||||
|  | ||||
| Resource, loader and cache are the three main actors for the purpose.<br/> | ||||
| The _resource_ is an image, an audio, a video or any other type: | ||||
|  | ||||
| ```cpp | ||||
| struct my_resource { const int value; }; | ||||
| ``` | ||||
|  | ||||
| The _loader_ is a callable type the aim of which is to load a specific resource: | ||||
|  | ||||
| ```cpp | ||||
| struct my_loader final { | ||||
|     using result_type = std::shared_ptr<my_resource>; | ||||
|  | ||||
|     result_type operator()(int value) const { | ||||
|         // ... | ||||
|         return std::make_shared<my_resource>(value); | ||||
|     } | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| Its function operator can accept any arguments and should return a value of the | ||||
| declared result type (`std::shared_ptr<my_resource>` in the example).<br/> | ||||
| A loader can also overload its function call operator to make it possible to | ||||
| construct the same or another resource from different lists of arguments. | ||||
|  | ||||
| Finally, a cache is a specialization of a class template tailored to a specific | ||||
| resource and (optionally) a loader: | ||||
|  | ||||
| ```cpp | ||||
| using my_cache = entt::resource_cache<my_resource, my_loader>; | ||||
|  | ||||
| // ... | ||||
|  | ||||
| my_cache cache{}; | ||||
| ``` | ||||
|  | ||||
| The class is designed to create different caches for different resource types | ||||
| and to manage each one independently in the most appropriate way.<br/> | ||||
| As a (very) trivial example, audio tracks can survive in most of the scenes of | ||||
| an application while meshes can be associated with a single scene only, then | ||||
| discarded when a player leaves it. | ||||
|  | ||||
| ## Resource handle | ||||
|  | ||||
| Resources aren't returned directly to the caller. Instead, they are wrapped in a | ||||
| _resource handle_, an instance of the `entt::resource` class template.<br/> | ||||
| For those who know the _flyweight design pattern_ already, that's exactly what | ||||
| it is. To all others, this is the time to brush up on some notions instead. | ||||
|  | ||||
| A shared pointer could have been used as a resource handle. In fact, the default | ||||
| implementation mostly maps the interface of its standard counterpart and only | ||||
| adds a few things on top of it.<br/> | ||||
| However, the handle in `EnTT` is designed as a standalone class template. This | ||||
| is due to the fact that specializing a class in the standard library is often | ||||
| undefined behavior while having the ability to specialize the handle for one, | ||||
| more or all resource types could help over time. | ||||
|  | ||||
| ## Loaders | ||||
|  | ||||
| A loader is responsible for _loading_ resources (quite obviously).<br/> | ||||
| By default, it's just a callable object that forwards its arguments to the | ||||
| resource itself. That is, a _passthrough type_. All the work is demanded to the | ||||
| constructor(s) of the resource itself.<br/> | ||||
| Loaders also are fully customizable as expected. | ||||
|  | ||||
| A custom loader is a class with at least one function call operator and a member | ||||
| type named `result_type`.<br/> | ||||
| The loader isn't required to return a resource handle. As long as `return_type` | ||||
| is suitable for constructing a handle, that's fine. | ||||
|  | ||||
| When using the default handle, it expects a resource type which is convertible | ||||
| to or suitable for constructing an `std::shared_ptr<Type>` (where `Type` is the | ||||
| actual resource type).<br/> | ||||
| In other terms, the loader should return shared pointers to the given resource | ||||
| type. However, this isn't mandatory. Users can easily get around this constraint | ||||
| by specializing both the handle and the loader. | ||||
|  | ||||
| A cache forwards all its arguments to the loader if required. This means that | ||||
| loaders can also support tag dispatching to offer different loading policies: | ||||
|  | ||||
| ```cpp | ||||
| struct my_loader { | ||||
|     using result_type = std::shared_ptr<my_resource>; | ||||
|  | ||||
|     struct from_disk_tag{}; | ||||
|     struct from_network_tag{}; | ||||
|  | ||||
|     template<typename Args> | ||||
|     result_type operator()(from_disk_tag, Args&&... args) { | ||||
|         // ... | ||||
|         return std::make_shared<my_resource>(std::forward<Args>(args)...); | ||||
|     } | ||||
|  | ||||
|     template<typename Args> | ||||
|     result_type operator()(from_network_tag, Args&&... args) { | ||||
|         // ... | ||||
|         return std::make_shared<my_resource>(std::forward<Args>(args)...); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| This makes the whole loading logic quite flexible and easy to extend over time. | ||||
|  | ||||
| ## The cache class | ||||
|  | ||||
| The cache is the class that is asked to _connect the dots_.<br/> | ||||
| It loads the resources, stores them aside and returns handles as needed: | ||||
|  | ||||
| ```cpp | ||||
| entt::resource_cache<my_resource, my_loader> cache{}; | ||||
| ``` | ||||
|  | ||||
| Under the hood, a cache is nothing more than a map where the key value has type | ||||
| `entt::id_type` while the mapped value is whatever type its loader returns.<br/> | ||||
| For this reason, it offers most of the functionalities a user would expect from | ||||
| a map, such as `empty` or `size` and so on. Similarly, it's an iterable type | ||||
| that also supports indexing by resource id: | ||||
|  | ||||
| ```cpp | ||||
| for(auto [id, res]: cache) { | ||||
|     // ... | ||||
| } | ||||
|  | ||||
| if(entt::resource<my_resource> res = cache["resource/id"_hs]; res) { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Please, refer to the inline documentation for all the details about the other | ||||
| functions (such as `contains` or `erase`). | ||||
|  | ||||
| Set aside the part of the API that this class _shares_ with a map, it also adds | ||||
| something on top of it in order to address the most common requirements of a | ||||
| resource cache.<br/> | ||||
| In particular, it doesn't have an `emplace` member function which is replaced by | ||||
| `load` and `force_load` instead (where the former loads a new resource only if | ||||
| not present while the second triggers a forced loading in any case): | ||||
|  | ||||
| ```cpp | ||||
| auto ret = cache.load("resource/id"_hs); | ||||
|  | ||||
| // true only if the resource was not already present | ||||
| const bool loaded = ret.second; | ||||
|  | ||||
| // takes the resource handle pointed to by the returned iterator | ||||
| entt::resource<my_resource> res = ret.first->second; | ||||
| ``` | ||||
|  | ||||
| Note that the hashed string is used for convenience in the example above.<br/> | ||||
| Resource identifiers are nothing more than integral values. Therefore, plain | ||||
| numbers as well as non-class enum value are accepted. | ||||
|  | ||||
| It's worth mentioning that the iterators of a cache as well as its indexing | ||||
| operators return resource handles rather than instances of the mapped type.<br/> | ||||
| Since the cache has no control over the loader and a resource isn't required to | ||||
| also be convertible to bool, these handles can be invalid. This usually means an | ||||
| error in the user logic but it may also be an _expected_ event.<br/> | ||||
| It's therefore recommended to verify handles validity with a check in debug (for | ||||
| example, when loading) or an appropriate logic in retail. | ||||
							
								
								
									
										549
									
								
								external/entt/entt/docs/md/signal.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										549
									
								
								external/entt/entt/docs/md/signal.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,549 @@ | ||||
| # Crash Course: events, signals and everything in between | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
| * [Delegate](#delegate) | ||||
|   * [Runtime arguments](#runtime-arguments) | ||||
|   * [Lambda support](#lambda-support) | ||||
| * [Signals](#signals) | ||||
| * [Event dispatcher](#event-dispatcher) | ||||
|   * [Named queues](#named-queues) | ||||
| * [Event emitter](#event-emitter) | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| Signals are more often than not a core part of games and software architectures | ||||
| in general.<br/> | ||||
| They help to decouple the various parts of a system while allowing them to | ||||
| communicate with each other somehow. | ||||
|  | ||||
| The so called _modern C++_ comes with a tool that can be useful in this regard, | ||||
| the `std::function`. As an example, it can be used to create delegates.<br/> | ||||
| However, there is no guarantee that an `std::function` doesn't perform | ||||
| allocations under the hood and this could be problematic sometimes. Furthermore, | ||||
| it solves a problem but may not adapt well to other requirements that may arise | ||||
| from time to time. | ||||
|  | ||||
| In case that the flexibility and power of an `std::function` isn't required or | ||||
| if the price to pay for them is too high, `EnTT` offers a complete set of | ||||
| lightweight classes to solve the same and many other problems. | ||||
|  | ||||
| # Delegate | ||||
|  | ||||
| A delegate can be used as a general purpose invoker with no memory overhead for | ||||
| free functions and member functions provided along with an instance on which to | ||||
| invoke them.<br/> | ||||
| It doesn't claim to be a drop-in replacement for an `std::function`, so don't | ||||
| expect to use it whenever an `std::function` fits well. That said, it's most | ||||
| likely even a better fit than an `std::function` in a lot of cases, so expect to | ||||
| use it quite a lot anyway. | ||||
|  | ||||
| The interface is trivial. It offers a default constructor to create empty | ||||
| delegates: | ||||
|  | ||||
| ```cpp | ||||
| entt::delegate<int(int)> delegate{}; | ||||
| ``` | ||||
|  | ||||
| What is needed to create an instance is to specify the type of the function the | ||||
| delegate _accepts_, that is the signature of the functions it models.<br/> | ||||
| However, attempting to use an empty delegate by invoking its function call | ||||
| operator results in undefined behavior or most likely a crash. | ||||
|  | ||||
| There exist a few overloads of the `connect` member function to initialize a | ||||
| delegate: | ||||
|  | ||||
| ```cpp | ||||
| int f(int i) { return i; } | ||||
|  | ||||
| struct my_struct { | ||||
|     int f(const int &i) const { return i; } | ||||
| }; | ||||
|  | ||||
| // bind a free function to the delegate | ||||
| delegate.connect<&f>(); | ||||
|  | ||||
| // bind a member function to the delegate | ||||
| my_struct instance; | ||||
| delegate.connect<&my_struct::f>(instance); | ||||
| ``` | ||||
|  | ||||
| The delegate class also accepts data members, if needed. In this case, the | ||||
| function type of the delegate is such that the parameter list is empty and the | ||||
| value of the data member is at least convertible to the return type. | ||||
|  | ||||
| Free functions having type equivalent to `void(T &, args...)` are accepted as | ||||
| well. The first argument `T &` is considered a payload and the function will | ||||
| receive it back every time it's invoked. In other terms, this works just fine | ||||
| with the above definition: | ||||
|  | ||||
| ```cpp | ||||
| void g(const char &c, int i) { /* ... */ } | ||||
| const char c = 'c'; | ||||
|  | ||||
| delegate.connect<&g>(c); | ||||
| delegate(42); | ||||
| ``` | ||||
|  | ||||
| The function `g` is invoked with a reference to `c` and `42`. However, the | ||||
| function type of the delegate is still `void(int)`. This is also the signature | ||||
| of its function call operator.<br/> | ||||
| Another interesting aspect of the delegate class is that it accepts functions | ||||
| with a list of parameters that is shorter than that of its function type: | ||||
|  | ||||
| ```cpp | ||||
| void g() { /* ... */ } | ||||
| delegate.connect<&g>(); | ||||
| delegate(42); | ||||
| ``` | ||||
|  | ||||
| Where the function type of the delegate is `void(int)` as above. It goes without | ||||
| saying that the extra arguments are silently discarded internally.<br/> | ||||
| This is a nice-to-have feature in a lot of cases, as an example when the | ||||
| `delegate` class is used as a building block of a signal-slot system. | ||||
|  | ||||
| To create and initialize a delegate at once, there are a few specialized | ||||
| constructors. Because of the rules of the language, the listener is provided by | ||||
| means of the `entt::connect_arg` variable template: | ||||
|  | ||||
| ```cpp | ||||
| entt::delegate<int(int)> func{entt::connect_arg<&f>}; | ||||
| ``` | ||||
|  | ||||
| Aside `connect`, a `disconnect` counterpart isn't provided. Instead, there | ||||
| exists a `reset` member function to use to clear a delegate.<br/> | ||||
| To know if a delegate is empty, it can be used explicitly in every conditional | ||||
| statement: | ||||
|  | ||||
| ```cpp | ||||
| if(delegate) { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Finally, to invoke a delegate, the function call operator is the way to go as | ||||
| already shown in the examples above: | ||||
|  | ||||
| ```cpp | ||||
| auto ret = delegate(42); | ||||
| ``` | ||||
|  | ||||
| In all cases, listeners don't have to strictly follow the signature of the | ||||
| delegate. As long as a listener can be invoked with the given arguments to yield | ||||
| a result that is convertible to the given result type, everything works just | ||||
| fine. | ||||
|  | ||||
| As a side note, members of classes may or may not be associated with instances. | ||||
| If they are not, the first argument of the function type must be that of the | ||||
| class on which the members operate and an instance of this class must obviously | ||||
| be passed when invoking the delegate: | ||||
|  | ||||
| ```cpp | ||||
| entt::delegate<void(my_struct &, int)> delegate; | ||||
| delegate.connect<&my_struct::f>(); | ||||
|  | ||||
| my_struct instance; | ||||
| delegate(instance, 42); | ||||
| ``` | ||||
|  | ||||
| In this case, it's not possible to _deduce_ the function type since the first | ||||
| argument doesn't necessarily have to be a reference (for example, it can be a | ||||
| pointer, as well as a const reference).<br/> | ||||
| Therefore, the function type must be declared explicitly for unbound members. | ||||
|  | ||||
| ## Runtime arguments | ||||
|  | ||||
| The `delegate` class is meant to be used primarily with template arguments. | ||||
| However, as a consequence of its design, it also offers minimal support for | ||||
| runtime arguments.<br/> | ||||
| When used like this, some features aren't supported though. In particular: | ||||
|  | ||||
| * Curried functions aren't accepted. | ||||
| * Functions with an argument list that differs from that of the delegate aren't | ||||
|   supported. | ||||
| * Return type and types of arguments **must** coincide with those of the | ||||
|   delegate and _being at least convertible_ isn't enough anymore. | ||||
|  | ||||
| Moreover, for a given function type `Ret(Args...)`, the signature of the | ||||
| functions connected at runtime must necessarily be `Ret(const void *, Args...)`. | ||||
|  | ||||
| Runtime arguments can be passed both to the constructor of a delegate and to the | ||||
| `connect` member function. An optional parameter is also accepted in both cases. | ||||
| This argument is used to pass arbitrary user data back and forth as a | ||||
| `const void *` upon invocation.<br/> | ||||
| To connect a function to a delegate _in the hard way_: | ||||
|  | ||||
| ```cpp | ||||
| int func(const void *ptr, int i) { return *static_cast<const int *>(ptr) * i; } | ||||
| const int value = 42; | ||||
|  | ||||
| // use the constructor ... | ||||
| entt::delegate delegate{&func, &value}; | ||||
|  | ||||
| // ... or the connect member function | ||||
| delegate.connect(&func, &value); | ||||
| ``` | ||||
|  | ||||
| The type of the delegate is deduced from the function if possible. In this case, | ||||
| since the first argument is an implementation detail, the deduced function type | ||||
| is `int(int)`.<br/> | ||||
| Invoking a delegate built in this way follows the same rules as previously | ||||
| explained. | ||||
|  | ||||
| ## Lambda support | ||||
|  | ||||
| In general, the `delegate` class doesn't fully support lambda functions in all | ||||
| their nuances. The reason is pretty simple: a `delegate` isn't a drop-in | ||||
| replacement for an `std::function`. Instead, it tries to overcome the problems | ||||
| with the latter.<br/> | ||||
| That being said, non-capturing lambda functions are supported, even though some | ||||
| features aren't available in this case. | ||||
|  | ||||
| This is a logical consequence of the support for connecting functions at | ||||
| runtime. Therefore, lambda functions undergo the same rules and | ||||
| limitations.<br/> | ||||
| In fact, since non-capturing lambda functions decay to pointers to functions, | ||||
| they can be used with a `delegate` as if they were _normal functions_ with | ||||
| optional payload: | ||||
|  | ||||
| ```cpp | ||||
| my_struct instance; | ||||
|  | ||||
| // use the constructor ... | ||||
| entt::delegate delegate{+[](const void *ptr, int value) { | ||||
|     return static_cast<const my_struct *>(ptr)->f(value); | ||||
| }, &instance}; | ||||
|  | ||||
| // ... or the connect member function | ||||
| delegate.connect([](const void *ptr, int value) { | ||||
|     return static_cast<const my_struct *>(ptr)->f(value); | ||||
| }, &instance); | ||||
| ``` | ||||
|  | ||||
| As above, the first parameter (`const void *`) isn't part of the function type | ||||
| of the delegate and is used to dispatch arbitrary user data back and forth. In | ||||
| other terms, the function type of the delegate above is `int(int)`. | ||||
|  | ||||
| # Signals | ||||
|  | ||||
| Signal handlers work with references to classes, function pointers and pointers | ||||
| to members. Listeners can be any kind of objects and users are in charge of | ||||
| connecting and disconnecting them from a signal to avoid crashes due to | ||||
| different lifetimes. On the other side, performance shouldn't be affected that | ||||
| much by the presence of such a signal handler.<br/> | ||||
| Signals make use of delegates internally and therefore they undergo the same | ||||
| rules and offer similar functionalities. It may be a good idea to consult the | ||||
| documentation of the `delegate` class for further information. | ||||
|  | ||||
| A signal handler is can be used as a private data member without exposing any | ||||
| _publish_ functionality to the clients of a class.<br/> | ||||
| The basic idea is to impose a clear separation between the signal itself and the | ||||
| `sink` class, that is a tool to be used to connect and disconnect listeners on | ||||
| the fly. | ||||
|  | ||||
| The API of a signal handler is straightforward. If a collector is supplied to | ||||
| the signal when something is published, all the values returned by its listeners | ||||
| are literally _collected_ and used later by the caller. Otherwise, the class | ||||
| works just like a plain signal that emits events from time to time.<br/> | ||||
| To create instances of signal handlers it's sufficient to provide the type of | ||||
| function to which they refer: | ||||
|  | ||||
| ```cpp | ||||
| entt::sigh<void(int, char)> signal; | ||||
| ``` | ||||
|  | ||||
| Signals offer all the basic functionalities required to know how many listeners | ||||
| they contain (`size`) or if they contain at least a listener (`empty`), as well | ||||
| as a function to use to swap handlers (`swap`). | ||||
|  | ||||
| Besides them, there are member functions to use both to connect and disconnect | ||||
| listeners in all their forms by means of a sink: | ||||
|  | ||||
| ```cpp | ||||
| void foo(int, char) { /* ... */ } | ||||
|  | ||||
| struct listener { | ||||
|     void bar(const int &, char) { /* ... */ } | ||||
| }; | ||||
|  | ||||
| // ... | ||||
|  | ||||
| entt::sink sink{signal}; | ||||
| listener instance; | ||||
|  | ||||
| sink.connect<&foo>(); | ||||
| sink.connect<&listener::bar>(instance); | ||||
|  | ||||
| // ... | ||||
|  | ||||
| // disconnects a free function | ||||
| sink.disconnect<&foo>(); | ||||
|  | ||||
| // disconnect a member function of an instance | ||||
| sink.disconnect<&listener::bar>(instance); | ||||
|  | ||||
| // disconnect all member functions of an instance, if any | ||||
| sink.disconnect(instance); | ||||
|  | ||||
| // discards all listeners at once | ||||
| sink.disconnect(); | ||||
| ``` | ||||
|  | ||||
| As shown above, listeners don't have to strictly follow the signature of the | ||||
| signal. As long as a listener can be invoked with the given arguments to yield a | ||||
| result that is convertible to the given return type, everything works just | ||||
| fine.<br/> | ||||
| It's also possible to connect a listener before other elements already contained | ||||
| by the signal. The `before` function returns a `sink` object that is correctly | ||||
| initialized for the purpose and can be used to connect one or more listeners in | ||||
| order and in the desired position: | ||||
|  | ||||
| ```cpp | ||||
| sink.before<&foo>().connect<&listener::bar>(instance); | ||||
| ``` | ||||
|  | ||||
| In all cases, the `connect` member function returns by default a `connection` | ||||
| object to be used as an alternative to break a connection by means of its | ||||
| `release` member function.<br/> | ||||
| A `scoped_connection` can also be created from a connection. In this case, the | ||||
| link is broken automatically as soon as the object goes out of scope. | ||||
|  | ||||
| Once listeners are attached (or even if there are no listeners at all), events | ||||
| and data in general are published through a signal by means of the `publish` | ||||
| member function: | ||||
|  | ||||
| ```cpp | ||||
| signal.publish(42, 'c'); | ||||
| ``` | ||||
|  | ||||
| To collect data, the `collect` member function is used instead: | ||||
|  | ||||
| ```cpp | ||||
| int f() { return 0; } | ||||
| int g() { return 1; } | ||||
|  | ||||
| // ... | ||||
|  | ||||
| entt::sigh<int()> signal; | ||||
| entt::sink sink{signal}; | ||||
|  | ||||
| sink.connect<&f>(); | ||||
| sink.connect<&g>(); | ||||
|  | ||||
| std::vector<int> vec{}; | ||||
| signal.collect([&vec](int value) { vec.push_back(value); }); | ||||
|  | ||||
| assert(vec[0] == 0); | ||||
| assert(vec[1] == 1); | ||||
| ``` | ||||
|  | ||||
| A collector must expose a function operator that accepts as an argument a type | ||||
| to which the return type of the listeners can be converted. Moreover, it can | ||||
| optionally return a boolean value that is true to stop collecting data, false | ||||
| otherwise. This way one can avoid calling all the listeners in case it isn't | ||||
| necessary.<br/> | ||||
| Functors can also be used in place of a lambda. Since the collector is copied | ||||
| when invoking the `collect` member function, `std::ref` is the way to go in this | ||||
| case: | ||||
|  | ||||
| ```cpp | ||||
| struct my_collector { | ||||
|     std::vector<int> vec{}; | ||||
|  | ||||
|     bool operator()(int v) { | ||||
|         vec.push_back(v); | ||||
|         return true; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| // ... | ||||
|  | ||||
| my_collector collector; | ||||
| signal.collect(std::ref(collector)); | ||||
| ``` | ||||
|  | ||||
| # Event dispatcher | ||||
|  | ||||
| The event dispatcher class allows users to trigger immediate events or to queue | ||||
| and publish them all together later.<br/> | ||||
| This class lazily instantiates its queues. Therefore, it's not necessary to | ||||
| _announce_ the event types in advance: | ||||
|  | ||||
| ```cpp | ||||
| // define a general purpose dispatcher | ||||
| entt::dispatcher dispatcher{}; | ||||
| ``` | ||||
|  | ||||
| A listener registered with a dispatcher is such that its type offers one or more | ||||
| member functions that take arguments of type `Event &` for any type of event, | ||||
| regardless of the return value.<br/> | ||||
| These functions are linked directly via `connect` to a _sink_: | ||||
|  | ||||
| ```cpp | ||||
| struct an_event { int value; }; | ||||
| struct another_event {}; | ||||
|  | ||||
| struct listener { | ||||
|     void receive(const an_event &) { /* ... */ } | ||||
|     void method(const another_event &) { /* ... */ } | ||||
| }; | ||||
|  | ||||
| // ... | ||||
|  | ||||
| listener listener; | ||||
| dispatcher.sink<an_event>().connect<&listener::receive>(listener); | ||||
| dispatcher.sink<another_event>().connect<&listener::method>(listener); | ||||
| ``` | ||||
|  | ||||
| Note that connecting listeners within event handlers can result in undefined | ||||
| behavior.<br/> | ||||
| The `disconnect` member function is used to remove one listener at a time or all | ||||
| of them at once: | ||||
|  | ||||
| ```cpp | ||||
| dispatcher.sink<an_event>().disconnect<&listener::receive>(listener); | ||||
| dispatcher.sink<another_event>().disconnect(listener); | ||||
| ``` | ||||
|  | ||||
| The `trigger` member function serves the purpose of sending an immediate event | ||||
| to all the listeners registered so far: | ||||
|  | ||||
| ```cpp | ||||
| dispatcher.trigger(an_event{42}); | ||||
| dispatcher.trigger<another_event>(); | ||||
| ``` | ||||
|  | ||||
| Listeners are invoked immediately, order of execution isn't guaranteed. This | ||||
| method can be used to push around urgent messages like an _is terminating_ | ||||
| notification on a mobile app. | ||||
|  | ||||
| On the other hand, the `enqueue` member function queues messages together and | ||||
| helps to maintain control over the moment they are sent to listeners: | ||||
|  | ||||
| ```cpp | ||||
| dispatcher.enqueue<an_event>(42); | ||||
| dispatcher.enqueue(another_event{}); | ||||
| ``` | ||||
|  | ||||
| Events are stored aside until the `update` member function is invoked: | ||||
|  | ||||
| ```cpp | ||||
| // emits all the events of the given type at once | ||||
| dispatcher.update<an_event>(); | ||||
|  | ||||
| // emits all the events queued so far at once | ||||
| dispatcher.update(); | ||||
| ``` | ||||
|  | ||||
| This way users can embed the dispatcher in a loop and literally dispatch events | ||||
| once per tick to their systems. | ||||
|  | ||||
| ## Named queues | ||||
|  | ||||
| All queues within a dispatcher are associated by default with an event type and | ||||
| then retrieved from it.<br/> | ||||
| However, it's possible to create queues with different _names_ (and therefore | ||||
| also multiple queues for a single type). In fact, more or less all functions | ||||
| also take an additional parameter. As an example: | ||||
|  | ||||
| ```cpp | ||||
| dispatcher.sink<an_event>("custom"_hs).connect<&listener::receive>(listener); | ||||
| ``` | ||||
|  | ||||
| In this case, the term _name_ is misused as these are actual numeric identifiers | ||||
| of type `id_type`.<br/> | ||||
| An exception to this rule is the `enqueue` function. There is no additional | ||||
| parameter for it but rather a different function: | ||||
|  | ||||
| ```cpp | ||||
| dispatcher.enqueue_hint<an_event>("custom"_hs, 42); | ||||
| ``` | ||||
|  | ||||
| This is mainly due to the template argument deduction rules and unfortunately | ||||
| there is no real (elegant) way to avoid it. | ||||
|  | ||||
| # Event emitter | ||||
|  | ||||
| A general purpose event emitter thought mainly for those cases where it comes to | ||||
| working with asynchronous stuff.<br/> | ||||
| Originally designed to fit the requirements of | ||||
| [`uvw`](https://github.com/skypjack/uvw) (a wrapper for `libuv` written in | ||||
| modern C++), it was adapted later to be included in this library. | ||||
|  | ||||
| To create an emitter type, derived classes must inherit from the base as: | ||||
|  | ||||
| ```cpp | ||||
| struct my_emitter: emitter<my_emitter> { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Handlers for the different events are created internally on the fly. It's not | ||||
| required to specify in advance the full list of accepted events.<br/> | ||||
| Moreover, whenever an event is published, an emitter also passes a reference | ||||
| to itself to its listeners. | ||||
|  | ||||
| To create new instances of an emitter, no arguments are required: | ||||
|  | ||||
| ```cpp | ||||
| my_emitter emitter{}; | ||||
| ``` | ||||
|  | ||||
| Listeners are movable and callable objects (free functions, lambdas, functors, | ||||
| `std::function`s, whatever) whose function type is compatible with: | ||||
|  | ||||
| ```cpp | ||||
| void(Type &, my_emitter &) | ||||
| ``` | ||||
|  | ||||
| Where `Type` is the type of event they want to receive.<br/> | ||||
| To attach a listener to an emitter, there exists the `on` member function: | ||||
|  | ||||
| ```cpp | ||||
| emitter.on<my_event>([](const my_event &event, my_emitter &emitter) { | ||||
|     // ... | ||||
| }); | ||||
| ``` | ||||
|  | ||||
| Similarly, the `reset` member function is used to disconnect listeners given a | ||||
| type while `clear` is used to disconnect all listeners at once: | ||||
|  | ||||
| ```cpp | ||||
| // resets the listener for my_event | ||||
| emitter.erase<my_event>(); | ||||
|  | ||||
| // resets all listeners | ||||
| emitter.clear() | ||||
| ``` | ||||
|  | ||||
| To send an event to the listener registered on a given type, the `publish` | ||||
| function is the way to go: | ||||
|  | ||||
| ```cpp | ||||
| struct my_event { int i; }; | ||||
|  | ||||
| // ... | ||||
|  | ||||
| emitter.publish(my_event{42}); | ||||
| ``` | ||||
|  | ||||
| Finally, the `empty` member function tests if there exists at least a listener | ||||
| registered with the event emitter while `contains` is used to check if a given | ||||
| event type is associated with a valid listener: | ||||
|  | ||||
| ```cpp | ||||
| if(emitter.contains<my_event>()) { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| This class introduces a _nice-to-have_ model based on events and listeners.<br/> | ||||
| More in general, it's a handy tool when the derived classes _wrap_ asynchronous | ||||
| operations but it's not limited to such uses. | ||||
							
								
								
									
										107
									
								
								external/entt/entt/docs/md/unreal.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								external/entt/entt/docs/md/unreal.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | ||||
| # EnTT and Unreal Engine | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Enable Cpp17](#enable-cpp17) | ||||
| * [EnTT as a third party module](#entt-as-a-third-party-module) | ||||
| * [Include EnTT](#include-entt) | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| ## Enable Cpp17 | ||||
|  | ||||
| As of writing (Unreal Engine v4.25), the default C++ standard of Unreal Engine | ||||
| is C++14.<br/> | ||||
| On the other hand, note that `EnTT` requires C++17 to compile. To enable it, in | ||||
| the main module of the project there should be a `<Game Name>.Build.cs` file, | ||||
| the constructor of which must contain the following lines: | ||||
|  | ||||
| ```cs | ||||
| PCHUsage = PCHUsageMode.NoSharedPCHs; | ||||
| PrivatePCHHeaderFile = "<PCH filename>.h"; | ||||
| CppStandard = CppStandardVersion.Cpp17; | ||||
| ``` | ||||
|  | ||||
| Replace `<PCH filename>.h` with the name of the already existing PCH header | ||||
| file, if any.<br/> | ||||
| In case the project doesn't already contain a file of this type, it's possible | ||||
| to create one with the following content: | ||||
|  | ||||
| ```cpp | ||||
| #pragma once | ||||
| #include "CoreMinimal.h" | ||||
| ``` | ||||
|  | ||||
| Remember to remove any old `PCHUsage = <...>` line that was previously there. At | ||||
| this point, C++17 support should be in place.<br/> | ||||
| Try to compile the project to ensure it works as expected before following | ||||
| further steps. | ||||
|  | ||||
| Note that updating a *project* to C++17 doesn't necessarily mean that the IDE in | ||||
| use will also start to recognize its syntax.<br/> | ||||
| If the plan is to use C++17 in the project too, check the specific instructions | ||||
| for the IDE in use. | ||||
|  | ||||
| ## EnTT as a third party module | ||||
|  | ||||
| Once this point is reached, the `Source` directory should look like this: | ||||
|  | ||||
| ``` | ||||
| Source | ||||
| |  MyGame.Target.cs | ||||
| |  MyGameEditor.Target.cs | ||||
| | | ||||
| +---MyGame | ||||
| |  |  MyGame.Build.cs | ||||
| |  |  MyGame.h (PCH Header file) | ||||
| | | ||||
| \---ThirdParty | ||||
|    \---EnTT | ||||
|       |   EnTT.Build.cs | ||||
|       | | ||||
|       \---entt (GitHub repository content inside) | ||||
| ``` | ||||
|  | ||||
| To make this happen, create the folder `ThirdParty` under `Source` if it doesn't | ||||
| exist already. Then, add an `EnTT` folder under `ThirdParty`.<br/> | ||||
| Within the latter, create a new file `EnTT.Build.cs` with the following content: | ||||
|  | ||||
| ```cs | ||||
| using System.IO; | ||||
| using UnrealBuildTool; | ||||
|  | ||||
| public class EnTT: ModuleRules { | ||||
|     public EnTT(ReadOnlyTargetRules Target) : base(Target) { | ||||
|         Type = ModuleType.External; | ||||
|         PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "entt", "src", "entt")); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The last line indicates that the actual files will be found in the directory | ||||
| `EnTT/entt/src/entt`.<br/> | ||||
| Download the repository for `EnTT` and place it next to `EnTT.Build.cs` or | ||||
| update the path above accordingly. | ||||
|  | ||||
| Finally, open the `<Game Name>.Build.cs` file and add `EnTT` as a dependency at | ||||
| the end of the list: | ||||
|  | ||||
| ```cs | ||||
| PublicDependencyModuleNames.AddRange(new[] { | ||||
|     "Core", "CoreUObject", "Engine", "InputCore", [...], "EnTT" | ||||
| }); | ||||
| ``` | ||||
|  | ||||
| Note that some IDEs might require a restart to start recognizing the new module | ||||
| for code-highlighting features and such. | ||||
|  | ||||
| ## Include EnTT | ||||
|  | ||||
| In any source file of the project, add `#include "entt.hpp"` or any other path | ||||
| to the file from `EnTT` to use it.<br/> | ||||
| Try to create a registry as `entt::registry registry;` to make sure everything | ||||
| compiles fine. | ||||
							
								
								
									
										34
									
								
								external/entt/entt/entt.imp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								external/entt/entt/entt.imp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| [ | ||||
|   { "include": [ "@<gtest/internal/.*>", "private", "<gtest/gtest.h>", "public" ] }, | ||||
|   { "include": [ "@<gtest/gtest-.*>", "private", "<gtest/gtest.h>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/container/fwd.hpp[\">]", "private", "<entt/container/dense_map.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/container/fwd.hpp[\">]", "private", "<entt/container/dense_set.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/any.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/family.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/hashed_string.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/ident.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/monostate.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/type_info.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/type_traits.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/entity.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/group.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/handle.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/helper.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/observer.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/organizer.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/registry.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/runtime_view.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/snapshot.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/sparse_set.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/storage.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/view.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/meta/fwd.hpp[\">]", "private", "<entt/meta/meta.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/poly/fwd.hpp[\">]", "private", "<entt/poly/poly.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/cache.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/loader.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/resource.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/delegate.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/dispatcher.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/emitter.hpp>", "public" ] }, | ||||
|   { "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/sigh.hpp>", "public" ] } | ||||
| ] | ||||
							
								
								
									
										3
									
								
								external/entt/entt/natvis/entt/config.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								external/entt/entt/natvis/entt/config.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||||
| </AutoVisualizer> | ||||
							
								
								
									
										33
									
								
								external/entt/entt/natvis/entt/container.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								external/entt/entt/natvis/entt/container.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||||
| 	<Type Name="entt::dense_map<*>"> | ||||
| 		<Intrinsic Name="size" Expression="packed.first_base::value.size()"/> | ||||
| 		<Intrinsic Name="bucket_count" Expression="sparse.first_base::value.size()"/> | ||||
| 		<DisplayString>{{ size={ size() } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[capacity]" ExcludeView="simple">packed.first_base::value.capacity()</Item> | ||||
| 			<Item Name="[bucket_count]" ExcludeView="simple">bucket_count()</Item> | ||||
| 			<Item Name="[load_factor]" ExcludeView="simple">(float)size() / (float)bucket_count()</Item> | ||||
| 			<Item Name="[max_load_factor]" ExcludeView="simple">threshold</Item> | ||||
| 			<IndexListItems> | ||||
| 				<Size>size()</Size> | ||||
| 				<ValueNode>packed.first_base::value[$i].element</ValueNode> | ||||
| 			</IndexListItems> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::dense_set<*>"> | ||||
| 		<Intrinsic Name="size" Expression="packed.first_base::value.size()"/> | ||||
| 		<Intrinsic Name="bucket_count" Expression="sparse.first_base::value.size()"/> | ||||
| 		<DisplayString>{{ size={ size() } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[capacity]" ExcludeView="simple">packed.first_base::value.capacity()</Item> | ||||
| 			<Item Name="[bucket_count]" ExcludeView="simple">bucket_count()</Item> | ||||
| 			<Item Name="[load_factor]" ExcludeView="simple">(float)size() / (float)bucket_count()</Item> | ||||
| 			<Item Name="[max_load_factor]" ExcludeView="simple">threshold</Item> | ||||
| 			<IndexListItems> | ||||
| 				<Size>size()</Size> | ||||
| 				<ValueNode>packed.first_base::value[$i].second</ValueNode> | ||||
| 			</IndexListItems> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| </AutoVisualizer> | ||||
							
								
								
									
										32
									
								
								external/entt/entt/natvis/entt/core.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								external/entt/entt/natvis/entt/core.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||||
|     <Type Name="entt::basic_any<*>"> | ||||
| 		<DisplayString>{{ type={ info->alias,na }, policy={ mode,en } }}</DisplayString> | ||||
|     </Type> | ||||
| 	<Type Name="entt::compressed_pair<*>"> | ||||
| 		<Intrinsic Name="first" Optional="true" Expression="((first_base*)this)->value"/> | ||||
| 		<Intrinsic Name="first" Optional="true" Expression="*(first_base::base_type*)this"/> | ||||
| 		<Intrinsic Name="second" Optional="true" Expression="((second_base*)this)->value"/> | ||||
| 		<Intrinsic Name="second" Optional="true" Expression="*(second_base::base_type*)this"/> | ||||
| 		<DisplayString >({ first() }, { second() })</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[first]">first()</Item> | ||||
| 			<Item Name="[second]">second()</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::basic_hashed_string<*>"> | ||||
| 		<DisplayString Condition="base_type::repr != nullptr">{{ hash={ base_type::hash } }}</DisplayString> | ||||
| 		<DisplayString>{{}}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[data]">base_type::repr,na</Item> | ||||
| 			<Item Name="[length]">base_type::length</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::type_info"> | ||||
| 		<DisplayString>{{ name={ alias,na } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[hash]">identifier</Item> | ||||
| 			<Item Name="[index]">seq</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| </AutoVisualizer> | ||||
							
								
								
									
										153
									
								
								external/entt/entt/natvis/entt/entity.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								external/entt/entt/natvis/entt/entity.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||||
| 	<Type Name="entt::basic_registry<*>"> | ||||
| 		<Intrinsic Name="pools_size" Expression="pools.packed.first_base::value.size()"/> | ||||
| 		<Intrinsic Name="vars_size" Expression="vars.ctx.packed.first_base::value.size()"/> | ||||
| 		<Intrinsic Name="to_entity" Expression="*((entity_traits::entity_type *)&entity) & entity_traits::entity_mask"> | ||||
| 			<Parameter Name="entity" Type="entity_traits::value_type &"/> | ||||
| 		</Intrinsic> | ||||
| 		<DisplayString>{{ size={ epool.size() } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item IncludeView="simple" Name="[epool]">epool,view(simple)nr</Item> | ||||
| 			<Synthetic Name="[epool]" ExcludeView="simple"> | ||||
| 				<DisplayString>{ epool.size() }</DisplayString> | ||||
| 				<Expand> | ||||
| 					<CustomListItems> | ||||
| 						<Variable Name="pos" InitialValue="0" /> | ||||
| 						<Variable Name="last" InitialValue="epool.size()"/> | ||||
| 						<Loop> | ||||
| 							<Break Condition="pos == last"/> | ||||
| 							<If Condition="to_entity(epool[pos]) == pos"> | ||||
| 								<Item Name="[{ pos }]">epool[pos]</Item> | ||||
| 							</If> | ||||
| 							<Exec>++pos</Exec> | ||||
| 						</Loop> | ||||
| 					</CustomListItems> | ||||
| 				</Expand> | ||||
| 			</Synthetic> | ||||
| 			<Synthetic Name="[destroyed]" ExcludeView="simple"> | ||||
| 				<DisplayString>{ to_entity(free_list) != entity_traits::entity_mask }</DisplayString> | ||||
| 				<Expand> | ||||
| 					<CustomListItems> | ||||
| 						<Variable Name="it" InitialValue="to_entity(free_list)" /> | ||||
| 						<Loop> | ||||
| 							<Break Condition="it == entity_traits::entity_mask"/> | ||||
| 							<Item Name="[{ it }]">epool[it]</Item> | ||||
| 							<Exec>it = to_entity(epool[it])</Exec> | ||||
| 						</Loop> | ||||
| 					</CustomListItems> | ||||
| 				</Expand> | ||||
| 			</Synthetic> | ||||
| 			<Synthetic Name="[pools]"> | ||||
| 				<DisplayString>{ pools_size() }</DisplayString> | ||||
| 				<Expand> | ||||
| 					<IndexListItems ExcludeView="simple"> | ||||
| 						<Size>pools_size()</Size> | ||||
| 						<ValueNode>*pools.packed.first_base::value[$i].element.second</ValueNode> | ||||
| 					</IndexListItems> | ||||
| 					<IndexListItems IncludeView="simple"> | ||||
| 						<Size>pools_size()</Size> | ||||
| 						<ValueNode>*pools.packed.first_base::value[$i].element.second,view(simple)</ValueNode> | ||||
| 					</IndexListItems> | ||||
| 				</Expand> | ||||
| 			</Synthetic> | ||||
| 			<Item Name="[groups]" ExcludeView="simple">groups.size()</Item> | ||||
| 			<Synthetic Name="[vars]"> | ||||
| 				<DisplayString>{ vars_size() }</DisplayString> | ||||
| 				<Expand> | ||||
| 					<IndexListItems> | ||||
| 						<Size>vars_size()</Size> | ||||
| 						<ValueNode>vars.ctx.packed.first_base::value[$i].element.second</ValueNode> | ||||
| 					</IndexListItems> | ||||
| 				</Expand> | ||||
| 			</Synthetic> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::basic_sparse_set<*>"> | ||||
| 		<DisplayString>{{ size={ packed.size() }, type={ info->alias,na } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[capacity]" ExcludeView="simple">packed.capacity()</Item> | ||||
| 			<Item Name="[policy]">mode,en</Item> | ||||
| 			<Synthetic Name="[sparse]"> | ||||
| 				<DisplayString>{ sparse.size() * entity_traits::page_size }</DisplayString> | ||||
| 				<Expand> | ||||
| 					<ExpandedItem IncludeView="simple">sparse,view(simple)</ExpandedItem> | ||||
| 					<CustomListItems ExcludeView="simple"> | ||||
| 						<Variable Name="pos" InitialValue="0"/> | ||||
| 						<Variable Name="page" InitialValue="0"/> | ||||
| 						<Variable Name="offset" InitialValue="0"/> | ||||
| 						<Variable Name="last" InitialValue="sparse.size() * entity_traits::page_size"/> | ||||
| 						<Loop> | ||||
| 							<Break Condition="pos == last"/> | ||||
| 							<Exec>page = pos / entity_traits::page_size</Exec> | ||||
| 							<Exec>offset = pos & (entity_traits::page_size - 1)</Exec> | ||||
| 							<If Condition="sparse[page] && (*((entity_traits::entity_type *)&sparse[page][offset]) < ~entity_traits::entity_mask)"> | ||||
| 								<Item Name="[{ pos }]">*((entity_traits::entity_type *)&sparse[page][offset]) & entity_traits::entity_mask</Item> | ||||
| 							</If> | ||||
| 							<Exec>++pos</Exec> | ||||
| 						</Loop> | ||||
| 					</CustomListItems> | ||||
| 				</Expand> | ||||
| 			</Synthetic> | ||||
| 			<Synthetic Name="[packed]"> | ||||
| 				<DisplayString>{ packed.size() }</DisplayString> | ||||
| 				<Expand> | ||||
| 					<ExpandedItem IncludeView="simple">packed,view(simple)</ExpandedItem> | ||||
| 					<CustomListItems ExcludeView="simple"> | ||||
| 						<Variable Name="pos" InitialValue="0"/> | ||||
| 						<Variable Name="last" InitialValue="packed.size()"/> | ||||
| 						<Loop> | ||||
| 							<Break Condition="pos == last"/> | ||||
| 							<If Condition="*((entity_traits::entity_type *)&packed[pos]) < ~entity_traits::entity_mask"> | ||||
| 								<Item Name="[{ pos }]">packed[pos]</Item> | ||||
| 							</If> | ||||
| 							<Exec>++pos</Exec> | ||||
| 						</Loop> | ||||
| 					</CustomListItems> | ||||
| 				</Expand> | ||||
| 			</Synthetic> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::basic_storage<*>"> | ||||
| 		<DisplayString>{{ size={ base_type::packed.size() }, type={ base_type::info->alias,na } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[capacity]" Optional="true" ExcludeView="simple">packed.first_base::value.capacity() * comp_traits::page_size</Item> | ||||
| 			<Item Name="[page size]" Optional="true" ExcludeView="simple">comp_traits::page_size</Item> | ||||
| 			<Item Name="[base]" ExcludeView="simple">(base_type*)this,nand</Item> | ||||
| 			<Item Name="[base]" IncludeView="simple">(base_type*)this,view(simple)nand</Item> | ||||
| 			<!-- having SFINAE-like techniques in natvis is priceless :) --> | ||||
| 			<CustomListItems Condition="packed.first_base::value.size() != 0" Optional="true"> | ||||
| 				<Variable Name="pos" InitialValue="0" /> | ||||
| 				<Variable Name="last" InitialValue="base_type::packed.size()"/> | ||||
| 				<Loop> | ||||
| 					<Break Condition="pos == last"/> | ||||
| 					<If Condition="*((base_type::entity_traits::entity_type *)&base_type::packed[pos]) < ~base_type::entity_traits::entity_mask"> | ||||
| 						<Item Name="[{ pos }:{ base_type::packed[pos] }]">packed.first_base::value[pos / comp_traits::page_size][pos & (comp_traits::page_size - 1)]</Item> | ||||
| 					</If> | ||||
| 					<Exec>++pos</Exec> | ||||
| 				</Loop> | ||||
| 			</CustomListItems> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::basic_view<*>"> | ||||
| 		<DisplayString>{{ size_hint={ view->packed.size() } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[pools]">pools,na</Item> | ||||
| 			<Item Name="[filter]">filter,na</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::basic_runtime_view<*>"> | ||||
| 		<DisplayString Condition="pools.size() != 0u">{{ size_hint={ pools[0]->packed.size() } }}</DisplayString> | ||||
| 		<DisplayString>{{ size_hint=0 }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[pools]">pools,na</Item> | ||||
| 			<Item Name="[filter]">filter,na</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::null_t"> | ||||
| 		<DisplayString><null></DisplayString> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::tombstone_t"> | ||||
| 		<DisplayString><tombstone></DisplayString> | ||||
| 	</Type> | ||||
| </AutoVisualizer> | ||||
							
								
								
									
										19
									
								
								external/entt/entt/natvis/entt/graph.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								external/entt/entt/natvis/entt/graph.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||||
|     <Type Name="entt::adjacency_matrix<*>"> | ||||
| 		<DisplayString>{{ size={ vert } }}</DisplayString> | ||||
|         <Expand> | ||||
| 			<CustomListItems> | ||||
| 				<Variable Name="pos" InitialValue="0" /> | ||||
| 				<Variable Name="last" InitialValue="vert * vert"/> | ||||
| 				<Loop> | ||||
| 					<Break Condition="pos == last"/> | ||||
| 					<If Condition="matrix[pos] != 0u"> | ||||
| 						<Item Name="{pos / vert}">pos % vert</Item> | ||||
| 					</If> | ||||
| 					<Exec>++pos</Exec> | ||||
| 				</Loop> | ||||
| 			</CustomListItems> | ||||
|         </Expand> | ||||
|     </Type> | ||||
| </AutoVisualizer> | ||||
							
								
								
									
										3
									
								
								external/entt/entt/natvis/entt/locator.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								external/entt/entt/natvis/entt/locator.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||||
| </AutoVisualizer> | ||||
							
								
								
									
										121
									
								
								external/entt/entt/natvis/entt/meta.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								external/entt/entt/natvis/entt/meta.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||||
| 	<Type Name="entt::internal::meta_base_node"> | ||||
| 		<DisplayString>{{}}</DisplayString> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::internal::meta_conv_node"> | ||||
| 		<DisplayString>{{}}</DisplayString> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::internal::meta_ctor_node"> | ||||
| 		<DisplayString>{{ arity={ arity } }}</DisplayString> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::internal::meta_data_node"> | ||||
| 		<Intrinsic Name="has_property" Expression="!!(traits & property)"> | ||||
| 			<Parameter Name="property" Type="int"/> | ||||
| 		</Intrinsic> | ||||
| 		<DisplayString>{{ arity={ arity } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[arity]">arity</Item> | ||||
| 			<Item Name="[is_const]">has_property(entt::internal::meta_traits::is_const)</Item> | ||||
| 			<Item Name="[is_static]">has_property(entt::internal::meta_traits::is_static)</Item> | ||||
| 			<Item Name="[prop]">prop</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::internal::meta_func_node"	> | ||||
| 		<Intrinsic Name="has_property" Expression="!!(traits & property)"> | ||||
| 			<Parameter Name="property" Type="int"/> | ||||
| 		</Intrinsic> | ||||
| 		<DisplayString>{{ arity={ arity } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[is_const]">has_property(entt::internal::meta_traits::is_const)</Item> | ||||
| 			<Item Name="[is_static]">has_property(entt::internal::meta_traits::is_static)</Item> | ||||
| 			<Item Name="[next]" Condition="next != nullptr">*next</Item> | ||||
| 			<Item Name="[prop]">prop</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::internal::meta_prop_node"> | ||||
| 		<DisplayString>{ value }</DisplayString> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::internal::meta_template_node"> | ||||
| 		<DisplayString>{{ arity={ arity } }}</DisplayString> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::internal::meta_type_node"> | ||||
| 		<Intrinsic Name="has_property" Expression="!!(traits & property)"> | ||||
| 			<Parameter Name="property" Type="int"/> | ||||
| 		</Intrinsic> | ||||
| 		<DisplayString Condition="info != nullptr">{{ type={ info->alias,na } }}</DisplayString> | ||||
| 		<DisplayString>{{}}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[id]">id</Item> | ||||
| 			<Item Name="[sizeof]">size_of</Item> | ||||
| 			<Item Name="[is_arithmetic]">has_property(entt::internal::meta_traits::is_arithmetic)</Item> | ||||
| 			<Item Name="[is_integral]">has_property(entt::internal::meta_traits::is_integral)</Item> | ||||
| 			<Item Name="[is_signed]">has_property(entt::internal::meta_traits::is_signed)</Item> | ||||
| 			<Item Name="[is_array]">has_property(entt::internal::meta_traits::is_array)</Item> | ||||
| 			<Item Name="[is_enum]">has_property(entt::internal::meta_traits::is_enum)</Item> | ||||
| 			<Item Name="[is_class]">has_property(entt::internal::meta_traits::is_class)</Item> | ||||
| 			<Item Name="[is_meta_pointer_like]">has_property(entt::internal::meta_traits::is_meta_pointer_like)</Item> | ||||
| 			<Item Name="[is_meta_sequence_container]">has_property(entt::internal::meta_traits::is_meta_sequence_container)</Item> | ||||
| 			<Item Name="[is_meta_associative_container]">has_property(entt::internal::meta_traits::is_meta_associative_container)</Item> | ||||
| 			<Item Name="[default_constructor]">default_constructor != nullptr</Item> | ||||
| 			<Item Name="[conversion_helper]">conversion_helper != nullptr</Item> | ||||
| 			<Item Name="[from_void]">from_void != nullptr</Item> | ||||
| 			<Item Name="[template_info]">templ</Item> | ||||
| 			<Item Name="[details]" Condition="details != nullptr">*details</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::meta_any"> | ||||
| 		<DisplayString Condition="node.info != nullptr">{{ type={ node.info->alias,na }, policy={ storage.mode,en } }}</DisplayString> | ||||
| 		<DisplayString>{{}}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<ExpandedItem>node</ExpandedItem> | ||||
| 			<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::meta_handle"> | ||||
| 		<DisplayString>{ any }</DisplayString> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::meta_associative_container"> | ||||
| 		<DisplayString>{ storage }</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::meta_sequence_container"> | ||||
| 		<DisplayString>{ storage }</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::meta_data"> | ||||
| 		<DisplayString Condition="node != nullptr">{ *node }</DisplayString> | ||||
| 		<DisplayString>{{}}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<ExpandedItem Condition="node != nullptr">node</ExpandedItem> | ||||
| 			<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::meta_func"> | ||||
| 		<DisplayString Condition="node != nullptr">{ *node }</DisplayString> | ||||
| 		<DisplayString>{{}}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<ExpandedItem Condition="node != nullptr">node</ExpandedItem> | ||||
| 			<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::meta_prop"> | ||||
| 		<DisplayString Condition="node != nullptr">{ *node }</DisplayString> | ||||
| 		<DisplayString>{{}}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<ExpandedItem Condition="node != nullptr">node</ExpandedItem> | ||||
| 			<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::meta_type"> | ||||
| 		<DisplayString>{ node }</DisplayString> | ||||
| 		<Expand> | ||||
| 			<ExpandedItem>node</ExpandedItem> | ||||
| 			<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| </AutoVisualizer> | ||||
							
								
								
									
										3
									
								
								external/entt/entt/natvis/entt/platform.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								external/entt/entt/natvis/entt/platform.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||||
| </AutoVisualizer> | ||||
							
								
								
									
										6
									
								
								external/entt/entt/natvis/entt/poly.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								external/entt/entt/natvis/entt/poly.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||||
| 	<Type Name="entt::basic_poly<*>"> | ||||
| 		<DisplayString>{ storage }</DisplayString> | ||||
| 	</Type> | ||||
| </AutoVisualizer> | ||||
							
								
								
									
										3
									
								
								external/entt/entt/natvis/entt/process.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								external/entt/entt/natvis/entt/process.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||||
| </AutoVisualizer> | ||||
							
								
								
									
										15
									
								
								external/entt/entt/natvis/entt/resource.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								external/entt/entt/natvis/entt/resource.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||||
| 	<Type Name="entt::resource<*>"> | ||||
| 		<DisplayString>{ value }</DisplayString> | ||||
| 		<Expand> | ||||
| 			<ExpandedItem>value</ExpandedItem> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::resource_cache<*>"> | ||||
| 		<DisplayString>{ pool.first_base::value }</DisplayString> | ||||
| 		<Expand> | ||||
| 			<ExpandedItem>pool.first_base::value</ExpandedItem> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| </AutoVisualizer> | ||||
							
								
								
									
										56
									
								
								external/entt/entt/natvis/entt/signal.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								external/entt/entt/natvis/entt/signal.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||||
| 	<Type Name="entt::delegate<*>"> | ||||
| 		<DisplayString>{{ type={ "$T1" } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[empty]">fn == nullptr</Item> | ||||
| 			<Item Name="[data]">instance</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::basic_dispatcher<*>"> | ||||
| 		<Intrinsic Name="size" Expression="pools.first_base::value.packed.first_base::value.size()"/> | ||||
| 		<DisplayString>{{ size={ size() } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Synthetic Name="[pools]"> | ||||
| 				<DisplayString>{ size() }</DisplayString> | ||||
| 				<Expand> | ||||
| 					<IndexListItems> | ||||
| 						<Size>size()</Size> | ||||
| 						<ValueNode>*pools.first_base::value.packed.first_base::value[$i].element.second</ValueNode> | ||||
| 					</IndexListItems> | ||||
| 				</Expand> | ||||
| 			</Synthetic> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::internal::dispatcher_handler<*>"> | ||||
| 		<DisplayString>{{ size={ events.size() }, event={ "$T1" } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[signal]">signal</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::emitter<*>"> | ||||
| 		<DisplayString>{{ size={ handlers.first_base::value.packed.first_base::value.size() } }}</DisplayString> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::connection"> | ||||
| 		<DisplayString>{{ bound={ signal != nullptr } }}</DisplayString> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::scoped_connection"> | ||||
| 		<DisplayString>{ conn }</DisplayString> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::sigh<*>"> | ||||
| 		<DisplayString>{{ size={ calls.size() }, type={ "$T1" } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<IndexListItems> | ||||
| 				<Size>calls.size()</Size> | ||||
| 				<ValueNode>calls[$i]</ValueNode> | ||||
| 			</IndexListItems> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| 	<Type Name="entt::sink<*>"> | ||||
| 		<DisplayString>{{ type={ "$T1" } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[signal]">signal,na</Item> | ||||
| 			<Item Name="[offset]">offset</Item> | ||||
| 		</Expand> | ||||
| 	</Type> | ||||
| </AutoVisualizer> | ||||
							
								
								
									
										299
									
								
								external/entt/entt/scripts/amalgamate.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								external/entt/entt/scripts/amalgamate.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,299 @@ | ||||
| #!/usr/bin/env python | ||||
| # coding=utf-8 | ||||
|  | ||||
| # amalgamate.py - Amalgamate C source and header files. | ||||
| # Copyright (c) 2012, Erik Edlund <erik.edlund@32767.se> | ||||
| #  | ||||
| # Redistribution and use in source and binary forms, with or without modification, | ||||
| # are permitted provided that the following conditions are met: | ||||
| #  | ||||
| #  * Redistributions of source code must retain the above copyright notice, | ||||
| #  this list of conditions and the following disclaimer. | ||||
| #  | ||||
| #  * Redistributions in binary form must reproduce the above copyright notice, | ||||
| #  this list of conditions and the following disclaimer in the documentation | ||||
| #  and/or other materials provided with the distribution. | ||||
| #  | ||||
| #  * Neither the name of Erik Edlund, nor the names of its contributors may | ||||
| #  be used to endorse or promote products derived from this software without | ||||
| #  specific prior written permission. | ||||
| #  | ||||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||
| # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||||
| # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||||
| # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
| # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  | ||||
| from __future__ import division | ||||
| from __future__ import print_function | ||||
| from __future__ import unicode_literals | ||||
|  | ||||
| import argparse | ||||
| import datetime | ||||
| import json | ||||
| import os | ||||
| import re | ||||
|  | ||||
|  | ||||
| class Amalgamation(object): | ||||
|  | ||||
|     # Prepends self.source_path to file_path if needed. | ||||
|     def actual_path(self, file_path): | ||||
|         if not os.path.isabs(file_path): | ||||
|             file_path = os.path.join(self.source_path, file_path) | ||||
|         return file_path | ||||
|  | ||||
|     # Search included file_path in self.include_paths and | ||||
|     # in source_dir if specified. | ||||
|     def find_included_file(self, file_path, source_dir): | ||||
|         search_dirs = self.include_paths[:] | ||||
|         if source_dir: | ||||
|             search_dirs.insert(0, source_dir) | ||||
|  | ||||
|         for search_dir in search_dirs: | ||||
|             search_path = os.path.join(search_dir, file_path) | ||||
|             if os.path.isfile(self.actual_path(search_path)): | ||||
|                 return search_path | ||||
|         return None | ||||
|  | ||||
|     def __init__(self, args): | ||||
|         with open(args.config, 'r') as f: | ||||
|             config = json.loads(f.read()) | ||||
|             for key in config: | ||||
|                 setattr(self, key, config[key]) | ||||
|  | ||||
|             self.verbose = args.verbose == "yes" | ||||
|             self.prologue = args.prologue | ||||
|             self.source_path = args.source_path | ||||
|             self.included_files = [] | ||||
|  | ||||
|     # Generate the amalgamation and write it to the target file. | ||||
|     def generate(self): | ||||
|         amalgamation = "" | ||||
|  | ||||
|         if self.prologue: | ||||
|             with open(self.prologue, 'r') as f: | ||||
|                 amalgamation += datetime.datetime.now().strftime(f.read()) | ||||
|  | ||||
|         if self.verbose: | ||||
|             print("Config:") | ||||
|             print(" target        = {0}".format(self.target)) | ||||
|             print(" working_dir   = {0}".format(os.getcwd())) | ||||
|             print(" include_paths = {0}".format(self.include_paths)) | ||||
|         print("Creating amalgamation:") | ||||
|         for file_path in self.sources: | ||||
|             # Do not check the include paths while processing the source | ||||
|             # list, all given source paths must be correct. | ||||
|             # actual_path = self.actual_path(file_path) | ||||
|             print(" - processing \"{0}\"".format(file_path)) | ||||
|             t = TranslationUnit(file_path, self, True) | ||||
|             amalgamation += t.content | ||||
|  | ||||
|         with open(self.target, 'w') as f: | ||||
|             f.write(amalgamation) | ||||
|  | ||||
|         print("...done!\n") | ||||
|         if self.verbose: | ||||
|             print("Files processed: {0}".format(self.sources)) | ||||
|             print("Files included: {0}".format(self.included_files)) | ||||
|         print("") | ||||
|  | ||||
|  | ||||
| def _is_within(match, matches): | ||||
|     for m in matches: | ||||
|         if match.start() > m.start() and \ | ||||
|                 match.end() < m.end(): | ||||
|             return True | ||||
|     return False | ||||
|  | ||||
|  | ||||
| class TranslationUnit(object): | ||||
|     # // C++ comment. | ||||
|     cpp_comment_pattern = re.compile(r"//.*?\n") | ||||
|  | ||||
|     # /* C comment. */ | ||||
|     c_comment_pattern = re.compile(r"/\*.*?\*/", re.S) | ||||
|  | ||||
|     # "complex \"stri\\\ng\" value". | ||||
|     string_pattern = re.compile("[^']" r'".*?(?<=[^\\])"', re.S) | ||||
|  | ||||
|     # Handle simple include directives. Support for advanced | ||||
|     # directives where macros and defines needs to expanded is | ||||
|     # not a concern right now. | ||||
|     include_pattern = re.compile( | ||||
|         r'#\s*include\s+(<|")(?P<path>.*?)("|>)', re.S) | ||||
|  | ||||
|     # #pragma once | ||||
|     pragma_once_pattern = re.compile(r'#\s*pragma\s+once', re.S) | ||||
|  | ||||
|     # Search for pattern in self.content, add the match to | ||||
|     # contexts if found and update the index accordingly. | ||||
|     def _search_content(self, index, pattern, contexts): | ||||
|         match = pattern.search(self.content, index) | ||||
|         if match: | ||||
|             contexts.append(match) | ||||
|             return match.end() | ||||
|         return index + 2 | ||||
|  | ||||
|     # Return all the skippable contexts, i.e., comments and strings | ||||
|     def _find_skippable_contexts(self): | ||||
|         # Find contexts in the content in which a found include | ||||
|         # directive should not be processed. | ||||
|         skippable_contexts = [] | ||||
|  | ||||
|         # Walk through the content char by char, and try to grab | ||||
|         # skippable contexts using regular expressions when found. | ||||
|         i = 1 | ||||
|         content_len = len(self.content) | ||||
|         while i < content_len: | ||||
|             j = i - 1 | ||||
|             current = self.content[i] | ||||
|             previous = self.content[j] | ||||
|  | ||||
|             if current == '"': | ||||
|                 # String value. | ||||
|                 i = self._search_content(j, self.string_pattern, | ||||
|                                          skippable_contexts) | ||||
|             elif current == '*' and previous == '/': | ||||
|                 # C style comment. | ||||
|                 i = self._search_content(j, self.c_comment_pattern, | ||||
|                                          skippable_contexts) | ||||
|             elif current == '/' and previous == '/': | ||||
|                 # C++ style comment. | ||||
|                 i = self._search_content(j, self.cpp_comment_pattern, | ||||
|                                          skippable_contexts) | ||||
|             else: | ||||
|                 # Skip to the next char. | ||||
|                 i += 1 | ||||
|  | ||||
|         return skippable_contexts | ||||
|  | ||||
|     # Returns True if the match is within list of other matches | ||||
|  | ||||
|     # Removes pragma once from content | ||||
|     def _process_pragma_once(self): | ||||
|         content_len = len(self.content) | ||||
|         if content_len < len("#include <x>"): | ||||
|             return 0 | ||||
|  | ||||
|         # Find contexts in the content in which a found include | ||||
|         # directive should not be processed. | ||||
|         skippable_contexts = self._find_skippable_contexts() | ||||
|  | ||||
|         pragmas = [] | ||||
|         pragma_once_match = self.pragma_once_pattern.search(self.content) | ||||
|         while pragma_once_match: | ||||
|             if not _is_within(pragma_once_match, skippable_contexts): | ||||
|                 pragmas.append(pragma_once_match) | ||||
|  | ||||
|             pragma_once_match = self.pragma_once_pattern.search(self.content, | ||||
|                                                                 pragma_once_match.end()) | ||||
|  | ||||
|         # Handle all collected pragma once directives. | ||||
|         prev_end = 0 | ||||
|         tmp_content = '' | ||||
|         for pragma_match in pragmas: | ||||
|             tmp_content += self.content[prev_end:pragma_match.start()] | ||||
|             prev_end = pragma_match.end() | ||||
|         tmp_content += self.content[prev_end:] | ||||
|         self.content = tmp_content | ||||
|  | ||||
|     # Include all trivial #include directives into self.content. | ||||
|     def _process_includes(self): | ||||
|         content_len = len(self.content) | ||||
|         if content_len < len("#include <x>"): | ||||
|             return 0 | ||||
|  | ||||
|         # Find contexts in the content in which a found include | ||||
|         # directive should not be processed. | ||||
|         skippable_contexts = self._find_skippable_contexts() | ||||
|  | ||||
|         # Search for include directives in the content, collect those | ||||
|         # which should be included into the content. | ||||
|         includes = [] | ||||
|         include_match = self.include_pattern.search(self.content) | ||||
|         while include_match: | ||||
|             if not _is_within(include_match, skippable_contexts): | ||||
|                 include_path = include_match.group("path") | ||||
|                 search_same_dir = include_match.group(1) == '"' | ||||
|                 found_included_path = self.amalgamation.find_included_file( | ||||
|                     include_path, self.file_dir if search_same_dir else None) | ||||
|                 if found_included_path: | ||||
|                     includes.append((include_match, found_included_path)) | ||||
|  | ||||
|             include_match = self.include_pattern.search(self.content, | ||||
|                                                         include_match.end()) | ||||
|  | ||||
|         # Handle all collected include directives. | ||||
|         prev_end = 0 | ||||
|         tmp_content = '' | ||||
|         for include in includes: | ||||
|             include_match, found_included_path = include | ||||
|             tmp_content += self.content[prev_end:include_match.start()] | ||||
|             tmp_content += "// {0}\n".format(include_match.group(0)) | ||||
|             if found_included_path not in self.amalgamation.included_files: | ||||
|                 t = TranslationUnit(found_included_path, self.amalgamation, False) | ||||
|                 tmp_content += t.content | ||||
|             prev_end = include_match.end() | ||||
|         tmp_content += self.content[prev_end:] | ||||
|         self.content = tmp_content | ||||
|  | ||||
|         return len(includes) | ||||
|  | ||||
|     # Make all content processing | ||||
|     def _process(self): | ||||
|         if not self.is_root: | ||||
|             self._process_pragma_once() | ||||
|         self._process_includes() | ||||
|  | ||||
|     def __init__(self, file_path, amalgamation, is_root): | ||||
|         self.file_path = file_path | ||||
|         self.file_dir = os.path.dirname(file_path) | ||||
|         self.amalgamation = amalgamation | ||||
|         self.is_root = is_root | ||||
|  | ||||
|         self.amalgamation.included_files.append(self.file_path) | ||||
|  | ||||
|         actual_path = self.amalgamation.actual_path(file_path) | ||||
|         if not os.path.isfile(actual_path): | ||||
|             raise IOError("File not found: \"{0}\"".format(file_path)) | ||||
|         with open(actual_path, 'r') as f: | ||||
|             self.content = f.read() | ||||
|             self._process() | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     description = "Amalgamate C source and header files." | ||||
|     usage = " ".join([ | ||||
|         "amalgamate.py", | ||||
|         "[-v]", | ||||
|         "-c path/to/config.json", | ||||
|         "-s path/to/source/dir", | ||||
|         "[-p path/to/prologue.(c|h)]" | ||||
|     ]) | ||||
|     argsparser = argparse.ArgumentParser( | ||||
|         description=description, usage=usage) | ||||
|  | ||||
|     argsparser.add_argument("-v", "--verbose", dest="verbose", | ||||
|                             choices=["yes", "no"], metavar="", help="be verbose") | ||||
|  | ||||
|     argsparser.add_argument("-c", "--config", dest="config", | ||||
|                             required=True, metavar="", help="path to a JSON config file") | ||||
|  | ||||
|     argsparser.add_argument("-s", "--source", dest="source_path", | ||||
|                             required=True, metavar="", help="source code path") | ||||
|  | ||||
|     argsparser.add_argument("-p", "--prologue", dest="prologue", | ||||
|                             required=False, metavar="", help="path to a C prologue file") | ||||
|  | ||||
|     amalgamation = Amalgamation(argsparser.parse_args()) | ||||
|     amalgamation.generate() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
							
								
								
									
										8
									
								
								external/entt/entt/scripts/config.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								external/entt/entt/scripts/config.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| { | ||||
| 	"project": "entt", | ||||
| 	"target": "single_include/entt/entt.hpp", | ||||
| 	"sources": [ | ||||
| 		"src/entt/entt.hpp" | ||||
| 	], | ||||
| 	"include_paths": ["src"] | ||||
| } | ||||
							
								
								
									
										60
									
								
								external/entt/entt/scripts/update_homebrew.sh
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										60
									
								
								external/entt/entt/scripts/update_homebrew.sh
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| # only argument should be the version to upgrade to | ||||
| if [ $# != 1 ] | ||||
| then | ||||
|   echo "Expected a version tag like v2.7.1" | ||||
|   exit 1 | ||||
| fi | ||||
|  | ||||
| VERSION="$1" | ||||
| URL="https://github.com/skypjack/entt/archive/$VERSION.tar.gz" | ||||
| FORMULA="entt.rb" | ||||
|  | ||||
| echo "Updating homebrew package to $VERSION" | ||||
|  | ||||
| echo "Cloning..." | ||||
| git clone https://github.com/skypjack/homebrew-entt.git | ||||
| if [ $? != 0 ] | ||||
| then | ||||
|   exit 1 | ||||
| fi | ||||
| cd homebrew-entt | ||||
|  | ||||
| # download the repo at the version | ||||
| # exit with error messages if curl fails | ||||
| echo "Curling..." | ||||
| curl "$URL" --location --fail --silent --show-error --output archive.tar.gz | ||||
| if [ $? != 0 ] | ||||
| then | ||||
|   exit 1 | ||||
| fi | ||||
|  | ||||
| # compute sha256 hash | ||||
| echo "Hashing..." | ||||
| HASH="$(openssl sha256 archive.tar.gz | cut -d " " -f 2)" | ||||
|  | ||||
| # delete the archive | ||||
| rm archive.tar.gz | ||||
|  | ||||
| echo "Sedding..." | ||||
|  | ||||
| # change the url in the formula file | ||||
| # the slashes in the URL must be escaped | ||||
| ESCAPED_URL="$(echo "$URL" | sed -e 's/[\/&]/\\&/g')" | ||||
| sed -i -e '/url/s/".*"/"'$ESCAPED_URL'"/' $FORMULA | ||||
|  | ||||
| # change the hash in the formula file | ||||
| sed -i -e '/sha256/s/".*"/"'$HASH'"/' $FORMULA | ||||
|  | ||||
| # delete temporary file created by sed | ||||
| rm -rf "$FORMULA-e" | ||||
|  | ||||
| # update remote repo | ||||
| echo "Gitting..." | ||||
| git add entt.rb | ||||
| git commit -m "Update to $VERSION" | ||||
| git push origin master | ||||
|  | ||||
| # out of homebrew-entt dir | ||||
| cd .. | ||||
							
								
								
									
										82838
									
								
								external/entt/entt/single_include/entt/entt.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82838
									
								
								external/entt/entt/single_include/entt/entt.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										81
									
								
								external/entt/entt/src/entt/config/config.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								external/entt/entt/src/entt/config/config.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| #ifndef ENTT_CONFIG_CONFIG_H | ||||
| #define ENTT_CONFIG_CONFIG_H | ||||
|  | ||||
| #include "version.h" | ||||
|  | ||||
| #if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) | ||||
| #    define ENTT_CONSTEXPR | ||||
| #    define ENTT_THROW throw | ||||
| #    define ENTT_TRY try | ||||
| #    define ENTT_CATCH catch(...) | ||||
| #else | ||||
| #    define ENTT_CONSTEXPR constexpr // use only with throwing functions (waiting for C++20) | ||||
| #    define ENTT_THROW | ||||
| #    define ENTT_TRY if(true) | ||||
| #    define ENTT_CATCH if(false) | ||||
| #endif | ||||
|  | ||||
| #ifdef ENTT_USE_ATOMIC | ||||
| #    include <atomic> | ||||
| #    define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type> | ||||
| #else | ||||
| #    define ENTT_MAYBE_ATOMIC(Type) Type | ||||
| #endif | ||||
|  | ||||
| #ifndef ENTT_ID_TYPE | ||||
| #    include <cstdint> | ||||
| #    define ENTT_ID_TYPE std::uint32_t | ||||
| #endif | ||||
|  | ||||
| #ifndef ENTT_SPARSE_PAGE | ||||
| #    define ENTT_SPARSE_PAGE 4096 | ||||
| #endif | ||||
|  | ||||
| #ifndef ENTT_PACKED_PAGE | ||||
| #    define ENTT_PACKED_PAGE 1024 | ||||
| #endif | ||||
|  | ||||
| #ifdef ENTT_DISABLE_ASSERT | ||||
| #    undef ENTT_ASSERT | ||||
| #    define ENTT_ASSERT(condition, msg) (void(0)) | ||||
| #elif !defined ENTT_ASSERT | ||||
| #    include <cassert> | ||||
| #    define ENTT_ASSERT(condition, msg) assert(condition) | ||||
| #endif | ||||
|  | ||||
| #ifdef ENTT_DISABLE_ASSERT | ||||
| #    undef ENTT_ASSERT_CONSTEXPR | ||||
| #    define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) | ||||
| #elif !defined ENTT_ASSERT_CONSTEXPR | ||||
| #    define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) | ||||
| #endif | ||||
|  | ||||
| #ifdef ENTT_NO_ETO | ||||
| #    define ENTT_ETO_TYPE(Type) void | ||||
| #else | ||||
| #    define ENTT_ETO_TYPE(Type) Type | ||||
| #endif | ||||
|  | ||||
| #ifdef ENTT_STANDARD_CPP | ||||
| #    define ENTT_NONSTD false | ||||
| #else | ||||
| #    define ENTT_NONSTD true | ||||
| #    if defined __clang__ || defined __GNUC__ | ||||
| #        define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ | ||||
| #        define ENTT_PRETTY_FUNCTION_PREFIX '=' | ||||
| #        define ENTT_PRETTY_FUNCTION_SUFFIX ']' | ||||
| #    elif defined _MSC_VER | ||||
| #        define ENTT_PRETTY_FUNCTION __FUNCSIG__ | ||||
| #        define ENTT_PRETTY_FUNCTION_PREFIX '<' | ||||
| #        define ENTT_PRETTY_FUNCTION_SUFFIX '>' | ||||
| #    endif | ||||
| #endif | ||||
|  | ||||
| #if defined _MSC_VER | ||||
| #    pragma detect_mismatch("entt.version", ENTT_VERSION) | ||||
| #    pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) | ||||
| #    pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) | ||||
| #    pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										7
									
								
								external/entt/entt/src/entt/config/macro.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								external/entt/entt/src/entt/config/macro.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #ifndef ENTT_CONFIG_MACRO_H | ||||
| #define ENTT_CONFIG_MACRO_H | ||||
|  | ||||
| #define ENTT_STR(arg) #arg | ||||
| #define ENTT_XSTR(arg) ENTT_STR(arg) | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										14
									
								
								external/entt/entt/src/entt/config/version.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								external/entt/entt/src/entt/config/version.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #ifndef ENTT_CONFIG_VERSION_H | ||||
| #define ENTT_CONFIG_VERSION_H | ||||
|  | ||||
| #include "macro.h" | ||||
|  | ||||
| #define ENTT_VERSION_MAJOR 3 | ||||
| #define ENTT_VERSION_MINOR 11 | ||||
| #define ENTT_VERSION_PATCH 1 | ||||
|  | ||||
| #define ENTT_VERSION \ | ||||
|     ENTT_XSTR(ENTT_VERSION_MAJOR) \ | ||||
|     "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1060
									
								
								external/entt/entt/src/entt/container/dense_map.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1060
									
								
								external/entt/entt/src/entt/container/dense_map.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										895
									
								
								external/entt/entt/src/entt/container/dense_set.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										895
									
								
								external/entt/entt/src/entt/container/dense_set.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,895 @@ | ||||
| #ifndef ENTT_CONTAINER_DENSE_SET_HPP | ||||
| #define ENTT_CONTAINER_DENSE_SET_HPP | ||||
|  | ||||
| #include <cmath> | ||||
| #include <cstddef> | ||||
| #include <functional> | ||||
| #include <iterator> | ||||
| #include <limits> | ||||
| #include <memory> | ||||
| #include <tuple> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include "../config/config.h" | ||||
| #include "../core/compressed_pair.hpp" | ||||
| #include "../core/memory.hpp" | ||||
| #include "../core/type_traits.hpp" | ||||
| #include "fwd.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename It> | ||||
| class dense_set_iterator final { | ||||
|     template<typename> | ||||
|     friend class dense_set_iterator; | ||||
|  | ||||
| public: | ||||
|     using value_type = typename It::value_type::second_type; | ||||
|     using pointer = const value_type *; | ||||
|     using reference = const value_type &; | ||||
|     using difference_type = std::ptrdiff_t; | ||||
|     using iterator_category = std::random_access_iterator_tag; | ||||
|  | ||||
|     constexpr dense_set_iterator() noexcept | ||||
|         : it{} {} | ||||
|  | ||||
|     constexpr dense_set_iterator(const It iter) noexcept | ||||
|         : it{iter} {} | ||||
|  | ||||
|     template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>> | ||||
|     constexpr dense_set_iterator(const dense_set_iterator<Other> &other) noexcept | ||||
|         : it{other.it} {} | ||||
|  | ||||
|     constexpr dense_set_iterator &operator++() noexcept { | ||||
|         return ++it, *this; | ||||
|     } | ||||
|  | ||||
|     constexpr dense_set_iterator operator++(int) noexcept { | ||||
|         dense_set_iterator orig = *this; | ||||
|         return ++(*this), orig; | ||||
|     } | ||||
|  | ||||
|     constexpr dense_set_iterator &operator--() noexcept { | ||||
|         return --it, *this; | ||||
|     } | ||||
|  | ||||
|     constexpr dense_set_iterator operator--(int) noexcept { | ||||
|         dense_set_iterator orig = *this; | ||||
|         return operator--(), orig; | ||||
|     } | ||||
|  | ||||
|     constexpr dense_set_iterator &operator+=(const difference_type value) noexcept { | ||||
|         it += value; | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     constexpr dense_set_iterator operator+(const difference_type value) const noexcept { | ||||
|         dense_set_iterator copy = *this; | ||||
|         return (copy += value); | ||||
|     } | ||||
|  | ||||
|     constexpr dense_set_iterator &operator-=(const difference_type value) noexcept { | ||||
|         return (*this += -value); | ||||
|     } | ||||
|  | ||||
|     constexpr dense_set_iterator operator-(const difference_type value) const noexcept { | ||||
|         return (*this + -value); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { | ||||
|         return it[value].second; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr pointer operator->() const noexcept { | ||||
|         return std::addressof(it->second); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr reference operator*() const noexcept { | ||||
|         return *operator->(); | ||||
|     } | ||||
|  | ||||
|     template<typename ILhs, typename IRhs> | ||||
|     friend constexpr std::ptrdiff_t operator-(const dense_set_iterator<ILhs> &, const dense_set_iterator<IRhs> &) noexcept; | ||||
|  | ||||
|     template<typename ILhs, typename IRhs> | ||||
|     friend constexpr bool operator==(const dense_set_iterator<ILhs> &, const dense_set_iterator<IRhs> &) noexcept; | ||||
|  | ||||
|     template<typename ILhs, typename IRhs> | ||||
|     friend constexpr bool operator<(const dense_set_iterator<ILhs> &, const dense_set_iterator<IRhs> &) noexcept; | ||||
|  | ||||
| private: | ||||
|     It it; | ||||
| }; | ||||
|  | ||||
| template<typename ILhs, typename IRhs> | ||||
| [[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept { | ||||
|     return lhs.it - rhs.it; | ||||
| } | ||||
|  | ||||
| template<typename ILhs, typename IRhs> | ||||
| [[nodiscard]] constexpr bool operator==(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept { | ||||
|     return lhs.it == rhs.it; | ||||
| } | ||||
|  | ||||
| template<typename ILhs, typename IRhs> | ||||
| [[nodiscard]] constexpr bool operator!=(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept { | ||||
|     return !(lhs == rhs); | ||||
| } | ||||
|  | ||||
| template<typename ILhs, typename IRhs> | ||||
| [[nodiscard]] constexpr bool operator<(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept { | ||||
|     return lhs.it < rhs.it; | ||||
| } | ||||
|  | ||||
| template<typename ILhs, typename IRhs> | ||||
| [[nodiscard]] constexpr bool operator>(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept { | ||||
|     return rhs < lhs; | ||||
| } | ||||
|  | ||||
| template<typename ILhs, typename IRhs> | ||||
| [[nodiscard]] constexpr bool operator<=(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept { | ||||
|     return !(lhs > rhs); | ||||
| } | ||||
|  | ||||
| template<typename ILhs, typename IRhs> | ||||
| [[nodiscard]] constexpr bool operator>=(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept { | ||||
|     return !(lhs < rhs); | ||||
| } | ||||
|  | ||||
| template<typename It> | ||||
| class dense_set_local_iterator final { | ||||
|     template<typename> | ||||
|     friend class dense_set_local_iterator; | ||||
|  | ||||
| public: | ||||
|     using value_type = typename It::value_type::second_type; | ||||
|     using pointer = const value_type *; | ||||
|     using reference = const value_type &; | ||||
|     using difference_type = std::ptrdiff_t; | ||||
|     using iterator_category = std::forward_iterator_tag; | ||||
|  | ||||
|     constexpr dense_set_local_iterator() noexcept | ||||
|         : it{}, | ||||
|           offset{} {} | ||||
|  | ||||
|     constexpr dense_set_local_iterator(It iter, const std::size_t pos) noexcept | ||||
|         : it{iter}, | ||||
|           offset{pos} {} | ||||
|  | ||||
|     template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>> | ||||
|     constexpr dense_set_local_iterator(const dense_set_local_iterator<Other> &other) noexcept | ||||
|         : it{other.it}, | ||||
|           offset{other.offset} {} | ||||
|  | ||||
|     constexpr dense_set_local_iterator &operator++() noexcept { | ||||
|         return offset = it[offset].first, *this; | ||||
|     } | ||||
|  | ||||
|     constexpr dense_set_local_iterator operator++(int) noexcept { | ||||
|         dense_set_local_iterator orig = *this; | ||||
|         return ++(*this), orig; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr pointer operator->() const noexcept { | ||||
|         return std::addressof(it[offset].second); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr reference operator*() const noexcept { | ||||
|         return *operator->(); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr std::size_t index() const noexcept { | ||||
|         return offset; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     It it; | ||||
|     std::size_t offset; | ||||
| }; | ||||
|  | ||||
| template<typename ILhs, typename IRhs> | ||||
| [[nodiscard]] constexpr bool operator==(const dense_set_local_iterator<ILhs> &lhs, const dense_set_local_iterator<IRhs> &rhs) noexcept { | ||||
|     return lhs.index() == rhs.index(); | ||||
| } | ||||
|  | ||||
| template<typename ILhs, typename IRhs> | ||||
| [[nodiscard]] constexpr bool operator!=(const dense_set_local_iterator<ILhs> &lhs, const dense_set_local_iterator<IRhs> &rhs) noexcept { | ||||
|     return !(lhs == rhs); | ||||
| } | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief Associative container for unique objects of a given type. | ||||
|  * | ||||
|  * Internally, elements are organized into buckets. Which bucket an element is | ||||
|  * placed into depends entirely on its hash. Elements with the same hash code | ||||
|  * appear in the same bucket. | ||||
|  * | ||||
|  * @tparam Type Value type of the associative container. | ||||
|  * @tparam Hash Type of function to use to hash the values. | ||||
|  * @tparam KeyEqual Type of function to use to compare the values for equality. | ||||
|  * @tparam Allocator Type of allocator used to manage memory and elements. | ||||
|  */ | ||||
| template<typename Type, typename Hash, typename KeyEqual, typename Allocator> | ||||
| class dense_set { | ||||
|     static constexpr float default_threshold = 0.875f; | ||||
|     static constexpr std::size_t minimum_capacity = 8u; | ||||
|  | ||||
|     using node_type = std::pair<std::size_t, Type>; | ||||
|     using alloc_traits = std::allocator_traits<Allocator>; | ||||
|     static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type"); | ||||
|     using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>; | ||||
|     using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>; | ||||
|  | ||||
|     template<typename Other> | ||||
|     [[nodiscard]] std::size_t value_to_bucket(const Other &value) const noexcept { | ||||
|         return fast_mod(static_cast<size_type>(sparse.second()(value)), bucket_count()); | ||||
|     } | ||||
|  | ||||
|     template<typename Other> | ||||
|     [[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) { | ||||
|         for(auto it = begin(bucket), last = end(bucket); it != last; ++it) { | ||||
|             if(packed.second()(*it, value)) { | ||||
|                 return begin() + static_cast<typename iterator::difference_type>(it.index()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return end(); | ||||
|     } | ||||
|  | ||||
|     template<typename Other> | ||||
|     [[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) const { | ||||
|         for(auto it = cbegin(bucket), last = cend(bucket); it != last; ++it) { | ||||
|             if(packed.second()(*it, value)) { | ||||
|                 return cbegin() + static_cast<typename iterator::difference_type>(it.index()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return cend(); | ||||
|     } | ||||
|  | ||||
|     template<typename Other> | ||||
|     [[nodiscard]] auto insert_or_do_nothing(Other &&value) { | ||||
|         const auto index = value_to_bucket(value); | ||||
|  | ||||
|         if(auto it = constrained_find(value, index); it != end()) { | ||||
|             return std::make_pair(it, false); | ||||
|         } | ||||
|  | ||||
|         packed.first().emplace_back(sparse.first()[index], std::forward<Other>(value)); | ||||
|         sparse.first()[index] = packed.first().size() - 1u; | ||||
|         rehash_if_required(); | ||||
|  | ||||
|         return std::make_pair(--end(), true); | ||||
|     } | ||||
|  | ||||
|     void move_and_pop(const std::size_t pos) { | ||||
|         if(const auto last = size() - 1u; pos != last) { | ||||
|             size_type *curr = sparse.first().data() + value_to_bucket(packed.first().back().second); | ||||
|             packed.first()[pos] = std::move(packed.first().back()); | ||||
|             for(; *curr != last; curr = &packed.first()[*curr].first) {} | ||||
|             *curr = pos; | ||||
|         } | ||||
|  | ||||
|         packed.first().pop_back(); | ||||
|     } | ||||
|  | ||||
|     void rehash_if_required() { | ||||
|         if(size() > (bucket_count() * max_load_factor())) { | ||||
|             rehash(bucket_count() * 2u); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! @brief Key type of the container. */ | ||||
|     using key_type = Type; | ||||
|     /*! @brief Value type of the container. */ | ||||
|     using value_type = Type; | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using size_type = std::size_t; | ||||
|     /*! @brief Type of function to use to hash the elements. */ | ||||
|     using hasher = Hash; | ||||
|     /*! @brief Type of function to use to compare the elements for equality. */ | ||||
|     using key_equal = KeyEqual; | ||||
|     /*! @brief Allocator type. */ | ||||
|     using allocator_type = Allocator; | ||||
|     /*! @brief Random access iterator type. */ | ||||
|     using iterator = internal::dense_set_iterator<typename packed_container_type::iterator>; | ||||
|     /*! @brief Constant random access iterator type. */ | ||||
|     using const_iterator = internal::dense_set_iterator<typename packed_container_type::const_iterator>; | ||||
|     /*! @brief Forward iterator type. */ | ||||
|     using local_iterator = internal::dense_set_local_iterator<typename packed_container_type::iterator>; | ||||
|     /*! @brief Constant forward iterator type. */ | ||||
|     using const_local_iterator = internal::dense_set_local_iterator<typename packed_container_type::const_iterator>; | ||||
|  | ||||
|     /*! @brief Default constructor. */ | ||||
|     dense_set() | ||||
|         : dense_set{minimum_capacity} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an empty container with a given allocator. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     explicit dense_set(const allocator_type &allocator) | ||||
|         : dense_set{minimum_capacity, hasher{}, key_equal{}, allocator} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an empty container with a given allocator and user | ||||
|      * supplied minimal number of buckets. | ||||
|      * @param cnt Minimal number of buckets. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     dense_set(const size_type cnt, const allocator_type &allocator) | ||||
|         : dense_set{cnt, hasher{}, key_equal{}, allocator} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an empty container with a given allocator, hash | ||||
|      * function and user supplied minimal number of buckets. | ||||
|      * @param cnt Minimal number of buckets. | ||||
|      * @param hash Hash function to use. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     dense_set(const size_type cnt, const hasher &hash, const allocator_type &allocator) | ||||
|         : dense_set{cnt, hash, key_equal{}, allocator} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an empty container with a given allocator, hash | ||||
|      * function, compare function and user supplied minimal number of buckets. | ||||
|      * @param cnt Minimal number of buckets. | ||||
|      * @param hash Hash function to use. | ||||
|      * @param equal Compare function to use. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     explicit dense_set(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{}) | ||||
|         : sparse{allocator, hash}, | ||||
|           packed{allocator, equal}, | ||||
|           threshold{default_threshold} { | ||||
|         rehash(cnt); | ||||
|     } | ||||
|  | ||||
|     /*! @brief Default copy constructor. */ | ||||
|     dense_set(const dense_set &) = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Allocator-extended copy constructor. | ||||
|      * @param other The instance to copy from. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     dense_set(const dense_set &other, const allocator_type &allocator) | ||||
|         : sparse{std::piecewise_construct, std::forward_as_tuple(other.sparse.first(), allocator), std::forward_as_tuple(other.sparse.second())}, | ||||
|           packed{std::piecewise_construct, std::forward_as_tuple(other.packed.first(), allocator), std::forward_as_tuple(other.packed.second())}, | ||||
|           threshold{other.threshold} {} | ||||
|  | ||||
|     /*! @brief Default move constructor. */ | ||||
|     dense_set(dense_set &&) noexcept(std::is_nothrow_move_constructible_v<compressed_pair<sparse_container_type, hasher>> &&std::is_nothrow_move_constructible_v<compressed_pair<packed_container_type, key_equal>>) = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Allocator-extended move constructor. | ||||
|      * @param other The instance to move from. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     dense_set(dense_set &&other, const allocator_type &allocator) | ||||
|         : sparse{std::piecewise_construct, std::forward_as_tuple(std::move(other.sparse.first()), allocator), std::forward_as_tuple(std::move(other.sparse.second()))}, | ||||
|           packed{std::piecewise_construct, std::forward_as_tuple(std::move(other.packed.first()), allocator), std::forward_as_tuple(std::move(other.packed.second()))}, | ||||
|           threshold{other.threshold} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Default copy assignment operator. | ||||
|      * @return This container. | ||||
|      */ | ||||
|     dense_set &operator=(const dense_set &) = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Default move assignment operator. | ||||
|      * @return This container. | ||||
|      */ | ||||
|     dense_set &operator=(dense_set &&) noexcept(std::is_nothrow_move_assignable_v<compressed_pair<sparse_container_type, hasher>> &&std::is_nothrow_move_assignable_v<compressed_pair<packed_container_type, key_equal>>) = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the associated allocator. | ||||
|      * @return The associated allocator. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { | ||||
|         return sparse.first().get_allocator(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the beginning. | ||||
|      * | ||||
|      * The returned iterator points to the first instance of the internal array. | ||||
|      * If the array is empty, the returned iterator will be equal to `end()`. | ||||
|      * | ||||
|      * @return An iterator to the first instance of the internal array. | ||||
|      */ | ||||
|     [[nodiscard]] const_iterator cbegin() const noexcept { | ||||
|         return packed.first().begin(); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc cbegin */ | ||||
|     [[nodiscard]] const_iterator begin() const noexcept { | ||||
|         return cbegin(); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc begin */ | ||||
|     [[nodiscard]] iterator begin() noexcept { | ||||
|         return packed.first().begin(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the end. | ||||
|      * | ||||
|      * The returned iterator points to the element following the last instance | ||||
|      * of the internal array. Attempting to dereference the returned iterator | ||||
|      * results in undefined behavior. | ||||
|      * | ||||
|      * @return An iterator to the element following the last instance of the | ||||
|      * internal array. | ||||
|      */ | ||||
|     [[nodiscard]] const_iterator cend() const noexcept { | ||||
|         return packed.first().end(); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc cend */ | ||||
|     [[nodiscard]] const_iterator end() const noexcept { | ||||
|         return cend(); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc end */ | ||||
|     [[nodiscard]] iterator end() noexcept { | ||||
|         return packed.first().end(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks whether a container is empty. | ||||
|      * @return True if the container is empty, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool empty() const noexcept { | ||||
|         return packed.first().empty(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the number of elements in a container. | ||||
|      * @return Number of elements in a container. | ||||
|      */ | ||||
|     [[nodiscard]] size_type size() const noexcept { | ||||
|         return packed.first().size(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the maximum possible number of elements. | ||||
|      * @return Maximum possible number of elements. | ||||
|      */ | ||||
|     [[nodiscard]] size_type max_size() const noexcept { | ||||
|         return packed.first().max_size(); | ||||
|     } | ||||
|  | ||||
|     /*! @brief Clears the container. */ | ||||
|     void clear() noexcept { | ||||
|         sparse.first().clear(); | ||||
|         packed.first().clear(); | ||||
|         rehash(0u); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Inserts an element into the container, if it does not exist. | ||||
|      * @param value An element to insert into the container. | ||||
|      * @return A pair consisting of an iterator to the inserted element (or to | ||||
|      * the element that prevented the insertion) and a bool denoting whether the | ||||
|      * insertion took place. | ||||
|      */ | ||||
|     std::pair<iterator, bool> insert(const value_type &value) { | ||||
|         return insert_or_do_nothing(value); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc insert */ | ||||
|     std::pair<iterator, bool> insert(value_type &&value) { | ||||
|         return insert_or_do_nothing(std::move(value)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Inserts elements into the container, if they do not exist. | ||||
|      * @tparam It Type of input iterator. | ||||
|      * @param first An iterator to the first element of the range of elements. | ||||
|      * @param last An iterator past the last element of the range of elements. | ||||
|      */ | ||||
|     template<typename It> | ||||
|     void insert(It first, It last) { | ||||
|         for(; first != last; ++first) { | ||||
|             insert(*first); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an element in-place, if it does not exist. | ||||
|      * | ||||
|      * The element is also constructed when the container already has the key, | ||||
|      * in which case the newly constructed object is destroyed immediately. | ||||
|      * | ||||
|      * @tparam Args Types of arguments to forward to the constructor of the | ||||
|      * element. | ||||
|      * @param args Arguments to forward to the constructor of the element. | ||||
|      * @return A pair consisting of an iterator to the inserted element (or to | ||||
|      * the element that prevented the insertion) and a bool denoting whether the | ||||
|      * insertion took place. | ||||
|      */ | ||||
|     template<typename... Args> | ||||
|     std::pair<iterator, bool> emplace(Args &&...args) { | ||||
|         if constexpr(((sizeof...(Args) == 1u) && ... && std::is_same_v<std::decay_t<Args>, value_type>)) { | ||||
|             return insert_or_do_nothing(std::forward<Args>(args)...); | ||||
|         } else { | ||||
|             auto &node = packed.first().emplace_back(std::piecewise_construct, std::make_tuple(packed.first().size()), std::forward_as_tuple(std::forward<Args>(args)...)); | ||||
|             const auto index = value_to_bucket(node.second); | ||||
|  | ||||
|             if(auto it = constrained_find(node.second, index); it != end()) { | ||||
|                 packed.first().pop_back(); | ||||
|                 return std::make_pair(it, false); | ||||
|             } | ||||
|  | ||||
|             std::swap(node.first, sparse.first()[index]); | ||||
|             rehash_if_required(); | ||||
|  | ||||
|             return std::make_pair(--end(), true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Removes an element from a given position. | ||||
|      * @param pos An iterator to the element to remove. | ||||
|      * @return An iterator following the removed element. | ||||
|      */ | ||||
|     iterator erase(const_iterator pos) { | ||||
|         const auto diff = pos - cbegin(); | ||||
|         erase(*pos); | ||||
|         return begin() + diff; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Removes the given elements from a container. | ||||
|      * @param first An iterator to the first element of the range of elements. | ||||
|      * @param last An iterator past the last element of the range of elements. | ||||
|      * @return An iterator following the last removed element. | ||||
|      */ | ||||
|     iterator erase(const_iterator first, const_iterator last) { | ||||
|         const auto dist = first - cbegin(); | ||||
|  | ||||
|         for(auto from = last - cbegin(); from != dist; --from) { | ||||
|             erase(packed.first()[from - 1u].second); | ||||
|         } | ||||
|  | ||||
|         return (begin() + dist); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Removes the element associated with a given value. | ||||
|      * @param value Value of an element to remove. | ||||
|      * @return Number of elements removed (either 0 or 1). | ||||
|      */ | ||||
|     size_type erase(const value_type &value) { | ||||
|         for(size_type *curr = sparse.first().data() + value_to_bucket(value); *curr != (std::numeric_limits<size_type>::max)(); curr = &packed.first()[*curr].first) { | ||||
|             if(packed.second()(packed.first()[*curr].second, value)) { | ||||
|                 const auto index = *curr; | ||||
|                 *curr = packed.first()[*curr].first; | ||||
|                 move_and_pop(index); | ||||
|                 return 1u; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return 0u; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Exchanges the contents with those of a given container. | ||||
|      * @param other Container to exchange the content with. | ||||
|      */ | ||||
|     void swap(dense_set &other) { | ||||
|         using std::swap; | ||||
|         swap(sparse, other.sparse); | ||||
|         swap(packed, other.packed); | ||||
|         swap(threshold, other.threshold); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the number of elements matching a value (either 1 or 0). | ||||
|      * @param key Key value of an element to search for. | ||||
|      * @return Number of elements matching the key (either 1 or 0). | ||||
|      */ | ||||
|     [[nodiscard]] size_type count(const value_type &key) const { | ||||
|         return find(key) != end(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the number of elements matching a key (either 1 or 0). | ||||
|      * @tparam Other Type of the key value of an element to search for. | ||||
|      * @param key Key value of an element to search for. | ||||
|      * @return Number of elements matching the key (either 1 or 0). | ||||
|      */ | ||||
|     template<typename Other> | ||||
|     [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, size_type>> | ||||
|     count(const Other &key) const { | ||||
|         return find(key) != end(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Finds an element with a given value. | ||||
|      * @param value Value of an element to search for. | ||||
|      * @return An iterator to an element with the given value. If no such | ||||
|      * element is found, a past-the-end iterator is returned. | ||||
|      */ | ||||
|     [[nodiscard]] iterator find(const value_type &value) { | ||||
|         return constrained_find(value, value_to_bucket(value)); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc find */ | ||||
|     [[nodiscard]] const_iterator find(const value_type &value) const { | ||||
|         return constrained_find(value, value_to_bucket(value)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Finds an element that compares _equivalent_ to a given value. | ||||
|      * @tparam Other Type of an element to search for. | ||||
|      * @param value Value of an element to search for. | ||||
|      * @return An iterator to an element with the given value. If no such | ||||
|      * element is found, a past-the-end iterator is returned. | ||||
|      */ | ||||
|     template<typename Other> | ||||
|     [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, iterator>> | ||||
|     find(const Other &value) { | ||||
|         return constrained_find(value, value_to_bucket(value)); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc find */ | ||||
|     template<typename Other> | ||||
|     [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, const_iterator>> | ||||
|     find(const Other &value) const { | ||||
|         return constrained_find(value, value_to_bucket(value)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns a range containing all elements with a given value. | ||||
|      * @param value Value of an element to search for. | ||||
|      * @return A pair of iterators pointing to the first element and past the | ||||
|      * last element of the range. | ||||
|      */ | ||||
|     [[nodiscard]] std::pair<iterator, iterator> equal_range(const value_type &value) { | ||||
|         const auto it = find(value); | ||||
|         return {it, it + !(it == end())}; | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc equal_range */ | ||||
|     [[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(const value_type &value) const { | ||||
|         const auto it = find(value); | ||||
|         return {it, it + !(it == cend())}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns a range containing all elements that compare _equivalent_ | ||||
|      * to a given value. | ||||
|      * @tparam Other Type of an element to search for. | ||||
|      * @param value Value of an element to search for. | ||||
|      * @return A pair of iterators pointing to the first element and past the | ||||
|      * last element of the range. | ||||
|      */ | ||||
|     template<typename Other> | ||||
|     [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<iterator, iterator>>> | ||||
|     equal_range(const Other &value) { | ||||
|         const auto it = find(value); | ||||
|         return {it, it + !(it == end())}; | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc equal_range */ | ||||
|     template<class Other> | ||||
|     [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<const_iterator, const_iterator>>> | ||||
|     equal_range(const Other &value) const { | ||||
|         const auto it = find(value); | ||||
|         return {it, it + !(it == cend())}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if the container contains an element with a given value. | ||||
|      * @param value Value of an element to search for. | ||||
|      * @return True if there is such an element, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool contains(const value_type &value) const { | ||||
|         return (find(value) != cend()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if the container contains an element that compares | ||||
|      * _equivalent_ to a given value. | ||||
|      * @tparam Other Type of an element to search for. | ||||
|      * @param value Value of an element to search for. | ||||
|      * @return True if there is such an element, false otherwise. | ||||
|      */ | ||||
|     template<typename Other> | ||||
|     [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, bool>> | ||||
|     contains(const Other &value) const { | ||||
|         return (find(value) != cend()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the beginning of a given bucket. | ||||
|      * @param index An index of a bucket to access. | ||||
|      * @return An iterator to the beginning of the given bucket. | ||||
|      */ | ||||
|     [[nodiscard]] const_local_iterator cbegin(const size_type index) const { | ||||
|         return {packed.first().begin(), sparse.first()[index]}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the beginning of a given bucket. | ||||
|      * @param index An index of a bucket to access. | ||||
|      * @return An iterator to the beginning of the given bucket. | ||||
|      */ | ||||
|     [[nodiscard]] const_local_iterator begin(const size_type index) const { | ||||
|         return cbegin(index); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the beginning of a given bucket. | ||||
|      * @param index An index of a bucket to access. | ||||
|      * @return An iterator to the beginning of the given bucket. | ||||
|      */ | ||||
|     [[nodiscard]] local_iterator begin(const size_type index) { | ||||
|         return {packed.first().begin(), sparse.first()[index]}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the end of a given bucket. | ||||
|      * @param index An index of a bucket to access. | ||||
|      * @return An iterator to the end of the given bucket. | ||||
|      */ | ||||
|     [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const { | ||||
|         return {packed.first().begin(), (std::numeric_limits<size_type>::max)()}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the end of a given bucket. | ||||
|      * @param index An index of a bucket to access. | ||||
|      * @return An iterator to the end of the given bucket. | ||||
|      */ | ||||
|     [[nodiscard]] const_local_iterator end(const size_type index) const { | ||||
|         return cend(index); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the end of a given bucket. | ||||
|      * @param index An index of a bucket to access. | ||||
|      * @return An iterator to the end of the given bucket. | ||||
|      */ | ||||
|     [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) { | ||||
|         return {packed.first().begin(), (std::numeric_limits<size_type>::max)()}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the number of buckets. | ||||
|      * @return The number of buckets. | ||||
|      */ | ||||
|     [[nodiscard]] size_type bucket_count() const { | ||||
|         return sparse.first().size(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the maximum number of buckets. | ||||
|      * @return The maximum number of buckets. | ||||
|      */ | ||||
|     [[nodiscard]] size_type max_bucket_count() const { | ||||
|         return sparse.first().max_size(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the number of elements in a given bucket. | ||||
|      * @param index The index of the bucket to examine. | ||||
|      * @return The number of elements in the given bucket. | ||||
|      */ | ||||
|     [[nodiscard]] size_type bucket_size(const size_type index) const { | ||||
|         return static_cast<size_type>(std::distance(begin(index), end(index))); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the bucket for a given element. | ||||
|      * @param value The value of the element to examine. | ||||
|      * @return The bucket for the given element. | ||||
|      */ | ||||
|     [[nodiscard]] size_type bucket(const value_type &value) const { | ||||
|         return value_to_bucket(value); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the average number of elements per bucket. | ||||
|      * @return The average number of elements per bucket. | ||||
|      */ | ||||
|     [[nodiscard]] float load_factor() const { | ||||
|         return size() / static_cast<float>(bucket_count()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the maximum average number of elements per bucket. | ||||
|      * @return The maximum average number of elements per bucket. | ||||
|      */ | ||||
|     [[nodiscard]] float max_load_factor() const { | ||||
|         return threshold; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Sets the desired maximum average number of elements per bucket. | ||||
|      * @param value A desired maximum average number of elements per bucket. | ||||
|      */ | ||||
|     void max_load_factor(const float value) { | ||||
|         ENTT_ASSERT(value > 0.f, "Invalid load factor"); | ||||
|         threshold = value; | ||||
|         rehash(0u); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Reserves at least the specified number of buckets and regenerates | ||||
|      * the hash table. | ||||
|      * @param cnt New number of buckets. | ||||
|      */ | ||||
|     void rehash(const size_type cnt) { | ||||
|         auto value = cnt > minimum_capacity ? cnt : minimum_capacity; | ||||
|         const auto cap = static_cast<size_type>(size() / max_load_factor()); | ||||
|         value = value > cap ? value : cap; | ||||
|  | ||||
|         if(const auto sz = next_power_of_two(value); sz != bucket_count()) { | ||||
|             sparse.first().resize(sz); | ||||
|  | ||||
|             for(auto &&elem: sparse.first()) { | ||||
|                 elem = std::numeric_limits<size_type>::max(); | ||||
|             } | ||||
|  | ||||
|             for(size_type pos{}, last = size(); pos < last; ++pos) { | ||||
|                 const auto index = value_to_bucket(packed.first()[pos].second); | ||||
|                 packed.first()[pos].first = std::exchange(sparse.first()[index], pos); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Reserves space for at least the specified number of elements and | ||||
|      * regenerates the hash table. | ||||
|      * @param cnt New number of elements. | ||||
|      */ | ||||
|     void reserve(const size_type cnt) { | ||||
|         packed.first().reserve(cnt); | ||||
|         rehash(static_cast<size_type>(std::ceil(cnt / max_load_factor()))); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the function used to hash the elements. | ||||
|      * @return The function used to hash the elements. | ||||
|      */ | ||||
|     [[nodiscard]] hasher hash_function() const { | ||||
|         return sparse.second(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the function used to compare elements for equality. | ||||
|      * @return The function used to compare elements for equality. | ||||
|      */ | ||||
|     [[nodiscard]] key_equal key_eq() const { | ||||
|         return packed.second(); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     compressed_pair<sparse_container_type, hasher> sparse; | ||||
|     compressed_pair<packed_container_type, key_equal> packed; | ||||
|     float threshold; | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										26
									
								
								external/entt/entt/src/entt/container/fwd.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								external/entt/entt/src/entt/container/fwd.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| #ifndef ENTT_CONTAINER_FWD_HPP | ||||
| #define ENTT_CONTAINER_FWD_HPP | ||||
|  | ||||
| #include <functional> | ||||
| #include <memory> | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| template< | ||||
|     typename Key, | ||||
|     typename Type, | ||||
|     typename = std::hash<Key>, | ||||
|     typename = std::equal_to<Key>, | ||||
|     typename = std::allocator<std::pair<const Key, Type>>> | ||||
| class dense_map; | ||||
|  | ||||
| template< | ||||
|     typename Type, | ||||
|     typename = std::hash<Type>, | ||||
|     typename = std::equal_to<Type>, | ||||
|     typename = std::allocator<Type>> | ||||
| class dense_set; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										137
									
								
								external/entt/entt/src/entt/core/algorithm.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								external/entt/entt/src/entt/core/algorithm.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | ||||
| #ifndef ENTT_CORE_ALGORITHM_HPP | ||||
| #define ENTT_CORE_ALGORITHM_HPP | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <functional> | ||||
| #include <iterator> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include "utility.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @brief Function object to wrap `std::sort` in a class type. | ||||
|  * | ||||
|  * Unfortunately, `std::sort` cannot be passed as template argument to a class | ||||
|  * template or a function template.<br/> | ||||
|  * This class fills the gap by wrapping some flavors of `std::sort` in a | ||||
|  * function object. | ||||
|  */ | ||||
| struct std_sort { | ||||
|     /** | ||||
|      * @brief Sorts the elements in a range. | ||||
|      * | ||||
|      * Sorts the elements in a range using the given binary comparison function. | ||||
|      * | ||||
|      * @tparam It Type of random access iterator. | ||||
|      * @tparam Compare Type of comparison function object. | ||||
|      * @tparam Args Types of arguments to forward to the sort function. | ||||
|      * @param first An iterator to the first element of the range to sort. | ||||
|      * @param last An iterator past the last element of the range to sort. | ||||
|      * @param compare A valid comparison function object. | ||||
|      * @param args Arguments to forward to the sort function, if any. | ||||
|      */ | ||||
|     template<typename It, typename Compare = std::less<>, typename... Args> | ||||
|     void operator()(It first, It last, Compare compare = Compare{}, Args &&...args) const { | ||||
|         std::sort(std::forward<Args>(args)..., std::move(first), std::move(last), std::move(compare)); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /*! @brief Function object for performing insertion sort. */ | ||||
| struct insertion_sort { | ||||
|     /** | ||||
|      * @brief Sorts the elements in a range. | ||||
|      * | ||||
|      * Sorts the elements in a range using the given binary comparison function. | ||||
|      * | ||||
|      * @tparam It Type of random access iterator. | ||||
|      * @tparam Compare Type of comparison function object. | ||||
|      * @param first An iterator to the first element of the range to sort. | ||||
|      * @param last An iterator past the last element of the range to sort. | ||||
|      * @param compare A valid comparison function object. | ||||
|      */ | ||||
|     template<typename It, typename Compare = std::less<>> | ||||
|     void operator()(It first, It last, Compare compare = Compare{}) const { | ||||
|         if(first < last) { | ||||
|             for(auto it = first + 1; it < last; ++it) { | ||||
|                 auto value = std::move(*it); | ||||
|                 auto pre = it; | ||||
|  | ||||
|                 for(; pre > first && compare(value, *(pre - 1)); --pre) { | ||||
|                     *pre = std::move(*(pre - 1)); | ||||
|                 } | ||||
|  | ||||
|                 *pre = std::move(value); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Function object for performing LSD radix sort. | ||||
|  * @tparam Bit Number of bits processed per pass. | ||||
|  * @tparam N Maximum number of bits to sort. | ||||
|  */ | ||||
| template<std::size_t Bit, std::size_t N> | ||||
| struct radix_sort { | ||||
|     static_assert((N % Bit) == 0, "The maximum number of bits to sort must be a multiple of the number of bits processed per pass"); | ||||
|  | ||||
|     /** | ||||
|      * @brief Sorts the elements in a range. | ||||
|      * | ||||
|      * Sorts the elements in a range using the given _getter_ to access the | ||||
|      * actual data to be sorted. | ||||
|      * | ||||
|      * This implementation is inspired by the online book | ||||
|      * [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies.html#RadixSort). | ||||
|      * | ||||
|      * @tparam It Type of random access iterator. | ||||
|      * @tparam Getter Type of _getter_ function object. | ||||
|      * @param first An iterator to the first element of the range to sort. | ||||
|      * @param last An iterator past the last element of the range to sort. | ||||
|      * @param getter A valid _getter_ function object. | ||||
|      */ | ||||
|     template<typename It, typename Getter = identity> | ||||
|     void operator()(It first, It last, Getter getter = Getter{}) const { | ||||
|         if(first < last) { | ||||
|             static constexpr auto mask = (1 << Bit) - 1; | ||||
|             static constexpr auto buckets = 1 << Bit; | ||||
|             static constexpr auto passes = N / Bit; | ||||
|  | ||||
|             using value_type = typename std::iterator_traits<It>::value_type; | ||||
|             std::vector<value_type> aux(std::distance(first, last)); | ||||
|  | ||||
|             auto part = [getter = std::move(getter)](auto from, auto to, auto out, auto start) { | ||||
|                 std::size_t index[buckets]{}; | ||||
|                 std::size_t count[buckets]{}; | ||||
|  | ||||
|                 for(auto it = from; it != to; ++it) { | ||||
|                     ++count[(getter(*it) >> start) & mask]; | ||||
|                 } | ||||
|  | ||||
|                 for(std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) { | ||||
|                     index[pos + 1u] = index[pos] + count[pos]; | ||||
|                 } | ||||
|  | ||||
|                 for(auto it = from; it != to; ++it) { | ||||
|                     out[index[(getter(*it) >> start) & mask]++] = std::move(*it); | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             for(std::size_t pass = 0; pass < (passes & ~1); pass += 2) { | ||||
|                 part(first, last, aux.begin(), pass * Bit); | ||||
|                 part(aux.begin(), aux.end(), first, (pass + 1) * Bit); | ||||
|             } | ||||
|  | ||||
|             if constexpr(passes & 1) { | ||||
|                 part(first, last, aux.begin(), (passes - 1) * Bit); | ||||
|                 std::move(aux.begin(), aux.end(), first); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										510
									
								
								external/entt/entt/src/entt/core/any.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										510
									
								
								external/entt/entt/src/entt/core/any.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,510 @@ | ||||
| #ifndef ENTT_CORE_ANY_HPP | ||||
| #define ENTT_CORE_ANY_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <memory> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include "../config/config.h" | ||||
| #include "../core/utility.hpp" | ||||
| #include "fwd.hpp" | ||||
| #include "type_info.hpp" | ||||
| #include "type_traits.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| enum class any_operation : std::uint8_t { | ||||
|     copy, | ||||
|     move, | ||||
|     transfer, | ||||
|     assign, | ||||
|     destroy, | ||||
|     compare, | ||||
|     get | ||||
| }; | ||||
|  | ||||
| enum class any_policy : std::uint8_t { | ||||
|     owner, | ||||
|     ref, | ||||
|     cref | ||||
| }; | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief A SBO friendly, type-safe container for single values of any type. | ||||
|  * @tparam Len Size of the storage reserved for the small buffer optimization. | ||||
|  * @tparam Align Optional alignment requirement. | ||||
|  */ | ||||
| template<std::size_t Len, std::size_t Align> | ||||
| class basic_any { | ||||
|     using operation = internal::any_operation; | ||||
|     using policy = internal::any_policy; | ||||
|     using vtable_type = const void *(const operation, const basic_any &, const void *); | ||||
|  | ||||
|     struct storage_type { | ||||
|         alignas(Align) std::byte data[Len + !Len]; | ||||
|     }; | ||||
|  | ||||
|     template<typename Type> | ||||
|     static constexpr bool in_situ = Len && alignof(Type) <= Align && sizeof(Type) <= Len &&std::is_nothrow_move_constructible_v<Type>; | ||||
|  | ||||
|     template<typename Type> | ||||
|     static const void *basic_vtable(const operation op, const basic_any &value, const void *other) { | ||||
|         static_assert(!std::is_same_v<Type, void> && std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>, "Invalid type"); | ||||
|         const Type *element = nullptr; | ||||
|  | ||||
|         if constexpr(in_situ<Type>) { | ||||
|             element = value.owner() ? reinterpret_cast<const Type *>(&value.storage) : static_cast<const Type *>(value.instance); | ||||
|         } else { | ||||
|             element = static_cast<const Type *>(value.instance); | ||||
|         } | ||||
|  | ||||
|         switch(op) { | ||||
|         case operation::copy: | ||||
|             if constexpr(std::is_copy_constructible_v<Type>) { | ||||
|                 static_cast<basic_any *>(const_cast<void *>(other))->initialize<Type>(*element); | ||||
|             } | ||||
|             break; | ||||
|         case operation::move: | ||||
|             if constexpr(in_situ<Type>) { | ||||
|                 if(value.owner()) { | ||||
|                     return new(&static_cast<basic_any *>(const_cast<void *>(other))->storage) Type{std::move(*const_cast<Type *>(element))}; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return (static_cast<basic_any *>(const_cast<void *>(other))->instance = std::exchange(const_cast<basic_any &>(value).instance, nullptr)); | ||||
|         case operation::transfer: | ||||
|             if constexpr(std::is_move_assignable_v<Type>) { | ||||
|                 *const_cast<Type *>(element) = std::move(*static_cast<Type *>(const_cast<void *>(other))); | ||||
|                 return other; | ||||
|             } | ||||
|             [[fallthrough]]; | ||||
|         case operation::assign: | ||||
|             if constexpr(std::is_copy_assignable_v<Type>) { | ||||
|                 *const_cast<Type *>(element) = *static_cast<const Type *>(other); | ||||
|                 return other; | ||||
|             } | ||||
|             break; | ||||
|         case operation::destroy: | ||||
|             if constexpr(in_situ<Type>) { | ||||
|                 element->~Type(); | ||||
|             } else if constexpr(std::is_array_v<Type>) { | ||||
|                 delete[] element; | ||||
|             } else { | ||||
|                 delete element; | ||||
|             } | ||||
|             break; | ||||
|         case operation::compare: | ||||
|             if constexpr(!std::is_function_v<Type> && !std::is_array_v<Type> && is_equality_comparable_v<Type>) { | ||||
|                 return *element == *static_cast<const Type *>(other) ? other : nullptr; | ||||
|             } else { | ||||
|                 return (element == other) ? other : nullptr; | ||||
|             } | ||||
|         case operation::get: | ||||
|             return element; | ||||
|         } | ||||
|  | ||||
|         return nullptr; | ||||
|     } | ||||
|  | ||||
|     template<typename Type, typename... Args> | ||||
|     void initialize([[maybe_unused]] Args &&...args) { | ||||
|         info = &type_id<std::remove_cv_t<std::remove_reference_t<Type>>>(); | ||||
|  | ||||
|         if constexpr(!std::is_void_v<Type>) { | ||||
|             vtable = basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>; | ||||
|  | ||||
|             if constexpr(std::is_lvalue_reference_v<Type>) { | ||||
|                 static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v<Args> && ...), "Invalid arguments"); | ||||
|                 mode = std::is_const_v<std::remove_reference_t<Type>> ? policy::cref : policy::ref; | ||||
|                 instance = (std::addressof(args), ...); | ||||
|             } else if constexpr(in_situ<std::remove_cv_t<std::remove_reference_t<Type>>>) { | ||||
|                 if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>>) { | ||||
|                     new(&storage) std::remove_cv_t<std::remove_reference_t<Type>>{std::forward<Args>(args)...}; | ||||
|                 } else { | ||||
|                     new(&storage) std::remove_cv_t<std::remove_reference_t<Type>>(std::forward<Args>(args)...); | ||||
|                 } | ||||
|             } else { | ||||
|                 if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>>) { | ||||
|                     instance = new std::remove_cv_t<std::remove_reference_t<Type>>{std::forward<Args>(args)...}; | ||||
|                 } else { | ||||
|                     instance = new std::remove_cv_t<std::remove_reference_t<Type>>(std::forward<Args>(args)...); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     basic_any(const basic_any &other, const policy pol) noexcept | ||||
|         : instance{other.data()}, | ||||
|           info{other.info}, | ||||
|           vtable{other.vtable}, | ||||
|           mode{pol} {} | ||||
|  | ||||
| public: | ||||
|     /*! @brief Size of the internal storage. */ | ||||
|     static constexpr auto length = Len; | ||||
|     /*! @brief Alignment requirement. */ | ||||
|     static constexpr auto alignment = Align; | ||||
|  | ||||
|     /*! @brief Default constructor. */ | ||||
|     constexpr basic_any() noexcept | ||||
|         : basic_any{std::in_place_type<void>} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a wrapper by directly initializing the new object. | ||||
|      * @tparam Type Type of object to use to initialize the wrapper. | ||||
|      * @tparam Args Types of arguments to use to construct the new instance. | ||||
|      * @param args Parameters to use to construct the instance. | ||||
|      */ | ||||
|     template<typename Type, typename... Args> | ||||
|     explicit basic_any(std::in_place_type_t<Type>, Args &&...args) | ||||
|         : instance{}, | ||||
|           info{}, | ||||
|           vtable{}, | ||||
|           mode{policy::owner} { | ||||
|         initialize<Type>(std::forward<Args>(args)...); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a wrapper from a given value. | ||||
|      * @tparam Type Type of object to use to initialize the wrapper. | ||||
|      * @param value An instance of an object to use to initialize the wrapper. | ||||
|      */ | ||||
|     template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>> | ||||
|     basic_any(Type &&value) | ||||
|         : basic_any{std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Copy constructor. | ||||
|      * @param other The instance to copy from. | ||||
|      */ | ||||
|     basic_any(const basic_any &other) | ||||
|         : basic_any{} { | ||||
|         if(other.vtable) { | ||||
|             other.vtable(operation::copy, other, this); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Move constructor. | ||||
|      * @param other The instance to move from. | ||||
|      */ | ||||
|     basic_any(basic_any &&other) noexcept | ||||
|         : instance{}, | ||||
|           info{other.info}, | ||||
|           vtable{other.vtable}, | ||||
|           mode{other.mode} { | ||||
|         if(other.vtable) { | ||||
|             other.vtable(operation::move, other, this); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /*! @brief Frees the internal storage, whatever it means. */ | ||||
|     ~basic_any() { | ||||
|         if(vtable && owner()) { | ||||
|             vtable(operation::destroy, *this, nullptr); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Copy assignment operator. | ||||
|      * @param other The instance to copy from. | ||||
|      * @return This any object. | ||||
|      */ | ||||
|     basic_any &operator=(const basic_any &other) { | ||||
|         reset(); | ||||
|  | ||||
|         if(other.vtable) { | ||||
|             other.vtable(operation::copy, other, this); | ||||
|         } | ||||
|  | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Move assignment operator. | ||||
|      * @param other The instance to move from. | ||||
|      * @return This any object. | ||||
|      */ | ||||
|     basic_any &operator=(basic_any &&other) noexcept { | ||||
|         reset(); | ||||
|  | ||||
|         if(other.vtable) { | ||||
|             other.vtable(operation::move, other, this); | ||||
|             info = other.info; | ||||
|             vtable = other.vtable; | ||||
|             mode = other.mode; | ||||
|         } | ||||
|  | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Value assignment operator. | ||||
|      * @tparam Type Type of object to use to initialize the wrapper. | ||||
|      * @param value An instance of an object to use to initialize the wrapper. | ||||
|      * @return This any object. | ||||
|      */ | ||||
|     template<typename Type> | ||||
|     std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>, basic_any &> | ||||
|     operator=(Type &&value) { | ||||
|         emplace<std::decay_t<Type>>(std::forward<Type>(value)); | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the object type if any, `type_id<void>()` otherwise. | ||||
|      * @return The object type if any, `type_id<void>()` otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] const type_info &type() const noexcept { | ||||
|         return *info; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an opaque pointer to the contained instance. | ||||
|      * @return An opaque pointer the contained instance, if any. | ||||
|      */ | ||||
|     [[nodiscard]] const void *data() const noexcept { | ||||
|         return vtable ? vtable(operation::get, *this, nullptr) : nullptr; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an opaque pointer to the contained instance. | ||||
|      * @param req Expected type. | ||||
|      * @return An opaque pointer the contained instance, if any. | ||||
|      */ | ||||
|     [[nodiscard]] const void *data(const type_info &req) const noexcept { | ||||
|         return *info == req ? data() : nullptr; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an opaque pointer to the contained instance. | ||||
|      * @return An opaque pointer the contained instance, if any. | ||||
|      */ | ||||
|     [[nodiscard]] void *data() noexcept { | ||||
|         return mode == policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an opaque pointer to the contained instance. | ||||
|      * @param req Expected type. | ||||
|      * @return An opaque pointer the contained instance, if any. | ||||
|      */ | ||||
|     [[nodiscard]] void *data(const type_info &req) noexcept { | ||||
|         return mode == policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data(req)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Replaces the contained object by creating a new instance directly. | ||||
|      * @tparam Type Type of object to use to initialize the wrapper. | ||||
|      * @tparam Args Types of arguments to use to construct the new instance. | ||||
|      * @param args Parameters to use to construct the instance. | ||||
|      */ | ||||
|     template<typename Type, typename... Args> | ||||
|     void emplace(Args &&...args) { | ||||
|         reset(); | ||||
|         initialize<Type>(std::forward<Args>(args)...); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns a value to the contained object without replacing it. | ||||
|      * @param other The value to assign to the contained object. | ||||
|      * @return True in case of success, false otherwise. | ||||
|      */ | ||||
|     bool assign(const basic_any &other) { | ||||
|         if(vtable && mode != policy::cref && *info == *other.info) { | ||||
|             return (vtable(operation::assign, *this, other.data()) != nullptr); | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc assign */ | ||||
|     bool assign(basic_any &&other) { | ||||
|         if(vtable && mode != policy::cref && *info == *other.info) { | ||||
|             if(auto *val = other.data(); val) { | ||||
|                 return (vtable(operation::transfer, *this, val) != nullptr); | ||||
|             } else { | ||||
|                 return (vtable(operation::assign, *this, std::as_const(other).data()) != nullptr); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /*! @brief Destroys contained object */ | ||||
|     void reset() { | ||||
|         if(vtable && owner()) { | ||||
|             vtable(operation::destroy, *this, nullptr); | ||||
|         } | ||||
|  | ||||
|         // unnecessary but it helps to detect nasty bugs | ||||
|         ENTT_ASSERT((instance = nullptr) == nullptr, ""); | ||||
|         info = &type_id<void>(); | ||||
|         vtable = nullptr; | ||||
|         mode = policy::owner; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns false if a wrapper is empty, true otherwise. | ||||
|      * @return False if the wrapper is empty, true otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] explicit operator bool() const noexcept { | ||||
|         return vtable != nullptr; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if two wrappers differ in their content. | ||||
|      * @param other Wrapper with which to compare. | ||||
|      * @return False if the two objects differ in their content, true otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool operator==(const basic_any &other) const noexcept { | ||||
|         if(vtable && *info == *other.info) { | ||||
|             return (vtable(operation::compare, *this, other.data()) != nullptr); | ||||
|         } | ||||
|  | ||||
|         return (!vtable && !other.vtable); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if two wrappers differ in their content. | ||||
|      * @param other Wrapper with which to compare. | ||||
|      * @return True if the two objects differ in their content, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool operator!=(const basic_any &other) const noexcept { | ||||
|         return !(*this == other); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Aliasing constructor. | ||||
|      * @return A wrapper that shares a reference to an unmanaged object. | ||||
|      */ | ||||
|     [[nodiscard]] basic_any as_ref() noexcept { | ||||
|         return basic_any{*this, (mode == policy::cref ? policy::cref : policy::ref)}; | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc as_ref */ | ||||
|     [[nodiscard]] basic_any as_ref() const noexcept { | ||||
|         return basic_any{*this, policy::cref}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns true if a wrapper owns its object, false otherwise. | ||||
|      * @return True if the wrapper owns its object, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool owner() const noexcept { | ||||
|         return (mode == policy::owner); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     union { | ||||
|         const void *instance; | ||||
|         storage_type storage; | ||||
|     }; | ||||
|     const type_info *info; | ||||
|     vtable_type *vtable; | ||||
|     policy mode; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Performs type-safe access to the contained object. | ||||
|  * @tparam Type Type to which conversion is required. | ||||
|  * @tparam Len Size of the storage reserved for the small buffer optimization. | ||||
|  * @tparam Align Alignment requirement. | ||||
|  * @param data Target any object. | ||||
|  * @return The element converted to the requested type. | ||||
|  */ | ||||
| template<typename Type, std::size_t Len, std::size_t Align> | ||||
| Type any_cast(const basic_any<Len, Align> &data) noexcept { | ||||
|     const auto *const instance = any_cast<std::remove_reference_t<Type>>(&data); | ||||
|     ENTT_ASSERT(instance, "Invalid instance"); | ||||
|     return static_cast<Type>(*instance); | ||||
| } | ||||
|  | ||||
| /*! @copydoc any_cast */ | ||||
| template<typename Type, std::size_t Len, std::size_t Align> | ||||
| Type any_cast(basic_any<Len, Align> &data) noexcept { | ||||
|     // forces const on non-reference types to make them work also with wrappers for const references | ||||
|     auto *const instance = any_cast<std::remove_reference_t<const Type>>(&data); | ||||
|     ENTT_ASSERT(instance, "Invalid instance"); | ||||
|     return static_cast<Type>(*instance); | ||||
| } | ||||
|  | ||||
| /*! @copydoc any_cast */ | ||||
| template<typename Type, std::size_t Len, std::size_t Align> | ||||
| Type any_cast(basic_any<Len, Align> &&data) noexcept { | ||||
|     if constexpr(std::is_copy_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>) { | ||||
|         if(auto *const instance = any_cast<std::remove_reference_t<Type>>(&data); instance) { | ||||
|             return static_cast<Type>(std::move(*instance)); | ||||
|         } else { | ||||
|             return any_cast<Type>(data); | ||||
|         } | ||||
|     } else { | ||||
|         auto *const instance = any_cast<std::remove_reference_t<Type>>(&data); | ||||
|         ENTT_ASSERT(instance, "Invalid instance"); | ||||
|         return static_cast<Type>(std::move(*instance)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /*! @copydoc any_cast */ | ||||
| template<typename Type, std::size_t Len, std::size_t Align> | ||||
| const Type *any_cast(const basic_any<Len, Align> *data) noexcept { | ||||
|     const auto &info = type_id<std::remove_cv_t<Type>>(); | ||||
|     return static_cast<const Type *>(data->data(info)); | ||||
| } | ||||
|  | ||||
| /*! @copydoc any_cast */ | ||||
| template<typename Type, std::size_t Len, std::size_t Align> | ||||
| Type *any_cast(basic_any<Len, Align> *data) noexcept { | ||||
|     if constexpr(std::is_const_v<Type>) { | ||||
|         // last attempt to make wrappers for const references return their values | ||||
|         return any_cast<Type>(&std::as_const(*data)); | ||||
|     } else { | ||||
|         const auto &info = type_id<std::remove_cv_t<Type>>(); | ||||
|         return static_cast<Type *>(data->data(info)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Constructs a wrapper from a given type, passing it all arguments. | ||||
|  * @tparam Type Type of object to use to initialize the wrapper. | ||||
|  * @tparam Len Size of the storage reserved for the small buffer optimization. | ||||
|  * @tparam Align Optional alignment requirement. | ||||
|  * @tparam Args Types of arguments to use to construct the new instance. | ||||
|  * @param args Parameters to use to construct the instance. | ||||
|  * @return A properly initialized wrapper for an object of the given type. | ||||
|  */ | ||||
| template<typename Type, std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename... Args> | ||||
| basic_any<Len, Align> make_any(Args &&...args) { | ||||
|     return basic_any<Len, Align>{std::in_place_type<Type>, std::forward<Args>(args)...}; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Forwards its argument and avoids copies for lvalue references. | ||||
|  * @tparam Len Size of the storage reserved for the small buffer optimization. | ||||
|  * @tparam Align Optional alignment requirement. | ||||
|  * @tparam Type Type of argument to use to construct the new instance. | ||||
|  * @param value Parameter to use to construct the instance. | ||||
|  * @return A properly initialized and not necessarily owning wrapper. | ||||
|  */ | ||||
| template<std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename Type> | ||||
| basic_any<Len, Align> forward_as_any(Type &&value) { | ||||
|     return basic_any<Len, Align>{std::in_place_type<Type &&>, std::forward<Type>(value)}; | ||||
| } | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										30
									
								
								external/entt/entt/src/entt/core/attribute.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								external/entt/entt/src/entt/core/attribute.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| #ifndef ENTT_CORE_ATTRIBUTE_H | ||||
| #define ENTT_CORE_ATTRIBUTE_H | ||||
|  | ||||
| #ifndef ENTT_EXPORT | ||||
| #    if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER | ||||
| #        define ENTT_EXPORT __declspec(dllexport) | ||||
| #        define ENTT_IMPORT __declspec(dllimport) | ||||
| #        define ENTT_HIDDEN | ||||
| #    elif defined __GNUC__ && __GNUC__ >= 4 | ||||
| #        define ENTT_EXPORT __attribute__((visibility("default"))) | ||||
| #        define ENTT_IMPORT __attribute__((visibility("default"))) | ||||
| #        define ENTT_HIDDEN __attribute__((visibility("hidden"))) | ||||
| #    else /* Unsupported compiler */ | ||||
| #        define ENTT_EXPORT | ||||
| #        define ENTT_IMPORT | ||||
| #        define ENTT_HIDDEN | ||||
| #    endif | ||||
| #endif | ||||
|  | ||||
| #ifndef ENTT_API | ||||
| #    if defined ENTT_API_EXPORT | ||||
| #        define ENTT_API ENTT_EXPORT | ||||
| #    elif defined ENTT_API_IMPORT | ||||
| #        define ENTT_API ENTT_IMPORT | ||||
| #    else /* No API */ | ||||
| #        define ENTT_API | ||||
| #    endif | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										279
									
								
								external/entt/entt/src/entt/core/compressed_pair.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								external/entt/entt/src/entt/core/compressed_pair.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,279 @@ | ||||
| #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP | ||||
| #define ENTT_CORE_COMPRESSED_PAIR_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <tuple> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include "type_traits.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename Type, std::size_t, typename = void> | ||||
| struct compressed_pair_element { | ||||
|     using reference = Type &; | ||||
|     using const_reference = const Type &; | ||||
|  | ||||
|     template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<Type>>> | ||||
|     constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<Type>) | ||||
|         : value{} {} | ||||
|  | ||||
|     template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>> | ||||
|     constexpr compressed_pair_element(Arg &&arg) noexcept(std::is_nothrow_constructible_v<Type, Arg>) | ||||
|         : value{std::forward<Arg>(arg)} {} | ||||
|  | ||||
|     template<typename... Args, std::size_t... Index> | ||||
|     constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<Type, Args...>) | ||||
|         : value{std::forward<Args>(std::get<Index>(args))...} {} | ||||
|  | ||||
|     [[nodiscard]] constexpr reference get() noexcept { | ||||
|         return value; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr const_reference get() const noexcept { | ||||
|         return value; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     Type value; | ||||
| }; | ||||
|  | ||||
| template<typename Type, std::size_t Tag> | ||||
| struct compressed_pair_element<Type, Tag, std::enable_if_t<is_ebco_eligible_v<Type>>>: Type { | ||||
|     using reference = Type &; | ||||
|     using const_reference = const Type &; | ||||
|     using base_type = Type; | ||||
|  | ||||
|     template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<base_type>>> | ||||
|     constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<base_type>) | ||||
|         : base_type{} {} | ||||
|  | ||||
|     template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>> | ||||
|     constexpr compressed_pair_element(Arg &&arg) noexcept(std::is_nothrow_constructible_v<base_type, Arg>) | ||||
|         : base_type{std::forward<Arg>(arg)} {} | ||||
|  | ||||
|     template<typename... Args, std::size_t... Index> | ||||
|     constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<base_type, Args...>) | ||||
|         : base_type{std::forward<Args>(std::get<Index>(args))...} {} | ||||
|  | ||||
|     [[nodiscard]] constexpr reference get() noexcept { | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr const_reference get() const noexcept { | ||||
|         return *this; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief A compressed pair. | ||||
|  * | ||||
|  * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to | ||||
|  * reduce its final size to a minimum. | ||||
|  * | ||||
|  * @tparam First The type of the first element that the pair stores. | ||||
|  * @tparam Second The type of the second element that the pair stores. | ||||
|  */ | ||||
| template<typename First, typename Second> | ||||
| class compressed_pair final | ||||
|     : internal::compressed_pair_element<First, 0u>, | ||||
|       internal::compressed_pair_element<Second, 1u> { | ||||
|     using first_base = internal::compressed_pair_element<First, 0u>; | ||||
|     using second_base = internal::compressed_pair_element<Second, 1u>; | ||||
|  | ||||
| public: | ||||
|     /*! @brief The type of the first element that the pair stores. */ | ||||
|     using first_type = First; | ||||
|     /*! @brief The type of the second element that the pair stores. */ | ||||
|     using second_type = Second; | ||||
|  | ||||
|     /** | ||||
|      * @brief Default constructor, conditionally enabled. | ||||
|      * | ||||
|      * This constructor is only available when the types that the pair stores | ||||
|      * are both at least default constructible. | ||||
|      * | ||||
|      * @tparam Dummy Dummy template parameter used for internal purposes. | ||||
|      */ | ||||
|     template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<first_type> && std::is_default_constructible_v<second_type>>> | ||||
|     constexpr compressed_pair() noexcept(std::is_nothrow_default_constructible_v<first_base> &&std::is_nothrow_default_constructible_v<second_base>) | ||||
|         : first_base{}, | ||||
|           second_base{} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Copy constructor. | ||||
|      * @param other The instance to copy from. | ||||
|      */ | ||||
|     constexpr compressed_pair(const compressed_pair &other) noexcept(std::is_nothrow_copy_constructible_v<first_base> &&std::is_nothrow_copy_constructible_v<second_base>) = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Move constructor. | ||||
|      * @param other The instance to move from. | ||||
|      */ | ||||
|     constexpr compressed_pair(compressed_pair &&other) noexcept(std::is_nothrow_move_constructible_v<first_base> &&std::is_nothrow_move_constructible_v<second_base>) = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a pair from its values. | ||||
|      * @tparam Arg Type of value to use to initialize the first element. | ||||
|      * @tparam Other Type of value to use to initialize the second element. | ||||
|      * @param arg Value to use to initialize the first element. | ||||
|      * @param other Value to use to initialize the second element. | ||||
|      */ | ||||
|     template<typename Arg, typename Other> | ||||
|     constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(std::is_nothrow_constructible_v<first_base, Arg> &&std::is_nothrow_constructible_v<second_base, Other>) | ||||
|         : first_base{std::forward<Arg>(arg)}, | ||||
|           second_base{std::forward<Other>(other)} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a pair by forwarding the arguments to its parts. | ||||
|      * @tparam Args Types of arguments to use to initialize the first element. | ||||
|      * @tparam Other Types of arguments to use to initialize the second element. | ||||
|      * @param args Arguments to use to initialize the first element. | ||||
|      * @param other Arguments to use to initialize the second element. | ||||
|      */ | ||||
|     template<typename... Args, typename... Other> | ||||
|     constexpr compressed_pair(std::piecewise_construct_t, std::tuple<Args...> args, std::tuple<Other...> other) noexcept(std::is_nothrow_constructible_v<first_base, Args...> &&std::is_nothrow_constructible_v<second_base, Other...>) | ||||
|         : first_base{std::move(args), std::index_sequence_for<Args...>{}}, | ||||
|           second_base{std::move(other), std::index_sequence_for<Other...>{}} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Copy assignment operator. | ||||
|      * @param other The instance to copy from. | ||||
|      * @return This compressed pair object. | ||||
|      */ | ||||
|     constexpr compressed_pair &operator=(const compressed_pair &other) noexcept(std::is_nothrow_copy_assignable_v<first_base> &&std::is_nothrow_copy_assignable_v<second_base>) = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Move assignment operator. | ||||
|      * @param other The instance to move from. | ||||
|      * @return This compressed pair object. | ||||
|      */ | ||||
|     constexpr compressed_pair &operator=(compressed_pair &&other) noexcept(std::is_nothrow_move_assignable_v<first_base> &&std::is_nothrow_move_assignable_v<second_base>) = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the first element that a pair stores. | ||||
|      * @return The first element that a pair stores. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr first_type &first() noexcept { | ||||
|         return static_cast<first_base &>(*this).get(); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc first */ | ||||
|     [[nodiscard]] constexpr const first_type &first() const noexcept { | ||||
|         return static_cast<const first_base &>(*this).get(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the second element that a pair stores. | ||||
|      * @return The second element that a pair stores. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr second_type &second() noexcept { | ||||
|         return static_cast<second_base &>(*this).get(); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc second */ | ||||
|     [[nodiscard]] constexpr const second_type &second() const noexcept { | ||||
|         return static_cast<const second_base &>(*this).get(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Swaps two compressed pair objects. | ||||
|      * @param other The compressed pair to swap with. | ||||
|      */ | ||||
|     constexpr void swap(compressed_pair &other) noexcept(std::is_nothrow_swappable_v<first_type> &&std::is_nothrow_swappable_v<second_type>) { | ||||
|         using std::swap; | ||||
|         swap(first(), other.first()); | ||||
|         swap(second(), other.second()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Extracts an element from the compressed pair. | ||||
|      * @tparam Index An integer value that is either 0 or 1. | ||||
|      * @return Returns a reference to the first element if `Index` is 0 and a | ||||
|      * reference to the second element if `Index` is 1. | ||||
|      */ | ||||
|     template<std::size_t Index> | ||||
|     constexpr decltype(auto) get() noexcept { | ||||
|         if constexpr(Index == 0u) { | ||||
|             return first(); | ||||
|         } else { | ||||
|             static_assert(Index == 1u, "Index out of bounds"); | ||||
|             return second(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc get */ | ||||
|     template<std::size_t Index> | ||||
|     constexpr decltype(auto) get() const noexcept { | ||||
|         if constexpr(Index == 0u) { | ||||
|             return first(); | ||||
|         } else { | ||||
|             static_assert(Index == 1u, "Index out of bounds"); | ||||
|             return second(); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Deduction guide. | ||||
|  * @tparam Type Type of value to use to initialize the first element. | ||||
|  * @tparam Other Type of value to use to initialize the second element. | ||||
|  */ | ||||
| template<typename Type, typename Other> | ||||
| compressed_pair(Type &&, Other &&) -> compressed_pair<std::decay_t<Type>, std::decay_t<Other>>; | ||||
|  | ||||
| /** | ||||
|  * @brief Swaps two compressed pair objects. | ||||
|  * @tparam First The type of the first element that the pairs store. | ||||
|  * @tparam Second The type of the second element that the pairs store. | ||||
|  * @param lhs A valid compressed pair object. | ||||
|  * @param rhs A valid compressed pair object. | ||||
|  */ | ||||
| template<typename First, typename Second> | ||||
| inline constexpr void swap(compressed_pair<First, Second> &lhs, compressed_pair<First, Second> &rhs) { | ||||
|     lhs.swap(rhs); | ||||
| } | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| // disable structured binding support for clang 6, it messes when specializing tuple_size | ||||
| #if !defined __clang_major__ || __clang_major__ > 6 | ||||
| namespace std { | ||||
|  | ||||
| /** | ||||
|  * @brief `std::tuple_size` specialization for `compressed_pair`s. | ||||
|  * @tparam First The type of the first element that the pair stores. | ||||
|  * @tparam Second The type of the second element that the pair stores. | ||||
|  */ | ||||
| template<typename First, typename Second> | ||||
| struct tuple_size<entt::compressed_pair<First, Second>>: integral_constant<size_t, 2u> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief `std::tuple_element` specialization for `compressed_pair`s. | ||||
|  * @tparam Index The index of the type to return. | ||||
|  * @tparam First The type of the first element that the pair stores. | ||||
|  * @tparam Second The type of the second element that the pair stores. | ||||
|  */ | ||||
| template<size_t Index, typename First, typename Second> | ||||
| struct tuple_element<Index, entt::compressed_pair<First, Second>>: conditional<Index == 0u, First, Second> { | ||||
|     static_assert(Index < 2u, "Index out of bounds"); | ||||
| }; | ||||
|  | ||||
| } // namespace std | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										97
									
								
								external/entt/entt/src/entt/core/enum.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								external/entt/entt/src/entt/core/enum.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| #ifndef ENTT_CORE_ENUM_HPP | ||||
| #define ENTT_CORE_ENUM_HPP | ||||
|  | ||||
| #include <type_traits> | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @brief Enable bitmask support for enum classes. | ||||
|  * @tparam Type The enum type for which to enable bitmask support. | ||||
|  */ | ||||
| template<typename Type, typename = void> | ||||
| struct enum_as_bitmask: std::false_type {}; | ||||
|  | ||||
| /*! @copydoc enum_as_bitmask */ | ||||
| template<typename Type> | ||||
| struct enum_as_bitmask<Type, std::void_t<decltype(Type::_entt_enum_as_bitmask)>>: std::is_enum<Type> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam Type The enum class type for which to enable bitmask support. | ||||
|  */ | ||||
| template<typename Type> | ||||
| inline constexpr bool enum_as_bitmask_v = enum_as_bitmask<Type>::value; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| /** | ||||
|  * @brief Operator available for enums for which bitmask support is enabled. | ||||
|  * @tparam Type Enum class type. | ||||
|  * @param lhs The first value to use. | ||||
|  * @param rhs The second value to use. | ||||
|  * @return The result of invoking the operator on the underlying types of the | ||||
|  * two values provided. | ||||
|  */ | ||||
| template<typename Type> | ||||
| [[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type> | ||||
| operator|(const Type lhs, const Type rhs) noexcept { | ||||
|     return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) | static_cast<std::underlying_type_t<Type>>(rhs)); | ||||
| } | ||||
|  | ||||
| /*! @copydoc operator| */ | ||||
| template<typename Type> | ||||
| [[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type> | ||||
| operator&(const Type lhs, const Type rhs) noexcept { | ||||
|     return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) & static_cast<std::underlying_type_t<Type>>(rhs)); | ||||
| } | ||||
|  | ||||
| /*! @copydoc operator| */ | ||||
| template<typename Type> | ||||
| [[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type> | ||||
| operator^(const Type lhs, const Type rhs) noexcept { | ||||
|     return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) ^ static_cast<std::underlying_type_t<Type>>(rhs)); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Operator available for enums for which bitmask support is enabled. | ||||
|  * @tparam Type Enum class type. | ||||
|  * @param value The value to use. | ||||
|  * @return The result of invoking the operator on the underlying types of the | ||||
|  * value provided. | ||||
|  */ | ||||
| template<typename Type> | ||||
| [[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type> | ||||
| operator~(const Type value) noexcept { | ||||
|     return static_cast<Type>(~static_cast<std::underlying_type_t<Type>>(value)); | ||||
| } | ||||
|  | ||||
| /*! @copydoc operator~ */ | ||||
| template<typename Type> | ||||
| [[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, bool> | ||||
| operator!(const Type value) noexcept { | ||||
|     return !static_cast<std::underlying_type_t<Type>>(value); | ||||
| } | ||||
|  | ||||
| /*! @copydoc operator| */ | ||||
| template<typename Type> | ||||
| constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &> | ||||
| operator|=(Type &lhs, const Type rhs) noexcept { | ||||
|     return (lhs = (lhs | rhs)); | ||||
| } | ||||
|  | ||||
| /*! @copydoc operator| */ | ||||
| template<typename Type> | ||||
| constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &> | ||||
| operator&=(Type &lhs, const Type rhs) noexcept { | ||||
|     return (lhs = (lhs & rhs)); | ||||
| } | ||||
|  | ||||
| /*! @copydoc operator| */ | ||||
| template<typename Type> | ||||
| constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &> | ||||
| operator^=(Type &lhs, const Type rhs) noexcept { | ||||
|     return (lhs = (lhs ^ rhs)); | ||||
| } | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										32
									
								
								external/entt/entt/src/entt/core/family.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								external/entt/entt/src/entt/core/family.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| #ifndef ENTT_CORE_FAMILY_HPP | ||||
| #define ENTT_CORE_FAMILY_HPP | ||||
|  | ||||
| #include "../config/config.h" | ||||
| #include "fwd.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @brief Dynamic identifier generator. | ||||
|  * | ||||
|  * Utility class template that can be used to assign unique identifiers to types | ||||
|  * at runtime. Use different specializations to create separate sets of | ||||
|  * identifiers. | ||||
|  */ | ||||
| template<typename...> | ||||
| class family { | ||||
|     inline static ENTT_MAYBE_ATOMIC(id_type) identifier{}; | ||||
|  | ||||
| public: | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using value_type = id_type; | ||||
|  | ||||
|     /*! @brief Statically generated unique identifier for the given type. */ | ||||
|     template<typename... Type> | ||||
|     // at the time I'm writing, clang crashes during compilation if auto is used instead of family_type | ||||
|     inline static const value_type value = identifier++; | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										20
									
								
								external/entt/entt/src/entt/core/fwd.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								external/entt/entt/src/entt/core/fwd.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #ifndef ENTT_CORE_FWD_HPP | ||||
| #define ENTT_CORE_FWD_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include "../config/config.h" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| template<std::size_t Len = sizeof(double[2]), std::size_t = alignof(double[2])> | ||||
| class basic_any; | ||||
|  | ||||
| /*! @brief Alias declaration for type identifiers. */ | ||||
| using id_type = ENTT_ID_TYPE; | ||||
|  | ||||
| /*! @brief Alias declaration for the most common use case. */ | ||||
| using any = basic_any<>; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										334
									
								
								external/entt/entt/src/entt/core/hashed_string.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								external/entt/entt/src/entt/core/hashed_string.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,334 @@ | ||||
| #ifndef ENTT_CORE_HASHED_STRING_HPP | ||||
| #define ENTT_CORE_HASHED_STRING_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <cstdint> | ||||
| #include "fwd.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename> | ||||
| struct fnv1a_traits; | ||||
|  | ||||
| template<> | ||||
| struct fnv1a_traits<std::uint32_t> { | ||||
|     using type = std::uint32_t; | ||||
|     static constexpr std::uint32_t offset = 2166136261; | ||||
|     static constexpr std::uint32_t prime = 16777619; | ||||
| }; | ||||
|  | ||||
| template<> | ||||
| struct fnv1a_traits<std::uint64_t> { | ||||
|     using type = std::uint64_t; | ||||
|     static constexpr std::uint64_t offset = 14695981039346656037ull; | ||||
|     static constexpr std::uint64_t prime = 1099511628211ull; | ||||
| }; | ||||
|  | ||||
| template<typename Char> | ||||
| struct basic_hashed_string { | ||||
|     using value_type = Char; | ||||
|     using size_type = std::size_t; | ||||
|     using hash_type = id_type; | ||||
|  | ||||
|     const value_type *repr; | ||||
|     size_type length; | ||||
|     hash_type hash; | ||||
| }; | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief Zero overhead unique identifier. | ||||
|  * | ||||
|  * A hashed string is a compile-time tool that allows users to use | ||||
|  * human-readable identifiers in the codebase while using their numeric | ||||
|  * counterparts at runtime.<br/> | ||||
|  * Because of that, a hashed string can also be used in constant expressions if | ||||
|  * required. | ||||
|  * | ||||
|  * @warning | ||||
|  * This class doesn't take ownership of user-supplied strings nor does it make a | ||||
|  * copy of them. | ||||
|  * | ||||
|  * @tparam Char Character type. | ||||
|  */ | ||||
| template<typename Char> | ||||
| class basic_hashed_string: internal::basic_hashed_string<Char> { | ||||
|     using base_type = internal::basic_hashed_string<Char>; | ||||
|     using hs_traits = internal::fnv1a_traits<id_type>; | ||||
|  | ||||
|     struct const_wrapper { | ||||
|         // non-explicit constructor on purpose | ||||
|         constexpr const_wrapper(const Char *str) noexcept | ||||
|             : repr{str} {} | ||||
|  | ||||
|         const Char *repr; | ||||
|     }; | ||||
|  | ||||
|     // Fowler–Noll–Vo hash function v. 1a - the good | ||||
|     [[nodiscard]] static constexpr auto helper(const Char *str) noexcept { | ||||
|         base_type base{str, 0u, hs_traits::offset}; | ||||
|  | ||||
|         for(; str[base.length]; ++base.length) { | ||||
|             base.hash = (base.hash ^ static_cast<hs_traits::type>(str[base.length])) * hs_traits::prime; | ||||
|         } | ||||
|  | ||||
|         return base; | ||||
|     } | ||||
|  | ||||
|     // Fowler–Noll–Vo hash function v. 1a - the good | ||||
|     [[nodiscard]] static constexpr auto helper(const Char *str, const std::size_t len) noexcept { | ||||
|         base_type base{str, len, hs_traits::offset}; | ||||
|  | ||||
|         for(size_type pos{}; pos < len; ++pos) { | ||||
|             base.hash = (base.hash ^ static_cast<hs_traits::type>(str[pos])) * hs_traits::prime; | ||||
|         } | ||||
|  | ||||
|         return base; | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! @brief Character type. */ | ||||
|     using value_type = typename base_type::value_type; | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using size_type = typename base_type::size_type; | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using hash_type = typename base_type::hash_type; | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns directly the numeric representation of a string view. | ||||
|      * @param str Human-readable identifier. | ||||
|      * @param len Length of the string to hash. | ||||
|      * @return The numeric representation of the string. | ||||
|      */ | ||||
|     [[nodiscard]] static constexpr hash_type value(const value_type *str, const size_type len) noexcept { | ||||
|         return basic_hashed_string{str, len}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns directly the numeric representation of a string. | ||||
|      * @tparam N Number of characters of the identifier. | ||||
|      * @param str Human-readable identifier. | ||||
|      * @return The numeric representation of the string. | ||||
|      */ | ||||
|     template<std::size_t N> | ||||
|     [[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) noexcept { | ||||
|         return basic_hashed_string{str}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns directly the numeric representation of a string. | ||||
|      * @param wrapper Helps achieving the purpose by relying on overloading. | ||||
|      * @return The numeric representation of the string. | ||||
|      */ | ||||
|     [[nodiscard]] static constexpr hash_type value(const_wrapper wrapper) noexcept { | ||||
|         return basic_hashed_string{wrapper}; | ||||
|     } | ||||
|  | ||||
|     /*! @brief Constructs an empty hashed string. */ | ||||
|     constexpr basic_hashed_string() noexcept | ||||
|         : base_type{} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a hashed string from a string view. | ||||
|      * @param str Human-readable identifier. | ||||
|      * @param len Length of the string to hash. | ||||
|      */ | ||||
|     constexpr basic_hashed_string(const value_type *str, const size_type len) noexcept | ||||
|         : base_type{helper(str, len)} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a hashed string from an array of const characters. | ||||
|      * @tparam N Number of characters of the identifier. | ||||
|      * @param str Human-readable identifier. | ||||
|      */ | ||||
|     template<std::size_t N> | ||||
|     constexpr basic_hashed_string(const value_type (&str)[N]) noexcept | ||||
|         : base_type{helper(str)} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Explicit constructor on purpose to avoid constructing a hashed | ||||
|      * string directly from a `const value_type *`. | ||||
|      * | ||||
|      * @warning | ||||
|      * The lifetime of the string is not extended nor is it copied. | ||||
|      * | ||||
|      * @param wrapper Helps achieving the purpose by relying on overloading. | ||||
|      */ | ||||
|     explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept | ||||
|         : base_type{helper(wrapper.repr)} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the size a hashed string. | ||||
|      * @return The size of the hashed string. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr size_type size() const noexcept { | ||||
|         return base_type::length; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the human-readable representation of a hashed string. | ||||
|      * @return The string used to initialize the hashed string. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr const value_type *data() const noexcept { | ||||
|         return base_type::repr; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the numeric representation of a hashed string. | ||||
|      * @return The numeric representation of the hashed string. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr hash_type value() const noexcept { | ||||
|         return base_type::hash; | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc data */ | ||||
|     [[nodiscard]] constexpr operator const value_type *() const noexcept { | ||||
|         return data(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the numeric representation of a hashed string. | ||||
|      * @return The numeric representation of the hashed string. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr operator hash_type() const noexcept { | ||||
|         return value(); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Deduction guide. | ||||
|  * @tparam Char Character type. | ||||
|  * @param str Human-readable identifier. | ||||
|  * @param len Length of the string to hash. | ||||
|  */ | ||||
| template<typename Char> | ||||
| basic_hashed_string(const Char *str, const std::size_t len) -> basic_hashed_string<Char>; | ||||
|  | ||||
| /** | ||||
|  * @brief Deduction guide. | ||||
|  * @tparam Char Character type. | ||||
|  * @tparam N Number of characters of the identifier. | ||||
|  * @param str Human-readable identifier. | ||||
|  */ | ||||
| template<typename Char, std::size_t N> | ||||
| basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string<Char>; | ||||
|  | ||||
| /** | ||||
|  * @brief Compares two hashed strings. | ||||
|  * @tparam Char Character type. | ||||
|  * @param lhs A valid hashed string. | ||||
|  * @param rhs A valid hashed string. | ||||
|  * @return True if the two hashed strings are identical, false otherwise. | ||||
|  */ | ||||
| template<typename Char> | ||||
| [[nodiscard]] constexpr bool operator==(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept { | ||||
|     return lhs.value() == rhs.value(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compares two hashed strings. | ||||
|  * @tparam Char Character type. | ||||
|  * @param lhs A valid hashed string. | ||||
|  * @param rhs A valid hashed string. | ||||
|  * @return True if the two hashed strings differ, false otherwise. | ||||
|  */ | ||||
| template<typename Char> | ||||
| [[nodiscard]] constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept { | ||||
|     return !(lhs == rhs); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compares two hashed strings. | ||||
|  * @tparam Char Character type. | ||||
|  * @param lhs A valid hashed string. | ||||
|  * @param rhs A valid hashed string. | ||||
|  * @return True if the first element is less than the second, false otherwise. | ||||
|  */ | ||||
| template<typename Char> | ||||
| [[nodiscard]] constexpr bool operator<(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept { | ||||
|     return lhs.value() < rhs.value(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compares two hashed strings. | ||||
|  * @tparam Char Character type. | ||||
|  * @param lhs A valid hashed string. | ||||
|  * @param rhs A valid hashed string. | ||||
|  * @return True if the first element is less than or equal to the second, false | ||||
|  * otherwise. | ||||
|  */ | ||||
| template<typename Char> | ||||
| [[nodiscard]] constexpr bool operator<=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept { | ||||
|     return !(rhs < lhs); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compares two hashed strings. | ||||
|  * @tparam Char Character type. | ||||
|  * @param lhs A valid hashed string. | ||||
|  * @param rhs A valid hashed string. | ||||
|  * @return True if the first element is greater than the second, false | ||||
|  * otherwise. | ||||
|  */ | ||||
| template<typename Char> | ||||
| [[nodiscard]] constexpr bool operator>(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept { | ||||
|     return rhs < lhs; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compares two hashed strings. | ||||
|  * @tparam Char Character type. | ||||
|  * @param lhs A valid hashed string. | ||||
|  * @param rhs A valid hashed string. | ||||
|  * @return True if the first element is greater than or equal to the second, | ||||
|  * false otherwise. | ||||
|  */ | ||||
| template<typename Char> | ||||
| [[nodiscard]] constexpr bool operator>=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept { | ||||
|     return !(lhs < rhs); | ||||
| } | ||||
|  | ||||
| /*! @brief Aliases for common character types. */ | ||||
| using hashed_string = basic_hashed_string<char>; | ||||
|  | ||||
| /*! @brief Aliases for common character types. */ | ||||
| using hashed_wstring = basic_hashed_string<wchar_t>; | ||||
|  | ||||
| inline namespace literals { | ||||
|  | ||||
| /** | ||||
|  * @brief User defined literal for hashed strings. | ||||
|  * @param str The literal without its suffix. | ||||
|  * @return A properly initialized hashed string. | ||||
|  */ | ||||
| [[nodiscard]] constexpr hashed_string operator"" _hs(const char *str, std::size_t) noexcept { | ||||
|     return hashed_string{str}; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief User defined literal for hashed wstrings. | ||||
|  * @param str The literal without its suffix. | ||||
|  * @return A properly initialized hashed wstring. | ||||
|  */ | ||||
| [[nodiscard]] constexpr hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) noexcept { | ||||
|     return hashed_wstring{str}; | ||||
| } | ||||
|  | ||||
| } // namespace literals | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										35
									
								
								external/entt/entt/src/entt/core/ident.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								external/entt/entt/src/entt/core/ident.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| #ifndef ENTT_CORE_IDENT_HPP | ||||
| #define ENTT_CORE_IDENT_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include "fwd.hpp" | ||||
| #include "type_traits.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @brief Type integral identifiers. | ||||
|  * @tparam Type List of types for which to generate identifiers. | ||||
|  */ | ||||
| template<typename... Type> | ||||
| class ident { | ||||
|     template<typename Curr, std::size_t... Index> | ||||
|     [[nodiscard]] static constexpr id_type get(std::index_sequence<Index...>) noexcept { | ||||
|         static_assert((std::is_same_v<Curr, Type> || ...), "Invalid type"); | ||||
|         return (0 + ... + (std::is_same_v<Curr, type_list_element_t<Index, type_list<std::decay_t<Type>...>>> ? id_type{Index} : id_type{})); | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using value_type = id_type; | ||||
|  | ||||
|     /*! @brief Statically generated unique identifier for the given type. */ | ||||
|     template<typename Curr> | ||||
|     static constexpr value_type value = get<std::decay_t<Curr>>(std::index_sequence_for<Type...>{}); | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										197
									
								
								external/entt/entt/src/entt/core/iterator.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								external/entt/entt/src/entt/core/iterator.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,197 @@ | ||||
| #ifndef ENTT_CORE_ITERATOR_HPP | ||||
| #define ENTT_CORE_ITERATOR_HPP | ||||
|  | ||||
| #include <iterator> | ||||
| #include <memory> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type to use as pointer with input iterators. | ||||
|  * @tparam Type of wrapped value. | ||||
|  */ | ||||
| template<typename Type> | ||||
| struct input_iterator_pointer final { | ||||
|     /*! @brief Value type. */ | ||||
|     using value_type = Type; | ||||
|     /*! @brief Pointer type. */ | ||||
|     using pointer = Type *; | ||||
|     /*! @brief Reference type. */ | ||||
|     using reference = Type &; | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a proxy object by move. | ||||
|      * @param val Value to use to initialize the proxy object. | ||||
|      */ | ||||
|     constexpr input_iterator_pointer(value_type &&val) noexcept(std::is_nothrow_move_constructible_v<value_type>) | ||||
|         : value{std::move(val)} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Access operator for accessing wrapped values. | ||||
|      * @return A pointer to the wrapped value. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr pointer operator->() noexcept { | ||||
|         return std::addressof(value); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Dereference operator for accessing wrapped values. | ||||
|      * @return A reference to the wrapped value. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr reference operator*() noexcept { | ||||
|         return value; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     Type value; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Plain iota iterator (waiting for C++20). | ||||
|  * @tparam Type Value type. | ||||
|  */ | ||||
| template<typename Type> | ||||
| class iota_iterator final { | ||||
|     static_assert(std::is_integral_v<Type>, "Not an integral type"); | ||||
|  | ||||
| public: | ||||
|     /*! @brief Value type, likely an integral one. */ | ||||
|     using value_type = Type; | ||||
|     /*! @brief Invalid pointer type. */ | ||||
|     using pointer = void; | ||||
|     /*! @brief Non-reference type, same as value type. */ | ||||
|     using reference = value_type; | ||||
|     /*! @brief Difference type. */ | ||||
|     using difference_type = std::ptrdiff_t; | ||||
|     /*! @brief Iterator category. */ | ||||
|     using iterator_category = std::input_iterator_tag; | ||||
|  | ||||
|     /*! @brief Default constructor. */ | ||||
|     constexpr iota_iterator() noexcept | ||||
|         : current{} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an iota iterator from a given value. | ||||
|      * @param init The initial value assigned to the iota iterator. | ||||
|      */ | ||||
|     constexpr iota_iterator(const value_type init) noexcept | ||||
|         : current{init} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Pre-increment operator. | ||||
|      * @return This iota iterator. | ||||
|      */ | ||||
|     constexpr iota_iterator &operator++() noexcept { | ||||
|         return ++current, *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Post-increment operator. | ||||
|      * @return This iota iterator. | ||||
|      */ | ||||
|     constexpr iota_iterator operator++(int) noexcept { | ||||
|         iota_iterator orig = *this; | ||||
|         return ++(*this), orig; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Dereference operator. | ||||
|      * @return The underlying value. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr reference operator*() const noexcept { | ||||
|         return current; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     value_type current; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Comparison operator. | ||||
|  * @tparam Type Value type of the iota iterator. | ||||
|  * @param lhs A properly initialized iota iterator. | ||||
|  * @param rhs A properly initialized iota iterator. | ||||
|  * @return True if the two iterators are identical, false otherwise. | ||||
|  */ | ||||
| template<typename Type> | ||||
| [[nodiscard]] constexpr bool operator==(const iota_iterator<Type> &lhs, const iota_iterator<Type> &rhs) noexcept { | ||||
|     return *lhs == *rhs; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Comparison operator. | ||||
|  * @tparam Type Value type of the iota iterator. | ||||
|  * @param lhs A properly initialized iota iterator. | ||||
|  * @param rhs A properly initialized iota iterator. | ||||
|  * @return True if the two iterators differ, false otherwise. | ||||
|  */ | ||||
| template<typename Type> | ||||
| [[nodiscard]] constexpr bool operator!=(const iota_iterator<Type> &lhs, const iota_iterator<Type> &rhs) noexcept { | ||||
|     return !(lhs == rhs); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Utility class to create an iterable object from a pair of iterators. | ||||
|  * @tparam It Type of iterator. | ||||
|  * @tparam Sentinel Type of sentinel. | ||||
|  */ | ||||
| template<typename It, typename Sentinel = It> | ||||
| struct iterable_adaptor final { | ||||
|     /*! @brief Value type. */ | ||||
|     using value_type = typename std::iterator_traits<It>::value_type; | ||||
|     /*! @brief Iterator type. */ | ||||
|     using iterator = It; | ||||
|     /*! @brief Sentinel type. */ | ||||
|     using sentinel = Sentinel; | ||||
|  | ||||
|     /*! @brief Default constructor. */ | ||||
|     constexpr iterable_adaptor() noexcept(std::is_nothrow_default_constructible_v<iterator> &&std::is_nothrow_default_constructible_v<sentinel>) | ||||
|         : first{}, | ||||
|           last{} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Creates an iterable object from a pair of iterators. | ||||
|      * @param from Begin iterator. | ||||
|      * @param to End iterator. | ||||
|      */ | ||||
|     constexpr iterable_adaptor(iterator from, sentinel to) noexcept(std::is_nothrow_move_constructible_v<iterator> &&std::is_nothrow_move_constructible_v<sentinel>) | ||||
|         : first{std::move(from)}, | ||||
|           last{std::move(to)} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the beginning. | ||||
|      * @return An iterator to the first element of the range. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr iterator begin() const noexcept { | ||||
|         return first; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the end. | ||||
|      * @return An iterator to the element following the last element of the | ||||
|      * range. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr sentinel end() const noexcept { | ||||
|         return last; | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc begin */ | ||||
|     [[nodiscard]] constexpr iterator cbegin() const noexcept { | ||||
|         return begin(); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc end */ | ||||
|     [[nodiscard]] constexpr sentinel cend() const noexcept { | ||||
|         return end(); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     It first; | ||||
|     Sentinel last; | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										289
									
								
								external/entt/entt/src/entt/core/memory.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								external/entt/entt/src/entt/core/memory.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,289 @@ | ||||
| #ifndef ENTT_CORE_MEMORY_HPP | ||||
| #define ENTT_CORE_MEMORY_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <limits> | ||||
| #include <memory> | ||||
| #include <tuple> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include "../config/config.h" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @brief Checks whether a value is a power of two or not. | ||||
|  * @param value A value that may or may not be a power of two. | ||||
|  * @return True if the value is a power of two, false otherwise. | ||||
|  */ | ||||
| [[nodiscard]] inline constexpr bool is_power_of_two(const std::size_t value) noexcept { | ||||
|     return value && ((value & (value - 1)) == 0); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Computes the smallest power of two greater than or equal to a value. | ||||
|  * @param value The value to use. | ||||
|  * @return The smallest power of two greater than or equal to the given value. | ||||
|  */ | ||||
| [[nodiscard]] inline constexpr std::size_t next_power_of_two(const std::size_t value) noexcept { | ||||
|     ENTT_ASSERT_CONSTEXPR(value < (std::size_t{1u} << (std::numeric_limits<std::size_t>::digits - 1)), "Numeric limits exceeded"); | ||||
|     std::size_t curr = value - (value != 0u); | ||||
|  | ||||
|     for(int next = 1; next < std::numeric_limits<std::size_t>::digits; next = next * 2) { | ||||
|         curr |= curr >> next; | ||||
|     } | ||||
|  | ||||
|     return ++curr; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Fast module utility function (powers of two only). | ||||
|  * @param value A value for which to calculate the modulus. | ||||
|  * @param mod _Modulus_, it must be a power of two. | ||||
|  * @return The common remainder. | ||||
|  */ | ||||
| [[nodiscard]] inline constexpr std::size_t fast_mod(const std::size_t value, const std::size_t mod) noexcept { | ||||
|     ENTT_ASSERT_CONSTEXPR(is_power_of_two(mod), "Value must be a power of two"); | ||||
|     return value & (mod - 1u); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Unwraps fancy pointers, does nothing otherwise (waiting for C++20). | ||||
|  * @tparam Type Pointer type. | ||||
|  * @param ptr Fancy or raw pointer. | ||||
|  * @return A raw pointer that represents the address of the original pointer. | ||||
|  */ | ||||
| template<typename Type> | ||||
| [[nodiscard]] constexpr auto to_address(Type &&ptr) noexcept { | ||||
|     if constexpr(std::is_pointer_v<std::decay_t<Type>>) { | ||||
|         return ptr; | ||||
|     } else { | ||||
|         return to_address(std::forward<Type>(ptr).operator->()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Utility function to design allocation-aware containers. | ||||
|  * @tparam Allocator Type of allocator. | ||||
|  * @param lhs A valid allocator. | ||||
|  * @param rhs Another valid allocator. | ||||
|  */ | ||||
| template<typename Allocator> | ||||
| constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { | ||||
|     if constexpr(std::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) { | ||||
|         lhs = rhs; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Utility function to design allocation-aware containers. | ||||
|  * @tparam Allocator Type of allocator. | ||||
|  * @param lhs A valid allocator. | ||||
|  * @param rhs Another valid allocator. | ||||
|  */ | ||||
| template<typename Allocator> | ||||
| constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { | ||||
|     if constexpr(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) { | ||||
|         lhs = std::move(rhs); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Utility function to design allocation-aware containers. | ||||
|  * @tparam Allocator Type of allocator. | ||||
|  * @param lhs A valid allocator. | ||||
|  * @param rhs Another valid allocator. | ||||
|  */ | ||||
| template<typename Allocator> | ||||
| constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { | ||||
|     if constexpr(std::allocator_traits<Allocator>::propagate_on_container_swap::value) { | ||||
|         using std::swap; | ||||
|         swap(lhs, rhs); | ||||
|     } else { | ||||
|         ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Deleter for allocator-aware unique pointers (waiting for C++20). | ||||
|  * @tparam Args Types of arguments to use to construct the object. | ||||
|  */ | ||||
| template<typename Allocator> | ||||
| struct allocation_deleter: private Allocator { | ||||
|     /*! @brief Allocator type. */ | ||||
|     using allocator_type = Allocator; | ||||
|     /*! @brief Pointer type. */ | ||||
|     using pointer = typename std::allocator_traits<Allocator>::pointer; | ||||
|  | ||||
|     /** | ||||
|      * @brief Inherited constructors. | ||||
|      * @param alloc The allocator to use. | ||||
|      */ | ||||
|     constexpr allocation_deleter(const allocator_type &alloc) noexcept(std::is_nothrow_copy_constructible_v<allocator_type>) | ||||
|         : Allocator{alloc} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Destroys the pointed object and deallocates its memory. | ||||
|      * @param ptr A valid pointer to an object of the given type. | ||||
|      */ | ||||
|     constexpr void operator()(pointer ptr) noexcept(std::is_nothrow_destructible_v<typename allocator_type::value_type>) { | ||||
|         using alloc_traits = typename std::allocator_traits<Allocator>; | ||||
|         alloc_traits::destroy(*this, to_address(ptr)); | ||||
|         alloc_traits::deallocate(*this, ptr, 1u); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Allows `std::unique_ptr` to use allocators (waiting for C++20). | ||||
|  * @tparam Type Type of object to allocate for and to construct. | ||||
|  * @tparam Allocator Type of allocator used to manage memory and elements. | ||||
|  * @tparam Args Types of arguments to use to construct the object. | ||||
|  * @param allocator The allocator to use. | ||||
|  * @param args Parameters to use to construct the object. | ||||
|  * @return A properly initialized unique pointer with a custom deleter. | ||||
|  */ | ||||
| template<typename Type, typename Allocator, typename... Args> | ||||
| ENTT_CONSTEXPR auto allocate_unique(Allocator &allocator, Args &&...args) { | ||||
|     static_assert(!std::is_array_v<Type>, "Array types are not supported"); | ||||
|  | ||||
|     using alloc_traits = typename std::allocator_traits<Allocator>::template rebind_traits<Type>; | ||||
|     using allocator_type = typename alloc_traits::allocator_type; | ||||
|  | ||||
|     allocator_type alloc{allocator}; | ||||
|     auto ptr = alloc_traits::allocate(alloc, 1u); | ||||
|  | ||||
|     ENTT_TRY { | ||||
|         alloc_traits::construct(alloc, to_address(ptr), std::forward<Args>(args)...); | ||||
|     } | ||||
|     ENTT_CATCH { | ||||
|         alloc_traits::deallocate(alloc, ptr, 1u); | ||||
|         ENTT_THROW; | ||||
|     } | ||||
|  | ||||
|     return std::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc}; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename Type> | ||||
| struct uses_allocator_construction { | ||||
|     template<typename Allocator, typename... Params> | ||||
|     static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept { | ||||
|         if constexpr(!std::uses_allocator_v<Type, Allocator> && std::is_constructible_v<Type, Params...>) { | ||||
|             return std::forward_as_tuple(std::forward<Params>(params)...); | ||||
|         } else { | ||||
|             static_assert(std::uses_allocator_v<Type, Allocator>, "Ill-formed request"); | ||||
|  | ||||
|             if constexpr(std::is_constructible_v<Type, std::allocator_arg_t, const Allocator &, Params...>) { | ||||
|                 return std::tuple<std::allocator_arg_t, const Allocator &, Params &&...>{std::allocator_arg, allocator, std::forward<Params>(params)...}; | ||||
|             } else { | ||||
|                 static_assert(std::is_constructible_v<Type, Params..., const Allocator &>, "Ill-formed request"); | ||||
|                 return std::forward_as_tuple(std::forward<Params>(params)..., allocator); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template<typename Type, typename Other> | ||||
| struct uses_allocator_construction<std::pair<Type, Other>> { | ||||
|     using type = std::pair<Type, Other>; | ||||
|  | ||||
|     template<typename Allocator, typename First, typename Second> | ||||
|     static constexpr auto args(const Allocator &allocator, std::piecewise_construct_t, First &&first, Second &&second) noexcept { | ||||
|         return std::make_tuple( | ||||
|             std::piecewise_construct, | ||||
|             std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Type>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<First>(first)), | ||||
|             std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Other>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<Second>(second))); | ||||
|     } | ||||
|  | ||||
|     template<typename Allocator> | ||||
|     static constexpr auto args(const Allocator &allocator) noexcept { | ||||
|         return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::tuple<>{}, std::tuple<>{}); | ||||
|     } | ||||
|  | ||||
|     template<typename Allocator, typename First, typename Second> | ||||
|     static constexpr auto args(const Allocator &allocator, First &&first, Second &&second) noexcept { | ||||
|         return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::forward<First>(first)), std::forward_as_tuple(std::forward<Second>(second))); | ||||
|     } | ||||
|  | ||||
|     template<typename Allocator, typename First, typename Second> | ||||
|     static constexpr auto args(const Allocator &allocator, const std::pair<First, Second> &value) noexcept { | ||||
|         return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(value.first), std::forward_as_tuple(value.second)); | ||||
|     } | ||||
|  | ||||
|     template<typename Allocator, typename First, typename Second> | ||||
|     static constexpr auto args(const Allocator &allocator, std::pair<First, Second> &&value) noexcept { | ||||
|         return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::move(value.first)), std::forward_as_tuple(std::move(value.second))); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief Uses-allocator construction utility (waiting for C++20). | ||||
|  * | ||||
|  * Primarily intended for internal use. Prepares the argument list needed to | ||||
|  * create an object of a given type by means of uses-allocator construction. | ||||
|  * | ||||
|  * @tparam Type Type to return arguments for. | ||||
|  * @tparam Allocator Type of allocator used to manage memory and elements. | ||||
|  * @tparam Args Types of arguments to use to construct the object. | ||||
|  * @param allocator The allocator to use. | ||||
|  * @param args Parameters to use to construct the object. | ||||
|  * @return The arguments needed to create an object of the given type. | ||||
|  */ | ||||
| template<typename Type, typename Allocator, typename... Args> | ||||
| constexpr auto uses_allocator_construction_args(const Allocator &allocator, Args &&...args) noexcept { | ||||
|     return internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Uses-allocator construction utility (waiting for C++20). | ||||
|  * | ||||
|  * Primarily intended for internal use. Creates an object of a given type by | ||||
|  * means of uses-allocator construction. | ||||
|  * | ||||
|  * @tparam Type Type of object to create. | ||||
|  * @tparam Allocator Type of allocator used to manage memory and elements. | ||||
|  * @tparam Args Types of arguments to use to construct the object. | ||||
|  * @param allocator The allocator to use. | ||||
|  * @param args Parameters to use to construct the object. | ||||
|  * @return A newly created object of the given type. | ||||
|  */ | ||||
| template<typename Type, typename Allocator, typename... Args> | ||||
| constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args) { | ||||
|     return std::make_from_tuple<Type>(internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...)); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Uses-allocator construction utility (waiting for C++20). | ||||
|  * | ||||
|  * Primarily intended for internal use. Creates an object of a given type by | ||||
|  * means of uses-allocator construction at an uninitialized memory location. | ||||
|  * | ||||
|  * @tparam Type Type of object to create. | ||||
|  * @tparam Allocator Type of allocator used to manage memory and elements. | ||||
|  * @tparam Args Types of arguments to use to construct the object. | ||||
|  * @param value Memory location in which to place the object. | ||||
|  * @param allocator The allocator to use. | ||||
|  * @param args Parameters to use to construct the object. | ||||
|  * @return A pointer to the newly created object of the given type. | ||||
|  */ | ||||
| template<typename Type, typename Allocator, typename... Args> | ||||
| constexpr Type *uninitialized_construct_using_allocator(Type *value, const Allocator &allocator, Args &&...args) { | ||||
|     return std::apply([value](auto &&...curr) { return new(value) Type(std::forward<decltype(curr)>(curr)...); }, internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...)); | ||||
| } | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										56
									
								
								external/entt/entt/src/entt/core/monostate.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								external/entt/entt/src/entt/core/monostate.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| #ifndef ENTT_CORE_MONOSTATE_HPP | ||||
| #define ENTT_CORE_MONOSTATE_HPP | ||||
|  | ||||
| #include "../config/config.h" | ||||
| #include "fwd.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @brief Minimal implementation of the monostate pattern. | ||||
|  * | ||||
|  * A minimal, yet complete configuration system built on top of the monostate | ||||
|  * pattern. Thread safe by design, it works only with basic types like `int`s or | ||||
|  * `bool`s.<br/> | ||||
|  * Multiple types and therefore more than one value can be associated with a | ||||
|  * single key. Because of this, users must pay attention to use the same type | ||||
|  * both during an assignment and when they try to read back their data. | ||||
|  * Otherwise, they can incur in unexpected results. | ||||
|  */ | ||||
| template<id_type> | ||||
| struct monostate { | ||||
|     /** | ||||
|      * @brief Assigns a value of a specific type to a given key. | ||||
|      * @tparam Type Type of the value to assign. | ||||
|      * @param val User data to assign to the given key. | ||||
|      */ | ||||
|     template<typename Type> | ||||
|     void operator=(Type val) const noexcept { | ||||
|         value<Type> = val; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Gets a value of a specific type for a given key. | ||||
|      * @tparam Type Type of the value to get. | ||||
|      * @return Stored value, if any. | ||||
|      */ | ||||
|     template<typename Type> | ||||
|     operator Type() const noexcept { | ||||
|         return value<Type>; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     template<typename Type> | ||||
|     inline static ENTT_MAYBE_ATOMIC(Type) value{}; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam Value Value used to differentiate between different variables. | ||||
|  */ | ||||
| template<id_type Value> | ||||
| inline monostate<Value> monostate_v = {}; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										103
									
								
								external/entt/entt/src/entt/core/tuple.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								external/entt/entt/src/entt/core/tuple.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| #ifndef ENTT_CORE_TUPLE_HPP | ||||
| #define ENTT_CORE_TUPLE_HPP | ||||
|  | ||||
| #include <tuple> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename> | ||||
| struct is_tuple_impl: std::false_type {}; | ||||
|  | ||||
| template<typename... Args> | ||||
| struct is_tuple_impl<std::tuple<Args...>>: std::true_type {}; | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief Provides the member constant `value` to true if a given type is a | ||||
|  * tuple, false otherwise. | ||||
|  * @tparam Type The type to test. | ||||
|  */ | ||||
| template<typename Type> | ||||
| struct is_tuple: internal::is_tuple_impl<std::remove_cv_t<Type>> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam Type The type to test. | ||||
|  */ | ||||
| template<typename Type> | ||||
| inline constexpr bool is_tuple_v = is_tuple<Type>::value; | ||||
|  | ||||
| /** | ||||
|  * @brief Utility function to unwrap tuples of a single element. | ||||
|  * @tparam Type Tuple type of any sizes. | ||||
|  * @param value A tuple object of the given type. | ||||
|  * @return The tuple itself if it contains more than one element, the first | ||||
|  * element otherwise. | ||||
|  */ | ||||
| template<typename Type> | ||||
| constexpr decltype(auto) unwrap_tuple(Type &&value) noexcept { | ||||
|     if constexpr(std::tuple_size_v<std::remove_reference_t<Type>> == 1u) { | ||||
|         return std::get<0>(std::forward<Type>(value)); | ||||
|     } else { | ||||
|         return std::forward<Type>(value); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Utility class to forward-and-apply tuple objects. | ||||
|  * @tparam Func Type of underlying invocable object. | ||||
|  */ | ||||
| template<typename Func> | ||||
| struct forward_apply: private Func { | ||||
|     /** | ||||
|      * @brief Constructs a forward-and-apply object. | ||||
|      * @tparam Args Types of arguments to use to construct the new instance. | ||||
|      * @param args Parameters to use to construct the instance. | ||||
|      */ | ||||
|     template<class... Args> | ||||
|     constexpr forward_apply(Args &&...args) noexcept(std::is_nothrow_constructible_v<Func, Args...>) | ||||
|         : Func{std::forward<Args>(args)...} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Forwards and applies the arguments with the underlying function. | ||||
|      * @tparam Type Tuple-like type to forward to the underlying function. | ||||
|      * @param args Parameters to forward to the underlying function. | ||||
|      * @return Return value of the underlying function, if any. | ||||
|      */ | ||||
|     template<class Type> | ||||
|     constexpr decltype(auto) operator()(Type &&args) noexcept(noexcept(std::apply(std::declval<Func &>(), args))) { | ||||
|         return std::apply(static_cast<Func &>(*this), std::forward<Type>(args)); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc operator()() */ | ||||
|     template<class Type> | ||||
|     constexpr decltype(auto) operator()(Type &&args) const noexcept(noexcept(std::apply(std::declval<const Func &>(), args))) { | ||||
|         return std::apply(static_cast<const Func &>(*this), std::forward<Type>(args)); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Deduction guide. | ||||
|  * @tparam Func Type of underlying invocable object. | ||||
|  */ | ||||
| template<typename Func> | ||||
| forward_apply(Func) -> forward_apply<std::remove_reference_t<std::remove_cv_t<Func>>>; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										274
									
								
								external/entt/entt/src/entt/core/type_info.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								external/entt/entt/src/entt/core/type_info.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,274 @@ | ||||
| #ifndef ENTT_CORE_TYPE_INFO_HPP | ||||
| #define ENTT_CORE_TYPE_INFO_HPP | ||||
|  | ||||
| #include <string_view> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include "../config/config.h" | ||||
| #include "../core/attribute.h" | ||||
| #include "fwd.hpp" | ||||
| #include "hashed_string.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| struct ENTT_API type_index final { | ||||
|     [[nodiscard]] static id_type next() noexcept { | ||||
|         static ENTT_MAYBE_ATOMIC(id_type) value{}; | ||||
|         return value++; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template<typename Type> | ||||
| [[nodiscard]] constexpr auto stripped_type_name() noexcept { | ||||
| #if defined ENTT_PRETTY_FUNCTION | ||||
|     std::string_view pretty_function{ENTT_PRETTY_FUNCTION}; | ||||
|     auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1); | ||||
|     auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); | ||||
|     return value; | ||||
| #else | ||||
|     return std::string_view{""}; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')> | ||||
| [[nodiscard]] static constexpr std::string_view type_name(int) noexcept { | ||||
|     constexpr auto value = stripped_type_name<Type>(); | ||||
|     return value; | ||||
| } | ||||
|  | ||||
| template<typename Type> | ||||
| [[nodiscard]] static std::string_view type_name(char) noexcept { | ||||
|     static const auto value = stripped_type_name<Type>(); | ||||
|     return value; | ||||
| } | ||||
|  | ||||
| template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')> | ||||
| [[nodiscard]] static constexpr id_type type_hash(int) noexcept { | ||||
|     constexpr auto stripped = stripped_type_name<Type>(); | ||||
|     constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); | ||||
|     return value; | ||||
| } | ||||
|  | ||||
| template<typename Type> | ||||
| [[nodiscard]] static id_type type_hash(char) noexcept { | ||||
|     static const auto value = [](const auto stripped) { | ||||
|         return hashed_string::value(stripped.data(), stripped.size()); | ||||
|     }(stripped_type_name<Type>()); | ||||
|     return value; | ||||
| } | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief Type sequential identifier. | ||||
|  * @tparam Type Type for which to generate a sequential identifier. | ||||
|  */ | ||||
| template<typename Type, typename = void> | ||||
| struct ENTT_API type_index final { | ||||
|     /** | ||||
|      * @brief Returns the sequential identifier of a given type. | ||||
|      * @return The sequential identifier of a given type. | ||||
|      */ | ||||
|     [[nodiscard]] static id_type value() noexcept { | ||||
|         static const id_type value = internal::type_index::next(); | ||||
|         return value; | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc value */ | ||||
|     [[nodiscard]] constexpr operator id_type() const noexcept { | ||||
|         return value(); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Type hash. | ||||
|  * @tparam Type Type for which to generate a hash value. | ||||
|  */ | ||||
| template<typename Type, typename = void> | ||||
| struct type_hash final { | ||||
|     /** | ||||
|      * @brief Returns the numeric representation of a given type. | ||||
|      * @return The numeric representation of the given type. | ||||
|      */ | ||||
| #if defined ENTT_PRETTY_FUNCTION | ||||
|     [[nodiscard]] static constexpr id_type value() noexcept { | ||||
|         return internal::type_hash<Type>(0); | ||||
| #else | ||||
|     [[nodiscard]] static constexpr id_type value() noexcept { | ||||
|         return type_index<Type>::value(); | ||||
| #endif | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc value */ | ||||
|     [[nodiscard]] constexpr operator id_type() const noexcept { | ||||
|         return value(); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Type name. | ||||
|  * @tparam Type Type for which to generate a name. | ||||
|  */ | ||||
| template<typename Type, typename = void> | ||||
| struct type_name final { | ||||
|     /** | ||||
|      * @brief Returns the name of a given type. | ||||
|      * @return The name of the given type. | ||||
|      */ | ||||
|     [[nodiscard]] static constexpr std::string_view value() noexcept { | ||||
|         return internal::type_name<Type>(0); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc value */ | ||||
|     [[nodiscard]] constexpr operator std::string_view() const noexcept { | ||||
|         return value(); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /*! @brief Implementation specific information about a type. */ | ||||
| struct type_info final { | ||||
|     /** | ||||
|      * @brief Constructs a type info object for a given type. | ||||
|      * @tparam Type Type for which to construct a type info object. | ||||
|      */ | ||||
|     template<typename Type> | ||||
|     constexpr type_info(std::in_place_type_t<Type>) noexcept | ||||
|         : seq{type_index<std::remove_cv_t<std::remove_reference_t<Type>>>::value()}, | ||||
|           identifier{type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value()}, | ||||
|           alias{type_name<std::remove_cv_t<std::remove_reference_t<Type>>>::value()} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Type index. | ||||
|      * @return Type index. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr id_type index() const noexcept { | ||||
|         return seq; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Type hash. | ||||
|      * @return Type hash. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr id_type hash() const noexcept { | ||||
|         return identifier; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Type name. | ||||
|      * @return Type name. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr std::string_view name() const noexcept { | ||||
|         return alias; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     id_type seq; | ||||
|     id_type identifier; | ||||
|     std::string_view alias; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Compares the contents of two type info objects. | ||||
|  * @param lhs A type info object. | ||||
|  * @param rhs A type info object. | ||||
|  * @return True if the two type info objects are identical, false otherwise. | ||||
|  */ | ||||
| [[nodiscard]] inline constexpr bool operator==(const type_info &lhs, const type_info &rhs) noexcept { | ||||
|     return lhs.hash() == rhs.hash(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compares the contents of two type info objects. | ||||
|  * @param lhs A type info object. | ||||
|  * @param rhs A type info object. | ||||
|  * @return True if the two type info objects differ, false otherwise. | ||||
|  */ | ||||
| [[nodiscard]] inline constexpr bool operator!=(const type_info &lhs, const type_info &rhs) noexcept { | ||||
|     return !(lhs == rhs); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compares two type info objects. | ||||
|  * @param lhs A valid type info object. | ||||
|  * @param rhs A valid type info object. | ||||
|  * @return True if the first element is less than the second, false otherwise. | ||||
|  */ | ||||
| [[nodiscard]] constexpr bool operator<(const type_info &lhs, const type_info &rhs) noexcept { | ||||
|     return lhs.index() < rhs.index(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compares two type info objects. | ||||
|  * @param lhs A valid type info object. | ||||
|  * @param rhs A valid type info object. | ||||
|  * @return True if the first element is less than or equal to the second, false | ||||
|  * otherwise. | ||||
|  */ | ||||
| [[nodiscard]] constexpr bool operator<=(const type_info &lhs, const type_info &rhs) noexcept { | ||||
|     return !(rhs < lhs); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compares two type info objects. | ||||
|  * @param lhs A valid type info object. | ||||
|  * @param rhs A valid type info object. | ||||
|  * @return True if the first element is greater than the second, false | ||||
|  * otherwise. | ||||
|  */ | ||||
| [[nodiscard]] constexpr bool operator>(const type_info &lhs, const type_info &rhs) noexcept { | ||||
|     return rhs < lhs; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compares two type info objects. | ||||
|  * @param lhs A valid type info object. | ||||
|  * @param rhs A valid type info object. | ||||
|  * @return True if the first element is greater than or equal to the second, | ||||
|  * false otherwise. | ||||
|  */ | ||||
| [[nodiscard]] constexpr bool operator>=(const type_info &lhs, const type_info &rhs) noexcept { | ||||
|     return !(lhs < rhs); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Returns the type info object associated to a given type. | ||||
|  * | ||||
|  * The returned element refers to an object with static storage duration.<br/> | ||||
|  * The type doesn't need to be a complete type. If the type is a reference, the | ||||
|  * result refers to the referenced type. In all cases, top-level cv-qualifiers | ||||
|  * are ignored. | ||||
|  * | ||||
|  * @tparam Type Type for which to generate a type info object. | ||||
|  * @return A reference to a properly initialized type info object. | ||||
|  */ | ||||
| template<typename Type> | ||||
| [[nodiscard]] const type_info &type_id() noexcept { | ||||
|     if constexpr(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>) { | ||||
|         static type_info instance{std::in_place_type<Type>}; | ||||
|         return instance; | ||||
|     } else { | ||||
|         return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /*! @copydoc type_id */ | ||||
| template<typename Type> | ||||
| [[nodiscard]] const type_info &type_id(Type &&) noexcept { | ||||
|     return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>(); | ||||
| } | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										758
									
								
								external/entt/entt/src/entt/core/type_traits.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										758
									
								
								external/entt/entt/src/entt/core/type_traits.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,758 @@ | ||||
| #ifndef ENTT_CORE_TYPE_TRAITS_HPP | ||||
| #define ENTT_CORE_TYPE_TRAITS_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <iterator> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include "../config/config.h" | ||||
| #include "fwd.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @brief Utility class to disambiguate overloaded functions. | ||||
|  * @tparam N Number of choices available. | ||||
|  */ | ||||
| template<std::size_t N> | ||||
| struct choice_t | ||||
|     // Unfortunately, doxygen cannot parse such a construct. | ||||
|     : /*! @cond TURN_OFF_DOXYGEN */ choice_t<N - 1> /*! @endcond */ | ||||
| {}; | ||||
|  | ||||
| /*! @copybrief choice_t */ | ||||
| template<> | ||||
| struct choice_t<0> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Variable template for the choice trick. | ||||
|  * @tparam N Number of choices available. | ||||
|  */ | ||||
| template<std::size_t N> | ||||
| inline constexpr choice_t<N> choice{}; | ||||
|  | ||||
| /** | ||||
|  * @brief Identity type trait. | ||||
|  * | ||||
|  * Useful to establish non-deduced contexts in template argument deduction | ||||
|  * (waiting for C++20) or to provide types through function arguments. | ||||
|  * | ||||
|  * @tparam Type A type. | ||||
|  */ | ||||
| template<typename Type> | ||||
| struct type_identity { | ||||
|     /*! @brief Identity type. */ | ||||
|     using type = Type; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam Type A type. | ||||
|  */ | ||||
| template<typename Type> | ||||
| using type_identity_t = typename type_identity<Type>::type; | ||||
|  | ||||
| /** | ||||
|  * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. | ||||
|  * @tparam Type The type of which to return the size. | ||||
|  * @tparam The size of the type if `sizeof` accepts it, 0 otherwise. | ||||
|  */ | ||||
| template<typename Type, typename = void> | ||||
| struct size_of: std::integral_constant<std::size_t, 0u> {}; | ||||
|  | ||||
| /*! @copydoc size_of */ | ||||
| template<typename Type> | ||||
| struct size_of<Type, std::void_t<decltype(sizeof(Type))>> | ||||
|     : std::integral_constant<std::size_t, sizeof(Type)> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam Type The type of which to return the size. | ||||
|  */ | ||||
| template<typename Type> | ||||
| inline constexpr std::size_t size_of_v = size_of<Type>::value; | ||||
|  | ||||
| /** | ||||
|  * @brief Using declaration to be used to _repeat_ the same type a number of | ||||
|  * times equal to the size of a given parameter pack. | ||||
|  * @tparam Type A type to repeat. | ||||
|  */ | ||||
| template<typename Type, typename> | ||||
| using unpack_as_type = Type; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template to be used to _repeat_ the same value a | ||||
|  * number of times equal to the size of a given parameter pack. | ||||
|  * @tparam Value A value to repeat. | ||||
|  */ | ||||
| template<auto Value, typename> | ||||
| inline constexpr auto unpack_as_value = Value; | ||||
|  | ||||
| /** | ||||
|  * @brief Wraps a static constant. | ||||
|  * @tparam Value A static constant. | ||||
|  */ | ||||
| template<auto Value> | ||||
| using integral_constant = std::integral_constant<decltype(Value), Value>; | ||||
|  | ||||
| /** | ||||
|  * @brief Alias template to facilitate the creation of named values. | ||||
|  * @tparam Value A constant value at least convertible to `id_type`. | ||||
|  */ | ||||
| template<id_type Value> | ||||
| using tag = integral_constant<Value>; | ||||
|  | ||||
| /** | ||||
|  * @brief A class to use to push around lists of types, nothing more. | ||||
|  * @tparam Type Types provided by the type list. | ||||
|  */ | ||||
| template<typename... Type> | ||||
| struct type_list { | ||||
|     /*! @brief Type list type. */ | ||||
|     using type = type_list; | ||||
|     /*! @brief Compile-time number of elements in the type list. */ | ||||
|     static constexpr auto size = sizeof...(Type); | ||||
| }; | ||||
|  | ||||
| /*! @brief Primary template isn't defined on purpose. */ | ||||
| template<std::size_t, typename> | ||||
| struct type_list_element; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides compile-time indexed access to the types of a type list. | ||||
|  * @tparam Index Index of the type to return. | ||||
|  * @tparam First First type provided by the type list. | ||||
|  * @tparam Other Other types provided by the type list. | ||||
|  */ | ||||
| template<std::size_t Index, typename First, typename... Other> | ||||
| struct type_list_element<Index, type_list<First, Other...>> | ||||
|     : type_list_element<Index - 1u, type_list<Other...>> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides compile-time indexed access to the types of a type list. | ||||
|  * @tparam First First type provided by the type list. | ||||
|  * @tparam Other Other types provided by the type list. | ||||
|  */ | ||||
| template<typename First, typename... Other> | ||||
| struct type_list_element<0u, type_list<First, Other...>> { | ||||
|     /*! @brief Searched type. */ | ||||
|     using type = First; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam Index Index of the type to return. | ||||
|  * @tparam List Type list to search into. | ||||
|  */ | ||||
| template<std::size_t Index, typename List> | ||||
| using type_list_element_t = typename type_list_element<Index, List>::type; | ||||
|  | ||||
| /*! @brief Primary template isn't defined on purpose. */ | ||||
| template<typename, typename> | ||||
| struct type_list_index; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides compile-time type access to the types of a type list. | ||||
|  * @tparam Type Type to look for and for which to return the index. | ||||
|  * @tparam First First type provided by the type list. | ||||
|  * @tparam Other Other types provided by the type list. | ||||
|  */ | ||||
| template<typename Type, typename First, typename... Other> | ||||
| struct type_list_index<Type, type_list<First, Other...>> { | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using value_type = std::size_t; | ||||
|     /*! @brief Compile-time position of the given type in the sublist. */ | ||||
|     static constexpr value_type value = 1u + type_list_index<Type, type_list<Other...>>::value; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides compile-time type access to the types of a type list. | ||||
|  * @tparam Type Type to look for and for which to return the index. | ||||
|  * @tparam Other Other types provided by the type list. | ||||
|  */ | ||||
| template<typename Type, typename... Other> | ||||
| struct type_list_index<Type, type_list<Type, Other...>> { | ||||
|     static_assert(type_list_index<Type, type_list<Other...>>::value == sizeof...(Other), "Non-unique type"); | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using value_type = std::size_t; | ||||
|     /*! @brief Compile-time position of the given type in the sublist. */ | ||||
|     static constexpr value_type value = 0u; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides compile-time type access to the types of a type list. | ||||
|  * @tparam Type Type to look for and for which to return the index. | ||||
|  */ | ||||
| template<typename Type> | ||||
| struct type_list_index<Type, type_list<>> { | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using value_type = std::size_t; | ||||
|     /*! @brief Compile-time position of the given type in the sublist. */ | ||||
|     static constexpr value_type value = 0u; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam List Type list. | ||||
|  * @tparam Type Type to look for and for which to return the index. | ||||
|  */ | ||||
| template<typename Type, typename List> | ||||
| inline constexpr std::size_t type_list_index_v = type_list_index<Type, List>::value; | ||||
|  | ||||
| /** | ||||
|  * @brief Concatenates multiple type lists. | ||||
|  * @tparam Type Types provided by the first type list. | ||||
|  * @tparam Other Types provided by the second type list. | ||||
|  * @return A type list composed by the types of both the type lists. | ||||
|  */ | ||||
| template<typename... Type, typename... Other> | ||||
| constexpr type_list<Type..., Other...> operator+(type_list<Type...>, type_list<Other...>) { | ||||
|     return {}; | ||||
| } | ||||
|  | ||||
| /*! @brief Primary template isn't defined on purpose. */ | ||||
| template<typename...> | ||||
| struct type_list_cat; | ||||
|  | ||||
| /*! @brief Concatenates multiple type lists. */ | ||||
| template<> | ||||
| struct type_list_cat<> { | ||||
|     /*! @brief A type list composed by the types of all the type lists. */ | ||||
|     using type = type_list<>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Concatenates multiple type lists. | ||||
|  * @tparam Type Types provided by the first type list. | ||||
|  * @tparam Other Types provided by the second type list. | ||||
|  * @tparam List Other type lists, if any. | ||||
|  */ | ||||
| template<typename... Type, typename... Other, typename... List> | ||||
| struct type_list_cat<type_list<Type...>, type_list<Other...>, List...> { | ||||
|     /*! @brief A type list composed by the types of all the type lists. */ | ||||
|     using type = typename type_list_cat<type_list<Type..., Other...>, List...>::type; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Concatenates multiple type lists. | ||||
|  * @tparam Type Types provided by the type list. | ||||
|  */ | ||||
| template<typename... Type> | ||||
| struct type_list_cat<type_list<Type...>> { | ||||
|     /*! @brief A type list composed by the types of all the type lists. */ | ||||
|     using type = type_list<Type...>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam List Type lists to concatenate. | ||||
|  */ | ||||
| template<typename... List> | ||||
| using type_list_cat_t = typename type_list_cat<List...>::type; | ||||
|  | ||||
| /*! @brief Primary template isn't defined on purpose. */ | ||||
| template<typename> | ||||
| struct type_list_unique; | ||||
|  | ||||
| /** | ||||
|  * @brief Removes duplicates types from a type list. | ||||
|  * @tparam Type One of the types provided by the given type list. | ||||
|  * @tparam Other The other types provided by the given type list. | ||||
|  */ | ||||
| template<typename Type, typename... Other> | ||||
| struct type_list_unique<type_list<Type, Other...>> { | ||||
|     /*! @brief A type list without duplicate types. */ | ||||
|     using type = std::conditional_t< | ||||
|         (std::is_same_v<Type, Other> || ...), | ||||
|         typename type_list_unique<type_list<Other...>>::type, | ||||
|         type_list_cat_t<type_list<Type>, typename type_list_unique<type_list<Other...>>::type>>; | ||||
| }; | ||||
|  | ||||
| /*! @brief Removes duplicates types from a type list. */ | ||||
| template<> | ||||
| struct type_list_unique<type_list<>> { | ||||
|     /*! @brief A type list without duplicate types. */ | ||||
|     using type = type_list<>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam Type A type list. | ||||
|  */ | ||||
| template<typename Type> | ||||
| using type_list_unique_t = typename type_list_unique<Type>::type; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides the member constant `value` to true if a type list contains a | ||||
|  * given type, false otherwise. | ||||
|  * @tparam List Type list. | ||||
|  * @tparam Type Type to look for. | ||||
|  */ | ||||
| template<typename List, typename Type> | ||||
| struct type_list_contains; | ||||
|  | ||||
| /** | ||||
|  * @copybrief type_list_contains | ||||
|  * @tparam Type Types provided by the type list. | ||||
|  * @tparam Other Type to look for. | ||||
|  */ | ||||
| template<typename... Type, typename Other> | ||||
| struct type_list_contains<type_list<Type...>, Other>: std::disjunction<std::is_same<Type, Other>...> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam List Type list. | ||||
|  * @tparam Type Type to look for. | ||||
|  */ | ||||
| template<typename List, typename Type> | ||||
| inline constexpr bool type_list_contains_v = type_list_contains<List, Type>::value; | ||||
|  | ||||
| /*! @brief Primary template isn't defined on purpose. */ | ||||
| template<typename...> | ||||
| struct type_list_diff; | ||||
|  | ||||
| /** | ||||
|  * @brief Computes the difference between two type lists. | ||||
|  * @tparam Type Types provided by the first type list. | ||||
|  * @tparam Other Types provided by the second type list. | ||||
|  */ | ||||
| template<typename... Type, typename... Other> | ||||
| struct type_list_diff<type_list<Type...>, type_list<Other...>> { | ||||
|     /*! @brief A type list that is the difference between the two type lists. */ | ||||
|     using type = type_list_cat_t<std::conditional_t<type_list_contains_v<type_list<Other...>, Type>, type_list<>, type_list<Type>>...>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam List Type lists between which to compute the difference. | ||||
|  */ | ||||
| template<typename... List> | ||||
| using type_list_diff_t = typename type_list_diff<List...>::type; | ||||
|  | ||||
| /*! @brief Primary template isn't defined on purpose. */ | ||||
| template<typename, template<typename...> class> | ||||
| struct type_list_transform; | ||||
|  | ||||
| /** | ||||
|  * @brief Applies a given _function_ to a type list and generate a new list. | ||||
|  * @tparam Type Types provided by the type list. | ||||
|  * @tparam Op Unary operation as template class with a type member named `type`. | ||||
|  */ | ||||
| template<typename... Type, template<typename...> class Op> | ||||
| struct type_list_transform<type_list<Type...>, Op> { | ||||
|     /*! @brief Resulting type list after applying the transform function. */ | ||||
|     using type = type_list<typename Op<Type>::type...>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam List Type list. | ||||
|  * @tparam Op Unary operation as template class with a type member named `type`. | ||||
|  */ | ||||
| template<typename List, template<typename...> class Op> | ||||
| using type_list_transform_t = typename type_list_transform<List, Op>::type; | ||||
|  | ||||
| /** | ||||
|  * @brief A class to use to push around lists of constant values, nothing more. | ||||
|  * @tparam Value Values provided by the value list. | ||||
|  */ | ||||
| template<auto... Value> | ||||
| struct value_list { | ||||
|     /*! @brief Value list type. */ | ||||
|     using type = value_list; | ||||
|     /*! @brief Compile-time number of elements in the value list. */ | ||||
|     static constexpr auto size = sizeof...(Value); | ||||
| }; | ||||
|  | ||||
| /*! @brief Primary template isn't defined on purpose. */ | ||||
| template<std::size_t, typename> | ||||
| struct value_list_element; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides compile-time indexed access to the values of a value list. | ||||
|  * @tparam Index Index of the value to return. | ||||
|  * @tparam Value First value provided by the value list. | ||||
|  * @tparam Other Other values provided by the value list. | ||||
|  */ | ||||
| template<std::size_t Index, auto Value, auto... Other> | ||||
| struct value_list_element<Index, value_list<Value, Other...>> | ||||
|     : value_list_element<Index - 1u, value_list<Other...>> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides compile-time indexed access to the types of a type list. | ||||
|  * @tparam Value First value provided by the value list. | ||||
|  * @tparam Other Other values provided by the value list. | ||||
|  */ | ||||
| template<auto Value, auto... Other> | ||||
| struct value_list_element<0u, value_list<Value, Other...>> { | ||||
|     /*! @brief Searched value. */ | ||||
|     static constexpr auto value = Value; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam Index Index of the value to return. | ||||
|  * @tparam List Value list to search into. | ||||
|  */ | ||||
| template<std::size_t Index, typename List> | ||||
| inline constexpr auto value_list_element_v = value_list_element<Index, List>::value; | ||||
|  | ||||
| /** | ||||
|  * @brief Concatenates multiple value lists. | ||||
|  * @tparam Value Values provided by the first value list. | ||||
|  * @tparam Other Values provided by the second value list. | ||||
|  * @return A value list composed by the values of both the value lists. | ||||
|  */ | ||||
| template<auto... Value, auto... Other> | ||||
| constexpr value_list<Value..., Other...> operator+(value_list<Value...>, value_list<Other...>) { | ||||
|     return {}; | ||||
| } | ||||
|  | ||||
| /*! @brief Primary template isn't defined on purpose. */ | ||||
| template<typename...> | ||||
| struct value_list_cat; | ||||
|  | ||||
| /*! @brief Concatenates multiple value lists. */ | ||||
| template<> | ||||
| struct value_list_cat<> { | ||||
|     /*! @brief A value list composed by the values of all the value lists. */ | ||||
|     using type = value_list<>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Concatenates multiple value lists. | ||||
|  * @tparam Value Values provided by the first value list. | ||||
|  * @tparam Other Values provided by the second value list. | ||||
|  * @tparam List Other value lists, if any. | ||||
|  */ | ||||
| template<auto... Value, auto... Other, typename... List> | ||||
| struct value_list_cat<value_list<Value...>, value_list<Other...>, List...> { | ||||
|     /*! @brief A value list composed by the values of all the value lists. */ | ||||
|     using type = typename value_list_cat<value_list<Value..., Other...>, List...>::type; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Concatenates multiple value lists. | ||||
|  * @tparam Value Values provided by the value list. | ||||
|  */ | ||||
| template<auto... Value> | ||||
| struct value_list_cat<value_list<Value...>> { | ||||
|     /*! @brief A value list composed by the values of all the value lists. */ | ||||
|     using type = value_list<Value...>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam List Value lists to concatenate. | ||||
|  */ | ||||
| template<typename... List> | ||||
| using value_list_cat_t = typename value_list_cat<List...>::type; | ||||
|  | ||||
| /*! @brief Same as std::is_invocable, but with tuples. */ | ||||
| template<typename, typename> | ||||
| struct is_applicable: std::false_type {}; | ||||
|  | ||||
| /** | ||||
|  * @copybrief is_applicable | ||||
|  * @tparam Func A valid function type. | ||||
|  * @tparam Tuple Tuple-like type. | ||||
|  * @tparam Args The list of arguments to use to probe the function type. | ||||
|  */ | ||||
| template<typename Func, template<typename...> class Tuple, typename... Args> | ||||
| struct is_applicable<Func, Tuple<Args...>>: std::is_invocable<Func, Args...> {}; | ||||
|  | ||||
| /** | ||||
|  * @copybrief is_applicable | ||||
|  * @tparam Func A valid function type. | ||||
|  * @tparam Tuple Tuple-like type. | ||||
|  * @tparam Args The list of arguments to use to probe the function type. | ||||
|  */ | ||||
| template<typename Func, template<typename...> class Tuple, typename... Args> | ||||
| struct is_applicable<Func, const Tuple<Args...>>: std::is_invocable<Func, Args...> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam Func A valid function type. | ||||
|  * @tparam Args The list of arguments to use to probe the function type. | ||||
|  */ | ||||
| template<typename Func, typename Args> | ||||
| inline constexpr bool is_applicable_v = is_applicable<Func, Args>::value; | ||||
|  | ||||
| /*! @brief Same as std::is_invocable_r, but with tuples for arguments. */ | ||||
| template<typename, typename, typename> | ||||
| struct is_applicable_r: std::false_type {}; | ||||
|  | ||||
| /** | ||||
|  * @copybrief is_applicable_r | ||||
|  * @tparam Ret The type to which the return type of the function should be | ||||
|  * convertible. | ||||
|  * @tparam Func A valid function type. | ||||
|  * @tparam Args The list of arguments to use to probe the function type. | ||||
|  */ | ||||
| template<typename Ret, typename Func, typename... Args> | ||||
| struct is_applicable_r<Ret, Func, std::tuple<Args...>>: std::is_invocable_r<Ret, Func, Args...> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam Ret The type to which the return type of the function should be | ||||
|  * convertible. | ||||
|  * @tparam Func A valid function type. | ||||
|  * @tparam Args The list of arguments to use to probe the function type. | ||||
|  */ | ||||
| template<typename Ret, typename Func, typename Args> | ||||
| inline constexpr bool is_applicable_r_v = is_applicable_r<Ret, Func, Args>::value; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides the member constant `value` to true if a given type is | ||||
|  * complete, false otherwise. | ||||
|  * @tparam Type The type to test. | ||||
|  */ | ||||
| template<typename Type, typename = void> | ||||
| struct is_complete: std::false_type {}; | ||||
|  | ||||
| /*! @copydoc is_complete */ | ||||
| template<typename Type> | ||||
| struct is_complete<Type, std::void_t<decltype(sizeof(Type))>>: std::true_type {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam Type The type to test. | ||||
|  */ | ||||
| template<typename Type> | ||||
| inline constexpr bool is_complete_v = is_complete<Type>::value; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides the member constant `value` to true if a given type is an | ||||
|  * iterator, false otherwise. | ||||
|  * @tparam Type The type to test. | ||||
|  */ | ||||
| template<typename Type, typename = void> | ||||
| struct is_iterator: std::false_type {}; | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename, typename = void> | ||||
| struct has_iterator_category: std::false_type {}; | ||||
|  | ||||
| template<typename Type> | ||||
| struct has_iterator_category<Type, std::void_t<typename std::iterator_traits<Type>::iterator_category>>: std::true_type {}; | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /*! @copydoc is_iterator */ | ||||
| template<typename Type> | ||||
| struct is_iterator<Type, std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_pointer_t<Type>>, void>>> | ||||
|     : internal::has_iterator_category<Type> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam Type The type to test. | ||||
|  */ | ||||
| template<typename Type> | ||||
| inline constexpr bool is_iterator_v = is_iterator<Type>::value; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides the member constant `value` to true if a given type is both | ||||
|  * an empty and non-final class, false otherwise. | ||||
|  * @tparam Type The type to test | ||||
|  */ | ||||
| template<typename Type> | ||||
| struct is_ebco_eligible | ||||
|     : std::conjunction<std::is_empty<Type>, std::negation<std::is_final<Type>>> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam Type The type to test. | ||||
|  */ | ||||
| template<typename Type> | ||||
| inline constexpr bool is_ebco_eligible_v = is_ebco_eligible<Type>::value; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides the member constant `value` to true if `Type::is_transparent` | ||||
|  * is valid and denotes a type, false otherwise. | ||||
|  * @tparam Type The type to test. | ||||
|  */ | ||||
| template<typename Type, typename = void> | ||||
| struct is_transparent: std::false_type {}; | ||||
|  | ||||
| /*! @copydoc is_transparent */ | ||||
| template<typename Type> | ||||
| struct is_transparent<Type, std::void_t<typename Type::is_transparent>>: std::true_type {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam Type The type to test. | ||||
|  */ | ||||
| template<typename Type> | ||||
| inline constexpr bool is_transparent_v = is_transparent<Type>::value; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides the member constant `value` to true if a given type is | ||||
|  * equality comparable, false otherwise. | ||||
|  * @tparam Type The type to test. | ||||
|  */ | ||||
| template<typename Type, typename = void> | ||||
| struct is_equality_comparable: std::false_type {}; | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename, typename = void> | ||||
| struct has_tuple_size_value: std::false_type {}; | ||||
|  | ||||
| template<typename Type> | ||||
| struct has_tuple_size_value<Type, std::void_t<decltype(std::tuple_size<const Type>::value)>>: std::true_type {}; | ||||
|  | ||||
| template<typename Type, std::size_t... Index> | ||||
| [[nodiscard]] constexpr bool unpack_maybe_equality_comparable(std::index_sequence<Index...>) { | ||||
|     return (is_equality_comparable<std::tuple_element_t<Index, Type>>::value && ...); | ||||
| } | ||||
|  | ||||
| template<typename> | ||||
| [[nodiscard]] constexpr bool maybe_equality_comparable(choice_t<0>) { | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| template<typename Type> | ||||
| [[nodiscard]] constexpr auto maybe_equality_comparable(choice_t<1>) -> decltype(std::declval<typename Type::value_type>(), bool{}) { | ||||
|     if constexpr(is_iterator_v<Type>) { | ||||
|         return true; | ||||
|     } else if constexpr(std::is_same_v<typename Type::value_type, Type>) { | ||||
|         return maybe_equality_comparable<Type>(choice<0>); | ||||
|     } else { | ||||
|         return is_equality_comparable<typename Type::value_type>::value; | ||||
|     } | ||||
| } | ||||
|  | ||||
| template<typename Type> | ||||
| [[nodiscard]] constexpr std::enable_if_t<is_complete_v<std::tuple_size<std::remove_cv_t<Type>>>, bool> maybe_equality_comparable(choice_t<2>) { | ||||
|     if constexpr(has_tuple_size_value<Type>::value) { | ||||
|         return unpack_maybe_equality_comparable<Type>(std::make_index_sequence<std::tuple_size<Type>::value>{}); | ||||
|     } else { | ||||
|         return maybe_equality_comparable<Type>(choice<1>); | ||||
|     } | ||||
| } | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /*! @copydoc is_equality_comparable */ | ||||
| template<typename Type> | ||||
| struct is_equality_comparable<Type, std::void_t<decltype(std::declval<Type>() == std::declval<Type>())>> | ||||
|     : std::bool_constant<internal::maybe_equality_comparable<Type>(choice<2>)> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam Type The type to test. | ||||
|  */ | ||||
| template<typename Type> | ||||
| inline constexpr bool is_equality_comparable_v = is_equality_comparable<Type>::value; | ||||
|  | ||||
| /** | ||||
|  * @brief Transcribes the constness of a type to another type. | ||||
|  * @tparam To The type to which to transcribe the constness. | ||||
|  * @tparam From The type from which to transcribe the constness. | ||||
|  */ | ||||
| template<typename To, typename From> | ||||
| struct constness_as { | ||||
|     /*! @brief The type resulting from the transcription of the constness. */ | ||||
|     using type = std::remove_const_t<To>; | ||||
| }; | ||||
|  | ||||
| /*! @copydoc constness_as */ | ||||
| template<typename To, typename From> | ||||
| struct constness_as<To, const From> { | ||||
|     /*! @brief The type resulting from the transcription of the constness. */ | ||||
|     using type = const To; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Alias template to facilitate the transcription of the constness. | ||||
|  * @tparam To The type to which to transcribe the constness. | ||||
|  * @tparam From The type from which to transcribe the constness. | ||||
|  */ | ||||
| template<typename To, typename From> | ||||
| using constness_as_t = typename constness_as<To, From>::type; | ||||
|  | ||||
| /** | ||||
|  * @brief Extracts the class of a non-static member object or function. | ||||
|  * @tparam Member A pointer to a non-static member object or function. | ||||
|  */ | ||||
| template<typename Member> | ||||
| class member_class { | ||||
|     static_assert(std::is_member_pointer_v<Member>, "Invalid pointer type to non-static member object or function"); | ||||
|  | ||||
|     template<typename Class, typename Ret, typename... Args> | ||||
|     static Class *clazz(Ret (Class::*)(Args...)); | ||||
|  | ||||
|     template<typename Class, typename Ret, typename... Args> | ||||
|     static Class *clazz(Ret (Class::*)(Args...) const); | ||||
|  | ||||
|     template<typename Class, typename Type> | ||||
|     static Class *clazz(Type Class::*); | ||||
|  | ||||
| public: | ||||
|     /*! @brief The class of the given non-static member object or function. */ | ||||
|     using type = std::remove_pointer_t<decltype(clazz(std::declval<Member>()))>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam Member A pointer to a non-static member object or function. | ||||
|  */ | ||||
| template<typename Member> | ||||
| using member_class_t = typename member_class<Member>::type; | ||||
|  | ||||
| /** | ||||
|  * @brief Extracts the n-th argument of a given function or member function. | ||||
|  * @tparam Index The index of the argument to extract. | ||||
|  * @tparam Candidate A valid function, member function or data member. | ||||
|  */ | ||||
| template<std::size_t Index, auto Candidate> | ||||
| class nth_argument { | ||||
|     template<typename Ret, typename... Args> | ||||
|     static constexpr type_list<Args...> pick_up(Ret (*)(Args...)); | ||||
|  | ||||
|     template<typename Ret, typename Class, typename... Args> | ||||
|     static constexpr type_list<Args...> pick_up(Ret (Class ::*)(Args...)); | ||||
|  | ||||
|     template<typename Ret, typename Class, typename... Args> | ||||
|     static constexpr type_list<Args...> pick_up(Ret (Class ::*)(Args...) const); | ||||
|  | ||||
|     template<typename Type, typename Class> | ||||
|     static constexpr type_list<Type> pick_up(Type Class ::*); | ||||
|  | ||||
| public: | ||||
|     /*! @brief N-th argument of the given function or member function. */ | ||||
|     using type = type_list_element_t<Index, decltype(pick_up(Candidate))>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam Index The index of the argument to extract. | ||||
|  * @tparam Candidate A valid function, member function or data member. | ||||
|  */ | ||||
| template<std::size_t Index, auto Candidate> | ||||
| using nth_argument_t = typename nth_argument<Index, Candidate>::type; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										101
									
								
								external/entt/entt/src/entt/core/utility.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								external/entt/entt/src/entt/core/utility.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| #ifndef ENTT_CORE_UTILITY_HPP | ||||
| #define ENTT_CORE_UTILITY_HPP | ||||
|  | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /*! @brief Identity function object (waiting for C++20). */ | ||||
| struct identity { | ||||
|     /*! @brief Indicates that this is a transparent function object. */ | ||||
|     using is_transparent = void; | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns its argument unchanged. | ||||
|      * @tparam Type Type of the argument. | ||||
|      * @param value The actual argument. | ||||
|      * @return The submitted value as-is. | ||||
|      */ | ||||
|     template<class Type> | ||||
|     [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { | ||||
|         return std::forward<Type>(value); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Constant utility to disambiguate overloaded members of a class. | ||||
|  * @tparam Type Type of the desired overload. | ||||
|  * @tparam Class Type of class to which the member belongs. | ||||
|  * @param member A valid pointer to a member. | ||||
|  * @return Pointer to the member. | ||||
|  */ | ||||
| template<typename Type, typename Class> | ||||
| [[nodiscard]] constexpr auto overload(Type Class::*member) noexcept { | ||||
|     return member; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Constant utility to disambiguate overloaded functions. | ||||
|  * @tparam Func Function type of the desired overload. | ||||
|  * @param func A valid pointer to a function. | ||||
|  * @return Pointer to the function. | ||||
|  */ | ||||
| template<typename Func> | ||||
| [[nodiscard]] constexpr auto overload(Func *func) noexcept { | ||||
|     return func; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type for visitors. | ||||
|  * @tparam Func Types of function objects. | ||||
|  */ | ||||
| template<class... Func> | ||||
| struct overloaded: Func... { | ||||
|     using Func::operator()...; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Deduction guide. | ||||
|  * @tparam Func Types of function objects. | ||||
|  */ | ||||
| template<class... Func> | ||||
| overloaded(Func...) -> overloaded<Func...>; | ||||
|  | ||||
| /** | ||||
|  * @brief Basic implementation of a y-combinator. | ||||
|  * @tparam Func Type of a potentially recursive function. | ||||
|  */ | ||||
| template<class Func> | ||||
| struct y_combinator { | ||||
|     /** | ||||
|      * @brief Constructs a y-combinator from a given function. | ||||
|      * @param recursive A potentially recursive function. | ||||
|      */ | ||||
|     constexpr y_combinator(Func recursive) noexcept(std::is_nothrow_move_constructible_v<Func>) | ||||
|         : func{std::move(recursive)} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Invokes a y-combinator and therefore its underlying function. | ||||
|      * @tparam Args Types of arguments to use to invoke the underlying function. | ||||
|      * @param args Parameters to use to invoke the underlying function. | ||||
|      * @return Return value of the underlying function, if any. | ||||
|      */ | ||||
|     template<class... Args> | ||||
|     constexpr decltype(auto) operator()(Args &&...args) const noexcept(std::is_nothrow_invocable_v<Func, const y_combinator &, Args...>) { | ||||
|         return func(*this, std::forward<Args>(args)...); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc operator()() */ | ||||
|     template<class... Args> | ||||
|     constexpr decltype(auto) operator()(Args &&...args) noexcept(std::is_nothrow_invocable_v<Func, y_combinator &, Args...>) { | ||||
|         return func(*this, std::forward<Args>(args)...); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     Func func; | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										64
									
								
								external/entt/entt/src/entt/entity/component.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								external/entt/entt/src/entt/entity/component.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| #ifndef ENTT_ENTITY_COMPONENT_HPP | ||||
| #define ENTT_ENTITY_COMPONENT_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <type_traits> | ||||
| #include "../config/config.h" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename Type, typename = void> | ||||
| struct in_place_delete: std::bool_constant<!(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>)> {}; | ||||
|  | ||||
| template<typename Type> | ||||
| struct in_place_delete<Type, std::enable_if_t<Type::in_place_delete>> | ||||
|     : std::true_type {}; | ||||
|  | ||||
| template<typename Type, typename = void> | ||||
| struct page_size: std::integral_constant<std::size_t, !std::is_empty_v<ENTT_ETO_TYPE(Type)> * ENTT_PACKED_PAGE> {}; | ||||
|  | ||||
| template<typename Type> | ||||
| struct page_size<Type, std::enable_if_t<std::is_convertible_v<decltype(Type::page_size), std::size_t>>> | ||||
|     : std::integral_constant<std::size_t, Type::page_size> {}; | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief Common way to access various properties of components. | ||||
|  * @tparam Type Type of component. | ||||
|  */ | ||||
| template<typename Type, typename = void> | ||||
| struct component_traits { | ||||
|     static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type"); | ||||
|  | ||||
|     /*! @brief Component type. */ | ||||
|     using type = Type; | ||||
|  | ||||
|     /*! @brief Pointer stability, default is `false`. */ | ||||
|     static constexpr bool in_place_delete = internal::in_place_delete<Type>::value; | ||||
|     /*! @brief Page size, default is `ENTT_PACKED_PAGE` for non-empty types. */ | ||||
|     static constexpr std::size_t page_size = internal::page_size<Type>::value; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam Type Type of component. | ||||
|  */ | ||||
| template<class Type> | ||||
| inline constexpr bool ignore_as_empty_v = (std::is_void_v<Type> || component_traits<Type>::page_size == 0u); | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										339
									
								
								external/entt/entt/src/entt/entity/entity.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								external/entt/entt/src/entt/entity/entity.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,339 @@ | ||||
| #ifndef ENTT_ENTITY_ENTITY_HPP | ||||
| #define ENTT_ENTITY_ENTITY_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <cstdint> | ||||
| #include <type_traits> | ||||
| #include "../config/config.h" | ||||
| #include "fwd.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename, typename = void> | ||||
| struct entt_traits; | ||||
|  | ||||
| template<typename Type> | ||||
| struct entt_traits<Type, std::enable_if_t<std::is_enum_v<Type>>> | ||||
|     : entt_traits<std::underlying_type_t<Type>> {}; | ||||
|  | ||||
| template<typename Type> | ||||
| struct entt_traits<Type, std::enable_if_t<std::is_class_v<Type>>> | ||||
|     : entt_traits<typename Type::entity_type> {}; | ||||
|  | ||||
| template<> | ||||
| struct entt_traits<std::uint32_t> { | ||||
|     using entity_type = std::uint32_t; | ||||
|     using version_type = std::uint16_t; | ||||
|  | ||||
|     static constexpr entity_type entity_mask = 0xFFFFF; | ||||
|     static constexpr entity_type version_mask = 0xFFF; | ||||
|     static constexpr std::size_t entity_shift = 20u; | ||||
| }; | ||||
|  | ||||
| template<> | ||||
| struct entt_traits<std::uint64_t> { | ||||
|     using entity_type = std::uint64_t; | ||||
|     using version_type = std::uint32_t; | ||||
|  | ||||
|     static constexpr entity_type entity_mask = 0xFFFFFFFF; | ||||
|     static constexpr entity_type version_mask = 0xFFFFFFFF; | ||||
|     static constexpr std::size_t entity_shift = 32u; | ||||
| }; | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief Entity traits. | ||||
|  * @tparam Type Type of identifier. | ||||
|  */ | ||||
| template<typename Type> | ||||
| class entt_traits: internal::entt_traits<Type> { | ||||
|     using base_type = internal::entt_traits<Type>; | ||||
|  | ||||
| public: | ||||
|     /*! @brief Value type. */ | ||||
|     using value_type = Type; | ||||
|     /*! @brief Underlying entity type. */ | ||||
|     using entity_type = typename base_type::entity_type; | ||||
|     /*! @brief Underlying version type. */ | ||||
|     using version_type = typename base_type::version_type; | ||||
|     /*! @brief Reserved identifier. */ | ||||
|     static constexpr entity_type reserved = base_type::entity_mask | (base_type::version_mask << base_type::entity_shift); | ||||
|     /*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */ | ||||
|     static constexpr auto page_size = ENTT_SPARSE_PAGE; | ||||
|  | ||||
|     /** | ||||
|      * @brief Converts an entity to its underlying type. | ||||
|      * @param value The value to convert. | ||||
|      * @return The integral representation of the given value. | ||||
|      */ | ||||
|     [[nodiscard]] static constexpr entity_type to_integral(const value_type value) noexcept { | ||||
|         return static_cast<entity_type>(value); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the entity part once converted to the underlying type. | ||||
|      * @param value The value to convert. | ||||
|      * @return The integral representation of the entity part. | ||||
|      */ | ||||
|     [[nodiscard]] static constexpr entity_type to_entity(const value_type value) noexcept { | ||||
|         return (to_integral(value) & base_type::entity_mask); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the version part once converted to the underlying type. | ||||
|      * @param value The value to convert. | ||||
|      * @return The integral representation of the version part. | ||||
|      */ | ||||
|     [[nodiscard]] static constexpr version_type to_version(const value_type value) noexcept { | ||||
|         return (to_integral(value) >> base_type::entity_shift); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an identifier from its parts. | ||||
|      * | ||||
|      * If the version part is not provided, a tombstone is returned.<br/> | ||||
|      * If the entity part is not provided, a null identifier is returned. | ||||
|      * | ||||
|      * @param entity The entity part of the identifier. | ||||
|      * @param version The version part of the identifier. | ||||
|      * @return A properly constructed identifier. | ||||
|      */ | ||||
|     [[nodiscard]] static constexpr value_type construct(const entity_type entity, const version_type version) noexcept { | ||||
|         return value_type{(entity & base_type::entity_mask) | (static_cast<entity_type>(version) << base_type::entity_shift)}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Combines two identifiers in a single one. | ||||
|      * | ||||
|      * The returned identifier is a copy of the first element except for its | ||||
|      * version, which is taken from the second element. | ||||
|      * | ||||
|      * @param lhs The identifier from which to take the entity part. | ||||
|      * @param rhs The identifier from which to take the version part. | ||||
|      * @return A properly constructed identifier. | ||||
|      */ | ||||
|     [[nodiscard]] static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept { | ||||
|         constexpr auto mask = (base_type::version_mask << base_type::entity_shift); | ||||
|         return value_type{(lhs & base_type::entity_mask) | (rhs & mask)}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @copydoc entt_traits<Entity>::to_integral | ||||
|  * @tparam Entity The value type. | ||||
|  */ | ||||
| template<typename Entity> | ||||
| [[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_integral(const Entity value) noexcept { | ||||
|     return entt_traits<Entity>::to_integral(value); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @copydoc entt_traits<Entity>::to_entity | ||||
|  * @tparam Entity The value type. | ||||
|  */ | ||||
| template<typename Entity> | ||||
| [[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_entity(const Entity value) noexcept { | ||||
|     return entt_traits<Entity>::to_entity(value); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @copydoc entt_traits<Entity>::to_version | ||||
|  * @tparam Entity The value type. | ||||
|  */ | ||||
| template<typename Entity> | ||||
| [[nodiscard]] constexpr typename entt_traits<Entity>::version_type to_version(const Entity value) noexcept { | ||||
|     return entt_traits<Entity>::to_version(value); | ||||
| } | ||||
|  | ||||
| /*! @brief Null object for all identifiers.  */ | ||||
| struct null_t { | ||||
|     /** | ||||
|      * @brief Converts the null object to identifiers of any type. | ||||
|      * @tparam Entity Type of identifier. | ||||
|      * @return The null representation for the given type. | ||||
|      */ | ||||
|     template<typename Entity> | ||||
|     [[nodiscard]] constexpr operator Entity() const noexcept { | ||||
|         using entity_traits = entt_traits<Entity>; | ||||
|         return entity_traits::combine(entity_traits::reserved, entity_traits::reserved); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Compares two null objects. | ||||
|      * @param other A null object. | ||||
|      * @return True in all cases. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr bool operator==([[maybe_unused]] const null_t other) const noexcept { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Compares two null objects. | ||||
|      * @param other A null object. | ||||
|      * @return False in all cases. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr bool operator!=([[maybe_unused]] const null_t other) const noexcept { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Compares a null object and an identifier of any type. | ||||
|      * @tparam Entity Type of identifier. | ||||
|      * @param entity Identifier with which to compare. | ||||
|      * @return False if the two elements differ, true otherwise. | ||||
|      */ | ||||
|     template<typename Entity> | ||||
|     [[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept { | ||||
|         using entity_traits = entt_traits<Entity>; | ||||
|         return entity_traits::to_entity(entity) == entity_traits::to_entity(*this); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Compares a null object and an identifier of any type. | ||||
|      * @tparam Entity Type of identifier. | ||||
|      * @param entity Identifier with which to compare. | ||||
|      * @return True if the two elements differ, false otherwise. | ||||
|      */ | ||||
|     template<typename Entity> | ||||
|     [[nodiscard]] constexpr bool operator!=(const Entity entity) const noexcept { | ||||
|         return !(entity == *this); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Compares a null object and an identifier of any type. | ||||
|  * @tparam Entity Type of identifier. | ||||
|  * @param entity Identifier with which to compare. | ||||
|  * @param other A null object yet to be converted. | ||||
|  * @return False if the two elements differ, true otherwise. | ||||
|  */ | ||||
| template<typename Entity> | ||||
| [[nodiscard]] constexpr bool operator==(const Entity entity, const null_t other) noexcept { | ||||
|     return other.operator==(entity); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compares a null object and an identifier of any type. | ||||
|  * @tparam Entity Type of identifier. | ||||
|  * @param entity Identifier with which to compare. | ||||
|  * @param other A null object yet to be converted. | ||||
|  * @return True if the two elements differ, false otherwise. | ||||
|  */ | ||||
| template<typename Entity> | ||||
| [[nodiscard]] constexpr bool operator!=(const Entity entity, const null_t other) noexcept { | ||||
|     return !(other == entity); | ||||
| } | ||||
|  | ||||
| /*! @brief Tombstone object for all identifiers.  */ | ||||
| struct tombstone_t { | ||||
|     /** | ||||
|      * @brief Converts the tombstone object to identifiers of any type. | ||||
|      * @tparam Entity Type of identifier. | ||||
|      * @return The tombstone representation for the given type. | ||||
|      */ | ||||
|     template<typename Entity> | ||||
|     [[nodiscard]] constexpr operator Entity() const noexcept { | ||||
|         using entity_traits = entt_traits<Entity>; | ||||
|         return entity_traits::combine(entity_traits::reserved, entity_traits::reserved); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Compares two tombstone objects. | ||||
|      * @param other A tombstone object. | ||||
|      * @return True in all cases. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr bool operator==([[maybe_unused]] const tombstone_t other) const noexcept { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Compares two tombstone objects. | ||||
|      * @param other A tombstone object. | ||||
|      * @return False in all cases. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr bool operator!=([[maybe_unused]] const tombstone_t other) const noexcept { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Compares a tombstone object and an identifier of any type. | ||||
|      * @tparam Entity Type of identifier. | ||||
|      * @param entity Identifier with which to compare. | ||||
|      * @return False if the two elements differ, true otherwise. | ||||
|      */ | ||||
|     template<typename Entity> | ||||
|     [[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept { | ||||
|         using entity_traits = entt_traits<Entity>; | ||||
|         return entity_traits::to_version(entity) == entity_traits::to_version(*this); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Compares a tombstone object and an identifier of any type. | ||||
|      * @tparam Entity Type of identifier. | ||||
|      * @param entity Identifier with which to compare. | ||||
|      * @return True if the two elements differ, false otherwise. | ||||
|      */ | ||||
|     template<typename Entity> | ||||
|     [[nodiscard]] constexpr bool operator!=(const Entity entity) const noexcept { | ||||
|         return !(entity == *this); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Compares a tombstone object and an identifier of any type. | ||||
|  * @tparam Entity Type of identifier. | ||||
|  * @param entity Identifier with which to compare. | ||||
|  * @param other A tombstone object yet to be converted. | ||||
|  * @return False if the two elements differ, true otherwise. | ||||
|  */ | ||||
| template<typename Entity> | ||||
| [[nodiscard]] constexpr bool operator==(const Entity entity, const tombstone_t other) noexcept { | ||||
|     return other.operator==(entity); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compares a tombstone object and an identifier of any type. | ||||
|  * @tparam Entity Type of identifier. | ||||
|  * @param entity Identifier with which to compare. | ||||
|  * @param other A tombstone object yet to be converted. | ||||
|  * @return True if the two elements differ, false otherwise. | ||||
|  */ | ||||
| template<typename Entity> | ||||
| [[nodiscard]] constexpr bool operator!=(const Entity entity, const tombstone_t other) noexcept { | ||||
|     return !(other == entity); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compile-time constant for null entities. | ||||
|  * | ||||
|  * There exist implicit conversions from this variable to identifiers of any | ||||
|  * allowed type. Similarly, there exist comparison operators between the null | ||||
|  * entity and any other identifier. | ||||
|  */ | ||||
| inline constexpr null_t null{}; | ||||
|  | ||||
| /** | ||||
|  * @brief Compile-time constant for tombstone entities. | ||||
|  * | ||||
|  * There exist implicit conversions from this variable to identifiers of any | ||||
|  * allowed type. Similarly, there exist comparison operators between the | ||||
|  * tombstone entity and any other identifier. | ||||
|  */ | ||||
| inline constexpr tombstone_t tombstone{}; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										206
									
								
								external/entt/entt/src/entt/entity/fwd.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								external/entt/entt/src/entt/entity/fwd.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,206 @@ | ||||
| #ifndef ENTT_ENTITY_FWD_HPP | ||||
| #define ENTT_ENTITY_FWD_HPP | ||||
|  | ||||
| #include <memory> | ||||
| #include <type_traits> | ||||
| #include "../core/fwd.hpp" | ||||
| #include "../core/type_traits.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /*! @brief Default entity identifier. */ | ||||
| enum class entity : id_type {}; | ||||
|  | ||||
| template<typename Entity = entity, typename = std::allocator<Entity>> | ||||
| class basic_sparse_set; | ||||
|  | ||||
| template<typename Type, typename = entity, typename = std::allocator<Type>, typename = void> | ||||
| class basic_storage; | ||||
|  | ||||
| template<typename Type> | ||||
| class sigh_storage_mixin; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides a common way to define storage types. | ||||
|  * @tparam Type Storage value type. | ||||
|  * @tparam Entity A valid entity type (see entt_traits for more details). | ||||
|  * @tparam Allocator Type of allocator used to manage memory and elements. | ||||
|  */ | ||||
| template<typename Type, typename Entity = entity, typename Allocator = std::allocator<Type>, typename = void> | ||||
| struct storage_type { | ||||
|     /*! @brief Type-to-storage conversion result. */ | ||||
|     using type = sigh_storage_mixin<basic_storage<Type, Entity, Allocator>>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam Args Arguments to forward. | ||||
|  */ | ||||
| template<typename... Args> | ||||
| using storage_type_t = typename storage_type<Args...>::type; | ||||
|  | ||||
| /** | ||||
|  * Type-to-storage conversion utility that preserves constness. | ||||
|  * @tparam Type Storage value type, eventually const. | ||||
|  * @tparam Entity A valid entity type (see entt_traits for more details). | ||||
|  * @tparam Allocator Type of allocator used to manage memory and elements. | ||||
|  */ | ||||
| template<typename Type, typename Entity = entity, typename Allocator = std::allocator<std::remove_const_t<Type>>> | ||||
| struct storage_for { | ||||
|     /*! @brief Type-to-storage conversion result. */ | ||||
|     using type = constness_as_t<storage_type_t<std::remove_const_t<Type>, Entity, Allocator>, Type>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam Args Arguments to forward. | ||||
|  */ | ||||
| template<typename... Args> | ||||
| using storage_for_t = typename storage_for<Args...>::type; | ||||
|  | ||||
| template<typename Entity = entity, typename = std::allocator<Entity>> | ||||
| class basic_registry; | ||||
|  | ||||
| template<typename, typename, typename = void> | ||||
| class basic_view; | ||||
|  | ||||
| template<typename Type, typename = std::allocator<Type *>> | ||||
| class basic_runtime_view; | ||||
|  | ||||
| template<typename, typename, typename> | ||||
| class basic_group; | ||||
|  | ||||
| template<typename> | ||||
| class basic_observer; | ||||
|  | ||||
| template<typename> | ||||
| class basic_organizer; | ||||
|  | ||||
| template<typename, typename...> | ||||
| struct basic_handle; | ||||
|  | ||||
| template<typename> | ||||
| class basic_snapshot; | ||||
|  | ||||
| template<typename> | ||||
| class basic_snapshot_loader; | ||||
|  | ||||
| template<typename> | ||||
| class basic_continuous_loader; | ||||
|  | ||||
| /** | ||||
|  * @brief Alias for exclusion lists. | ||||
|  * @tparam Type List of types. | ||||
|  */ | ||||
| template<typename... Type> | ||||
| using exclude_t = type_list<Type...>; | ||||
|  | ||||
| /** | ||||
|  * @brief Variable template for exclusion lists. | ||||
|  * @tparam Type List of types. | ||||
|  */ | ||||
| template<typename... Type> | ||||
| inline constexpr exclude_t<Type...> exclude{}; | ||||
|  | ||||
| /** | ||||
|  * @brief Alias for lists of observed components. | ||||
|  * @tparam Type List of types. | ||||
|  */ | ||||
| template<typename... Type> | ||||
| using get_t = type_list<Type...>; | ||||
|  | ||||
| /** | ||||
|  * @brief Variable template for lists of observed components. | ||||
|  * @tparam Type List of types. | ||||
|  */ | ||||
| template<typename... Type> | ||||
| inline constexpr get_t<Type...> get{}; | ||||
|  | ||||
| /** | ||||
|  * @brief Alias for lists of owned components. | ||||
|  * @tparam Type List of types. | ||||
|  */ | ||||
| template<typename... Type> | ||||
| using owned_t = type_list<Type...>; | ||||
|  | ||||
| /** | ||||
|  * @brief Variable template for lists of owned components. | ||||
|  * @tparam Type List of types. | ||||
|  */ | ||||
| template<typename... Type> | ||||
| inline constexpr owned_t<Type...> owned{}; | ||||
|  | ||||
| /*! @brief Alias declaration for the most common use case. */ | ||||
| using sparse_set = basic_sparse_set<>; | ||||
|  | ||||
| /** | ||||
|  * @brief Alias declaration for the most common use case. | ||||
|  * @tparam Type Type of objects assigned to the entities. | ||||
|  */ | ||||
| template<typename Type> | ||||
| using storage = basic_storage<Type>; | ||||
|  | ||||
| /*! @brief Alias declaration for the most common use case. */ | ||||
| using registry = basic_registry<>; | ||||
|  | ||||
| /*! @brief Alias declaration for the most common use case. */ | ||||
| using observer = basic_observer<registry>; | ||||
|  | ||||
| /*! @brief Alias declaration for the most common use case. */ | ||||
| using organizer = basic_organizer<registry>; | ||||
|  | ||||
| /*! @brief Alias declaration for the most common use case. */ | ||||
| using handle = basic_handle<registry>; | ||||
|  | ||||
| /*! @brief Alias declaration for the most common use case. */ | ||||
| using const_handle = basic_handle<const registry>; | ||||
|  | ||||
| /** | ||||
|  * @brief Alias declaration for the most common use case. | ||||
|  * @tparam Args Other template parameters. | ||||
|  */ | ||||
| template<typename... Args> | ||||
| using handle_view = basic_handle<registry, Args...>; | ||||
|  | ||||
| /** | ||||
|  * @brief Alias declaration for the most common use case. | ||||
|  * @tparam Args Other template parameters. | ||||
|  */ | ||||
| template<typename... Args> | ||||
| using const_handle_view = basic_handle<const registry, Args...>; | ||||
|  | ||||
| /*! @brief Alias declaration for the most common use case. */ | ||||
| using snapshot = basic_snapshot<registry>; | ||||
|  | ||||
| /*! @brief Alias declaration for the most common use case. */ | ||||
| using snapshot_loader = basic_snapshot_loader<registry>; | ||||
|  | ||||
| /*! @brief Alias declaration for the most common use case. */ | ||||
| using continuous_loader = basic_continuous_loader<registry>; | ||||
|  | ||||
| /** | ||||
|  * @brief Alias declaration for the most common use case. | ||||
|  * @tparam Get Types of storage iterated by the view. | ||||
|  * @tparam Exclude Types of storage used to filter the view. | ||||
|  */ | ||||
| template<typename Get, typename Exclude = exclude_t<>> | ||||
| using view = basic_view<type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>; | ||||
|  | ||||
| /*! @brief Alias declaration for the most common use case. */ | ||||
| using runtime_view = basic_runtime_view<sparse_set>; | ||||
|  | ||||
| /*! @brief Alias declaration for the most common use case. */ | ||||
| using const_runtime_view = basic_runtime_view<const sparse_set>; | ||||
|  | ||||
| /** | ||||
|  * @brief Alias declaration for the most common use case. | ||||
|  * @tparam Owned Types of storage _owned_ by the group. | ||||
|  * @tparam Get Types of storage _observed_ by the group. | ||||
|  * @tparam Exclude Types of storage used to filter the group. | ||||
|  */ | ||||
| template<typename Owned, typename Get, typename Exclude> | ||||
| using group = basic_group<type_list_transform_t<Owned, storage_for>, type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										852
									
								
								external/entt/entt/src/entt/entity/group.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										852
									
								
								external/entt/entt/src/entt/entity/group.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,852 @@ | ||||
| #ifndef ENTT_ENTITY_GROUP_HPP | ||||
| #define ENTT_ENTITY_GROUP_HPP | ||||
|  | ||||
| #include <tuple> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include "../config/config.h" | ||||
| #include "../core/iterator.hpp" | ||||
| #include "../core/type_traits.hpp" | ||||
| #include "component.hpp" | ||||
| #include "entity.hpp" | ||||
| #include "fwd.hpp" | ||||
| #include "sparse_set.hpp" | ||||
| #include "storage.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename, typename, typename> | ||||
| class extended_group_iterator; | ||||
|  | ||||
| template<typename It, typename... Owned, typename... Get> | ||||
| class extended_group_iterator<It, owned_t<Owned...>, get_t<Get...>> { | ||||
|     template<typename Type> | ||||
|     auto index_to_element([[maybe_unused]] Type &cpool) const { | ||||
|         if constexpr(ignore_as_empty_v<typename Type::value_type>) { | ||||
|             return std::make_tuple(); | ||||
|         } else { | ||||
|             return std::forward_as_tuple(cpool.rbegin()[it.index()]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     using difference_type = std::ptrdiff_t; | ||||
|     using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Owned>().get_as_tuple({})..., std::declval<Get>().get_as_tuple({})...)); | ||||
|     using pointer = input_iterator_pointer<value_type>; | ||||
|     using reference = value_type; | ||||
|     using iterator_category = std::input_iterator_tag; | ||||
|  | ||||
|     constexpr extended_group_iterator() | ||||
|         : it{}, | ||||
|           pools{} {} | ||||
|  | ||||
|     extended_group_iterator(It from, const std::tuple<Owned *..., Get *...> &cpools) | ||||
|         : it{from}, | ||||
|           pools{cpools} {} | ||||
|  | ||||
|     extended_group_iterator &operator++() noexcept { | ||||
|         return ++it, *this; | ||||
|     } | ||||
|  | ||||
|     extended_group_iterator operator++(int) noexcept { | ||||
|         extended_group_iterator orig = *this; | ||||
|         return ++(*this), orig; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] reference operator*() const noexcept { | ||||
|         return std::tuple_cat(std::make_tuple(*it), index_to_element(*std::get<Owned *>(pools))..., std::get<Get *>(pools)->get_as_tuple(*it)...); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] pointer operator->() const noexcept { | ||||
|         return operator*(); | ||||
|     } | ||||
|  | ||||
|     template<typename... Lhs, typename... Rhs> | ||||
|     friend constexpr bool operator==(const extended_group_iterator<Lhs...> &, const extended_group_iterator<Rhs...> &) noexcept; | ||||
|  | ||||
| private: | ||||
|     It it; | ||||
|     std::tuple<Owned *..., Get *...> pools; | ||||
| }; | ||||
|  | ||||
| template<typename... Lhs, typename... Rhs> | ||||
| [[nodiscard]] constexpr bool operator==(const extended_group_iterator<Lhs...> &lhs, const extended_group_iterator<Rhs...> &rhs) noexcept { | ||||
|     return lhs.it == rhs.it; | ||||
| } | ||||
|  | ||||
| template<typename... Lhs, typename... Rhs> | ||||
| [[nodiscard]] constexpr bool operator!=(const extended_group_iterator<Lhs...> &lhs, const extended_group_iterator<Rhs...> &rhs) noexcept { | ||||
|     return !(lhs == rhs); | ||||
| } | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief Group. | ||||
|  * | ||||
|  * Primary template isn't defined on purpose. All the specializations give a | ||||
|  * compile-time error, but for a few reasonable cases. | ||||
|  */ | ||||
| template<typename, typename, typename> | ||||
| class basic_group; | ||||
|  | ||||
| /** | ||||
|  * @brief Non-owning group. | ||||
|  * | ||||
|  * A non-owning group returns all entities and only the entities that are at | ||||
|  * least in the given storage. Moreover, it's guaranteed that the entity list is | ||||
|  * tightly packed in memory for fast iterations. | ||||
|  * | ||||
|  * @b Important | ||||
|  * | ||||
|  * Iterators aren't invalidated if: | ||||
|  * | ||||
|  * * New elements are added to the storage. | ||||
|  * * The entity currently pointed is modified (for example, components are added | ||||
|  *   or removed from it). | ||||
|  * * The entity currently pointed is destroyed. | ||||
|  * | ||||
|  * In all other cases, modifying the pools iterated by the group in any way | ||||
|  * invalidates all the iterators and using them results in undefined behavior. | ||||
|  * | ||||
|  * @tparam Get Types of storage _observed_ by the group. | ||||
|  * @tparam Exclude Types of storage used to filter the group. | ||||
|  */ | ||||
| template<typename... Get, typename... Exclude> | ||||
| class basic_group<owned_t<>, get_t<Get...>, exclude_t<Exclude...>> { | ||||
|     using underlying_type = std::common_type_t<typename Get::entity_type..., typename Exclude::entity_type...>; | ||||
|     using basic_common_type = std::common_type_t<typename Get::base_type..., typename Exclude::base_type...>; | ||||
|  | ||||
|     template<typename Type> | ||||
|     static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Get::value_type...>>; | ||||
|  | ||||
| public: | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = underlying_type; | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using size_type = std::size_t; | ||||
|     /*! @brief Common type among all storage types. */ | ||||
|     using base_type = basic_common_type; | ||||
|     /*! @brief Random access iterator type. */ | ||||
|     using iterator = typename base_type::iterator; | ||||
|     /*! @brief Reversed iterator type. */ | ||||
|     using reverse_iterator = typename base_type::reverse_iterator; | ||||
|     /*! @brief Iterable group type. */ | ||||
|     using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<>, get_t<Get...>>>; | ||||
|  | ||||
|     /*! @brief Default constructor to use to create empty, invalid groups. */ | ||||
|     basic_group() noexcept | ||||
|         : handler{} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a group from a set of storage classes. | ||||
|      * @param ref The actual entities to iterate. | ||||
|      * @param gpool Storage types to iterate _observed_ by the group. | ||||
|      */ | ||||
|     basic_group(basic_common_type &ref, Get &...gpool) noexcept | ||||
|         : handler{&ref}, | ||||
|           pools{&gpool...} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns a const reference to the underlying handler. | ||||
|      * @return A const reference to the underlying handler. | ||||
|      */ | ||||
|     [[nodiscard]] const base_type &handle() const noexcept { | ||||
|         return *handler; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the storage for a given component type. | ||||
|      * @tparam Type Type of component of which to return the storage. | ||||
|      * @return The storage for the given component type. | ||||
|      */ | ||||
|     template<typename Type> | ||||
|     [[nodiscard]] decltype(auto) storage() const noexcept { | ||||
|         return storage<index_of<Type>>(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the storage for a given index. | ||||
|      * @tparam Index Index of the storage to return. | ||||
|      * @return The storage for the given index. | ||||
|      */ | ||||
|     template<std::size_t Index> | ||||
|     [[nodiscard]] decltype(auto) storage() const noexcept { | ||||
|         return *std::get<Index>(pools); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the number of entities that are part of the group. | ||||
|      * @return Number of entities that are part of the group. | ||||
|      */ | ||||
|     [[nodiscard]] size_type size() const noexcept { | ||||
|         return *this ? handler->size() : size_type{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the number of elements that a group has currently | ||||
|      * allocated space for. | ||||
|      * @return Capacity of the group. | ||||
|      */ | ||||
|     [[nodiscard]] size_type capacity() const noexcept { | ||||
|         return *this ? handler->capacity() : size_type{}; | ||||
|     } | ||||
|  | ||||
|     /*! @brief Requests the removal of unused capacity. */ | ||||
|     void shrink_to_fit() { | ||||
|         if(*this) { | ||||
|             handler->shrink_to_fit(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks whether a group is empty. | ||||
|      * @return True if the group is empty, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool empty() const noexcept { | ||||
|         return !*this || handler->empty(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the first entity of the group. | ||||
|      * | ||||
|      * The returned iterator points to the first entity of the group. If the | ||||
|      * group is empty, the returned iterator will be equal to `end()`. | ||||
|      * | ||||
|      * @return An iterator to the first entity of the group. | ||||
|      */ | ||||
|     [[nodiscard]] iterator begin() const noexcept { | ||||
|         return *this ? handler->begin() : iterator{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator that is past the last entity of the group. | ||||
|      * | ||||
|      * The returned iterator points to the entity following the last entity of | ||||
|      * the group. Attempting to dereference the returned iterator results in | ||||
|      * undefined behavior. | ||||
|      * | ||||
|      * @return An iterator to the entity following the last entity of the | ||||
|      * group. | ||||
|      */ | ||||
|     [[nodiscard]] iterator end() const noexcept { | ||||
|         return *this ? handler->end() : iterator{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the first entity of the reversed group. | ||||
|      * | ||||
|      * The returned iterator points to the first entity of the reversed group. | ||||
|      * If the group is empty, the returned iterator will be equal to `rend()`. | ||||
|      * | ||||
|      * @return An iterator to the first entity of the reversed group. | ||||
|      */ | ||||
|     [[nodiscard]] reverse_iterator rbegin() const noexcept { | ||||
|         return *this ? handler->rbegin() : reverse_iterator{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator that is past the last entity of the reversed | ||||
|      * group. | ||||
|      * | ||||
|      * The returned iterator points to the entity following the last entity of | ||||
|      * the reversed group. Attempting to dereference the returned iterator | ||||
|      * results in undefined behavior. | ||||
|      * | ||||
|      * @return An iterator to the entity following the last entity of the | ||||
|      * reversed group. | ||||
|      */ | ||||
|     [[nodiscard]] reverse_iterator rend() const noexcept { | ||||
|         return *this ? handler->rend() : reverse_iterator{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the first entity of the group, if any. | ||||
|      * @return The first entity of the group if one exists, the null entity | ||||
|      * otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] entity_type front() const noexcept { | ||||
|         const auto it = begin(); | ||||
|         return it != end() ? *it : null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the last entity of the group, if any. | ||||
|      * @return The last entity of the group if one exists, the null entity | ||||
|      * otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] entity_type back() const noexcept { | ||||
|         const auto it = rbegin(); | ||||
|         return it != rend() ? *it : null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Finds an entity. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return An iterator to the given entity if it's found, past the end | ||||
|      * iterator otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] iterator find(const entity_type entt) const noexcept { | ||||
|         const auto it = *this ? handler->find(entt) : iterator{}; | ||||
|         return it != end() && *it == entt ? it : end(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the identifier that occupies the given position. | ||||
|      * @param pos Position of the element to return. | ||||
|      * @return The identifier that occupies the given position. | ||||
|      */ | ||||
|     [[nodiscard]] entity_type operator[](const size_type pos) const { | ||||
|         return begin()[pos]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if a group is properly initialized. | ||||
|      * @return True if the group is properly initialized, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] explicit operator bool() const noexcept { | ||||
|         return handler != nullptr; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if a group contains an entity. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return True if the group contains the given entity, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool contains(const entity_type entt) const noexcept { | ||||
|         return *this && handler->contains(entt); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the components assigned to the given entity. | ||||
|      * | ||||
|      * Prefer this function instead of `registry::get` during iterations. It has | ||||
|      * far better performance than its counterpart. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to use an invalid component type results in a compilation | ||||
|      * error. Attempting to use an entity that doesn't belong to the group | ||||
|      * results in undefined behavior. | ||||
|      * | ||||
|      * @tparam Type Types of components to get. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return The components assigned to the entity. | ||||
|      */ | ||||
|     template<typename... Type> | ||||
|     [[nodiscard]] decltype(auto) get(const entity_type entt) const { | ||||
|         if constexpr(sizeof...(Type) == 0) { | ||||
|             return std::apply([entt](auto *...curr) { return std::tuple_cat(curr->get_as_tuple(entt)...); }, pools); | ||||
|         } else if constexpr(sizeof...(Type) == 1) { | ||||
|             return (std::get<index_of<Type>>(pools)->get(entt), ...); | ||||
|         } else { | ||||
|             return std::tuple_cat(std::get<index_of<Type>>(pools)->get_as_tuple(entt)...); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Iterates entities and components and applies the given function | ||||
|      * object to them. | ||||
|      * | ||||
|      * The function object is invoked for each entity. It is provided with the | ||||
|      * entity itself and a set of references to non-empty components. The | ||||
|      * _constness_ of the components is as requested.<br/> | ||||
|      * The signature of the function must be equivalent to one of the following | ||||
|      * forms: | ||||
|      * | ||||
|      * @code{.cpp} | ||||
|      * void(const entity_type, Type &...); | ||||
|      * void(Type &...); | ||||
|      * @endcode | ||||
|      * | ||||
|      * @note | ||||
|      * Empty types aren't explicitly instantiated and therefore they are never | ||||
|      * returned during iterations. | ||||
|      * | ||||
|      * @tparam Func Type of the function object to invoke. | ||||
|      * @param func A valid function object. | ||||
|      */ | ||||
|     template<typename Func> | ||||
|     void each(Func func) const { | ||||
|         for(const auto entt: *this) { | ||||
|             if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) { | ||||
|                 std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt))); | ||||
|             } else { | ||||
|                 std::apply(func, get(entt)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterable object to use to _visit_ a group. | ||||
|      * | ||||
|      * The iterable object returns tuples that contain the current entity and a | ||||
|      * set of references to its non-empty components. The _constness_ of the | ||||
|      * components is as requested. | ||||
|      * | ||||
|      * @note | ||||
|      * Empty types aren't explicitly instantiated and therefore they are never | ||||
|      * returned during iterations. | ||||
|      * | ||||
|      * @return An iterable object to use to _visit_ the group. | ||||
|      */ | ||||
|     [[nodiscard]] iterable each() const noexcept { | ||||
|         return iterable{{begin(), pools}, {end(), pools}}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Sort a group according to the given comparison function. | ||||
|      * | ||||
|      * Sort the group so that iterating it with a couple of iterators returns | ||||
|      * entities and components in the expected order. See `begin` and `end` for | ||||
|      * more details. | ||||
|      * | ||||
|      * The comparison function object must return `true` if the first element | ||||
|      * is _less_ than the second one, `false` otherwise. The signature of the | ||||
|      * comparison function should be equivalent to one of the following: | ||||
|      * | ||||
|      * @code{.cpp} | ||||
|      * bool(std::tuple<Type &...>, std::tuple<Type &...>); | ||||
|      * bool(const Type &..., const Type &...); | ||||
|      * bool(const Entity, const Entity); | ||||
|      * @endcode | ||||
|      * | ||||
|      * Where `Type` are such that they are iterated by the group.<br/> | ||||
|      * Moreover, the comparison function object shall induce a | ||||
|      * _strict weak ordering_ on the values. | ||||
|      * | ||||
|      * The sort function object must offer a member function template | ||||
|      * `operator()` that accepts three arguments: | ||||
|      * | ||||
|      * * An iterator to the first element of the range to sort. | ||||
|      * * An iterator past the last element of the range to sort. | ||||
|      * * A comparison function to use to compare the elements. | ||||
|      * | ||||
|      * @tparam Type Optional types of components to compare. | ||||
|      * @tparam Compare Type of comparison function object. | ||||
|      * @tparam Sort Type of sort function object. | ||||
|      * @tparam Args Types of arguments to forward to the sort function object. | ||||
|      * @param compare A valid comparison function object. | ||||
|      * @param algo A valid sort function object. | ||||
|      * @param args Arguments to forward to the sort function object, if any. | ||||
|      */ | ||||
|     template<typename... Type, typename Compare, typename Sort = std_sort, typename... Args> | ||||
|     void sort(Compare compare, Sort algo = Sort{}, Args &&...args) { | ||||
|         if(*this) { | ||||
|             if constexpr(sizeof...(Type) == 0) { | ||||
|                 static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function"); | ||||
|                 handler->sort(std::move(compare), std::move(algo), std::forward<Args>(args)...); | ||||
|             } else { | ||||
|                 auto comp = [this, &compare](const entity_type lhs, const entity_type rhs) { | ||||
|                     if constexpr(sizeof...(Type) == 1) { | ||||
|                         return compare((std::get<index_of<Type>>(pools)->get(lhs), ...), (std::get<index_of<Type>>(pools)->get(rhs), ...)); | ||||
|                     } else { | ||||
|                         return compare(std::forward_as_tuple(std::get<index_of<Type>>(pools)->get(lhs)...), std::forward_as_tuple(std::get<index_of<Type>>(pools)->get(rhs)...)); | ||||
|                     } | ||||
|                 }; | ||||
|  | ||||
|                 handler->sort(std::move(comp), std::move(algo), std::forward<Args>(args)...); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Sort the shared pool of entities according to the given component. | ||||
|      * | ||||
|      * Non-owning groups of the same type share with the registry a pool of | ||||
|      * entities with its own order that doesn't depend on the order of any pool | ||||
|      * of components. Users can order the underlying data structure so that it | ||||
|      * respects the order of the pool of the given component. | ||||
|      * | ||||
|      * @note | ||||
|      * The shared pool of entities and thus its order is affected by the changes | ||||
|      * to each and every pool that it tracks. Therefore changes to those pools | ||||
|      * can quickly ruin the order imposed to the pool of entities shared between | ||||
|      * the non-owning groups. | ||||
|      * | ||||
|      * @tparam Type Type of component to use to impose the order. | ||||
|      */ | ||||
|     template<typename Type> | ||||
|     void sort() const { | ||||
|         if(*this) { | ||||
|             handler->respect(*std::get<index_of<Type>>(pools)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     base_type *const handler; | ||||
|     const std::tuple<Get *...> pools; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Owning group. | ||||
|  * | ||||
|  * Owning groups returns all entities and only the entities that are at | ||||
|  * least in the given storage. Moreover: | ||||
|  * | ||||
|  * * It's guaranteed that the entity list is tightly packed in memory for fast | ||||
|  *   iterations. | ||||
|  * * It's guaranteed that all components in the owned storage are tightly packed | ||||
|  *   in memory for even faster iterations and to allow direct access. | ||||
|  * * They stay true to the order of the owned storage and all instances have the | ||||
|  *   same order in memory. | ||||
|  * | ||||
|  * The more types of storage are owned, the faster it is to iterate a group. | ||||
|  * | ||||
|  * @b Important | ||||
|  * | ||||
|  * Iterators aren't invalidated if: | ||||
|  * | ||||
|  * * New elements are added to the storage. | ||||
|  * * The entity currently pointed is modified (for example, components are added | ||||
|  *   or removed from it). | ||||
|  * * The entity currently pointed is destroyed. | ||||
|  * | ||||
|  * In all other cases, modifying the pools iterated by the group in any way | ||||
|  * invalidates all the iterators and using them results in undefined behavior. | ||||
|  * | ||||
|  * @tparam Owned Types of storage _owned_ by the group. | ||||
|  * @tparam Get Types of storage _observed_ by the group. | ||||
|  * @tparam Exclude Types of storage used to filter the group. | ||||
|  */ | ||||
| template<typename... Owned, typename... Get, typename... Exclude> | ||||
| class basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> { | ||||
|     using underlying_type = std::common_type_t<typename Owned::entity_type..., typename Get::entity_type..., typename Exclude::entity_type...>; | ||||
|     using basic_common_type = std::common_type_t<typename Owned::base_type..., typename Get::base_type..., typename Exclude::base_type...>; | ||||
|  | ||||
|     template<typename Type> | ||||
|     static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Owned::value_type..., typename Get::value_type...>>; | ||||
|  | ||||
| public: | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = underlying_type; | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using size_type = std::size_t; | ||||
|     /*! @brief Common type among all storage types. */ | ||||
|     using base_type = basic_common_type; | ||||
|     /*! @brief Random access iterator type. */ | ||||
|     using iterator = typename base_type::iterator; | ||||
|     /*! @brief Reversed iterator type. */ | ||||
|     using reverse_iterator = typename base_type::reverse_iterator; | ||||
|     /*! @brief Iterable group type. */ | ||||
|     using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<Owned...>, get_t<Get...>>>; | ||||
|  | ||||
|     /*! @brief Default constructor to use to create empty, invalid groups. */ | ||||
|     basic_group() noexcept | ||||
|         : length{} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a group from a set of storage classes. | ||||
|      * @param extent The actual number of entities to iterate. | ||||
|      * @param opool Storage types to iterate _owned_ by the group. | ||||
|      * @param gpool Storage types to iterate _observed_ by the group. | ||||
|      */ | ||||
|     basic_group(const std::size_t &extent, Owned &...opool, Get &...gpool) noexcept | ||||
|         : pools{&opool..., &gpool...}, | ||||
|           length{&extent} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the storage for a given component type. | ||||
|      * @tparam Type Type of component of which to return the storage. | ||||
|      * @return The storage for the given component type. | ||||
|      */ | ||||
|     template<typename Type> | ||||
|     [[nodiscard]] decltype(auto) storage() const noexcept { | ||||
|         return storage<index_of<Type>>(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the storage for a given index. | ||||
|      * @tparam Index Index of the storage to return. | ||||
|      * @return The storage for the given index. | ||||
|      */ | ||||
|     template<std::size_t Index> | ||||
|     [[nodiscard]] decltype(auto) storage() const noexcept { | ||||
|         return *std::get<Index>(pools); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the number of entities that that are part of the group. | ||||
|      * @return Number of entities that that are part of the group. | ||||
|      */ | ||||
|     [[nodiscard]] size_type size() const noexcept { | ||||
|         return *this ? *length : size_type{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks whether a group is empty. | ||||
|      * @return True if the group is empty, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool empty() const noexcept { | ||||
|         return !*this || !*length; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the first entity of the group. | ||||
|      * | ||||
|      * The returned iterator points to the first entity of the group. If the | ||||
|      * group is empty, the returned iterator will be equal to `end()`. | ||||
|      * | ||||
|      * @return An iterator to the first entity of the group. | ||||
|      */ | ||||
|     [[nodiscard]] iterator begin() const noexcept { | ||||
|         return *this ? (std::get<0>(pools)->base_type::end() - *length) : iterator{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator that is past the last entity of the group. | ||||
|      * | ||||
|      * The returned iterator points to the entity following the last entity of | ||||
|      * the group. Attempting to dereference the returned iterator results in | ||||
|      * undefined behavior. | ||||
|      * | ||||
|      * @return An iterator to the entity following the last entity of the | ||||
|      * group. | ||||
|      */ | ||||
|     [[nodiscard]] iterator end() const noexcept { | ||||
|         return *this ? std::get<0>(pools)->base_type::end() : iterator{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the first entity of the reversed group. | ||||
|      * | ||||
|      * The returned iterator points to the first entity of the reversed group. | ||||
|      * If the group is empty, the returned iterator will be equal to `rend()`. | ||||
|      * | ||||
|      * @return An iterator to the first entity of the reversed group. | ||||
|      */ | ||||
|     [[nodiscard]] reverse_iterator rbegin() const noexcept { | ||||
|         return *this ? std::get<0>(pools)->base_type::rbegin() : reverse_iterator{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator that is past the last entity of the reversed | ||||
|      * group. | ||||
|      * | ||||
|      * The returned iterator points to the entity following the last entity of | ||||
|      * the reversed group. Attempting to dereference the returned iterator | ||||
|      * results in undefined behavior. | ||||
|      * | ||||
|      * @return An iterator to the entity following the last entity of the | ||||
|      * reversed group. | ||||
|      */ | ||||
|     [[nodiscard]] reverse_iterator rend() const noexcept { | ||||
|         return *this ? (std::get<0>(pools)->base_type::rbegin() + *length) : reverse_iterator{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the first entity of the group, if any. | ||||
|      * @return The first entity of the group if one exists, the null entity | ||||
|      * otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] entity_type front() const noexcept { | ||||
|         const auto it = begin(); | ||||
|         return it != end() ? *it : null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the last entity of the group, if any. | ||||
|      * @return The last entity of the group if one exists, the null entity | ||||
|      * otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] entity_type back() const noexcept { | ||||
|         const auto it = rbegin(); | ||||
|         return it != rend() ? *it : null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Finds an entity. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return An iterator to the given entity if it's found, past the end | ||||
|      * iterator otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] iterator find(const entity_type entt) const noexcept { | ||||
|         const auto it = *this ? std::get<0>(pools)->find(entt) : iterator{}; | ||||
|         return it != end() && it >= begin() && *it == entt ? it : end(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the identifier that occupies the given position. | ||||
|      * @param pos Position of the element to return. | ||||
|      * @return The identifier that occupies the given position. | ||||
|      */ | ||||
|     [[nodiscard]] entity_type operator[](const size_type pos) const { | ||||
|         return begin()[pos]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if a group is properly initialized. | ||||
|      * @return True if the group is properly initialized, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] explicit operator bool() const noexcept { | ||||
|         return length != nullptr; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if a group contains an entity. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return True if the group contains the given entity, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool contains(const entity_type entt) const noexcept { | ||||
|         return *this && std::get<0>(pools)->contains(entt) && (std::get<0>(pools)->index(entt) < (*length)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the components assigned to the given entity. | ||||
|      * | ||||
|      * Prefer this function instead of `registry::get` during iterations. It has | ||||
|      * far better performance than its counterpart. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to use an invalid component type results in a compilation | ||||
|      * error. Attempting to use an entity that doesn't belong to the group | ||||
|      * results in undefined behavior. | ||||
|      * | ||||
|      * @tparam Type Types of components to get. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return The components assigned to the entity. | ||||
|      */ | ||||
|     template<typename... Type> | ||||
|     [[nodiscard]] decltype(auto) get(const entity_type entt) const { | ||||
|         if constexpr(sizeof...(Type) == 0) { | ||||
|             return std::apply([entt](auto *...curr) { return std::tuple_cat(curr->get_as_tuple(entt)...); }, pools); | ||||
|         } else if constexpr(sizeof...(Type) == 1) { | ||||
|             return (std::get<index_of<Type>>(pools)->get(entt), ...); | ||||
|         } else { | ||||
|             return std::tuple_cat(std::get<index_of<Type>>(pools)->get_as_tuple(entt)...); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Iterates entities and components and applies the given function | ||||
|      * object to them. | ||||
|      * | ||||
|      * The function object is invoked for each entity. It is provided with the | ||||
|      * entity itself and a set of references to non-empty components. The | ||||
|      * _constness_ of the components is as requested.<br/> | ||||
|      * The signature of the function must be equivalent to one of the following | ||||
|      * forms: | ||||
|      * | ||||
|      * @code{.cpp} | ||||
|      * void(const entity_type, Type &...); | ||||
|      * void(Type &...); | ||||
|      * @endcode | ||||
|      * | ||||
|      * @note | ||||
|      * Empty types aren't explicitly instantiated and therefore they are never | ||||
|      * returned during iterations. | ||||
|      * | ||||
|      * @tparam Func Type of the function object to invoke. | ||||
|      * @param func A valid function object. | ||||
|      */ | ||||
|     template<typename Func> | ||||
|     void each(Func func) const { | ||||
|         for(auto args: each()) { | ||||
|             if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) { | ||||
|                 std::apply(func, args); | ||||
|             } else { | ||||
|                 std::apply([&func](auto, auto &&...less) { func(std::forward<decltype(less)>(less)...); }, args); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterable object to use to _visit_ a group. | ||||
|      * | ||||
|      * The iterable object returns tuples that contain the current entity and a | ||||
|      * set of references to its non-empty components. The _constness_ of the | ||||
|      * components is as requested. | ||||
|      * | ||||
|      * @note | ||||
|      * Empty types aren't explicitly instantiated and therefore they are never | ||||
|      * returned during iterations. | ||||
|      * | ||||
|      * @return An iterable object to use to _visit_ the group. | ||||
|      */ | ||||
|     [[nodiscard]] iterable each() const noexcept { | ||||
|         return {{begin(), pools}, {end(), pools}}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Sort a group according to the given comparison function. | ||||
|      * | ||||
|      * Sort the group so that iterating it with a couple of iterators returns | ||||
|      * entities and components in the expected order. See `begin` and `end` for | ||||
|      * more details. | ||||
|      * | ||||
|      * The comparison function object must return `true` if the first element | ||||
|      * is _less_ than the second one, `false` otherwise. The signature of the | ||||
|      * comparison function should be equivalent to one of the following: | ||||
|      * | ||||
|      * @code{.cpp} | ||||
|      * bool(std::tuple<Type &...>, std::tuple<Type &...>); | ||||
|      * bool(const Type &, const Type &); | ||||
|      * bool(const Entity, const Entity); | ||||
|      * @endcode | ||||
|      * | ||||
|      * Where `Type` are either owned types or not but still such that they are | ||||
|      * iterated by the group.<br/> | ||||
|      * Moreover, the comparison function object shall induce a | ||||
|      * _strict weak ordering_ on the values. | ||||
|      * | ||||
|      * The sort function object must offer a member function template | ||||
|      * `operator()` that accepts three arguments: | ||||
|      * | ||||
|      * * An iterator to the first element of the range to sort. | ||||
|      * * An iterator past the last element of the range to sort. | ||||
|      * * A comparison function to use to compare the elements. | ||||
|      * | ||||
|      * @tparam Type Optional types of components to compare. | ||||
|      * @tparam Compare Type of comparison function object. | ||||
|      * @tparam Sort Type of sort function object. | ||||
|      * @tparam Args Types of arguments to forward to the sort function object. | ||||
|      * @param compare A valid comparison function object. | ||||
|      * @param algo A valid sort function object. | ||||
|      * @param args Arguments to forward to the sort function object, if any. | ||||
|      */ | ||||
|     template<typename... Type, typename Compare, typename Sort = std_sort, typename... Args> | ||||
|     void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const { | ||||
|         if constexpr(sizeof...(Type) == 0) { | ||||
|             static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function"); | ||||
|             std::get<0>(pools)->sort_n(*length, std::move(compare), std::move(algo), std::forward<Args>(args)...); | ||||
|         } else { | ||||
|             auto comp = [this, &compare](const entity_type lhs, const entity_type rhs) { | ||||
|                 if constexpr(sizeof...(Type) == 1) { | ||||
|                     return compare((std::get<index_of<Type>>(pools)->get(lhs), ...), (std::get<index_of<Type>>(pools)->get(rhs), ...)); | ||||
|                 } else { | ||||
|                     return compare(std::forward_as_tuple(std::get<index_of<Type>>(pools)->get(lhs)...), std::forward_as_tuple(std::get<index_of<Type>>(pools)->get(rhs)...)); | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             std::get<0>(pools)->sort_n(*length, std::move(comp), std::move(algo), std::forward<Args>(args)...); | ||||
|         } | ||||
|  | ||||
|         std::apply([this](auto *head, auto *...other) { | ||||
|             for(auto next = *length; next; --next) { | ||||
|                 const auto pos = next - 1; | ||||
|                 [[maybe_unused]] const auto entt = head->data()[pos]; | ||||
|                 (other->swap_elements(other->data()[pos], entt), ...); | ||||
|             } | ||||
|         }, | ||||
|                    pools); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     const std::tuple<Owned *..., Get *...> pools; | ||||
|     const size_type *const length; | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										382
									
								
								external/entt/entt/src/entt/entity/handle.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										382
									
								
								external/entt/entt/src/entt/entity/handle.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,382 @@ | ||||
| #ifndef ENTT_ENTITY_HANDLE_HPP | ||||
| #define ENTT_ENTITY_HANDLE_HPP | ||||
|  | ||||
| #include <iterator> | ||||
| #include <tuple> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include "../core/iterator.hpp" | ||||
| #include "../core/type_traits.hpp" | ||||
| #include "entity.hpp" | ||||
| #include "fwd.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename It> | ||||
| class handle_storage_iterator final { | ||||
|     template<typename Other> | ||||
|     friend class handle_storage_iterator; | ||||
|  | ||||
|     using underlying_type = std::remove_reference_t<typename It::value_type::second_type>; | ||||
|     using entity_type = typename underlying_type::entity_type; | ||||
|  | ||||
| public: | ||||
|     using value_type = typename std::iterator_traits<It>::value_type; | ||||
|     using pointer = input_iterator_pointer<value_type>; | ||||
|     using reference = value_type; | ||||
|     using difference_type = std::ptrdiff_t; | ||||
|     using iterator_category = std::input_iterator_tag; | ||||
|  | ||||
|     constexpr handle_storage_iterator() noexcept | ||||
|         : entt{null}, | ||||
|           it{}, | ||||
|           last{} {} | ||||
|  | ||||
|     constexpr handle_storage_iterator(entity_type value, It from, It to) noexcept | ||||
|         : entt{value}, | ||||
|           it{from}, | ||||
|           last{to} { | ||||
|         while(it != last && !it->second.contains(entt)) { ++it; } | ||||
|     } | ||||
|  | ||||
|     constexpr handle_storage_iterator &operator++() noexcept { | ||||
|         while(++it != last && !it->second.contains(entt)) {} | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     constexpr handle_storage_iterator operator++(int) noexcept { | ||||
|         handle_storage_iterator orig = *this; | ||||
|         return ++(*this), orig; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr reference operator*() const noexcept { | ||||
|         return *it; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr pointer operator->() const noexcept { | ||||
|         return operator*(); | ||||
|     } | ||||
|  | ||||
|     template<typename ILhs, typename IRhs> | ||||
|     friend constexpr bool operator==(const handle_storage_iterator<ILhs> &, const handle_storage_iterator<IRhs> &) noexcept; | ||||
|  | ||||
| private: | ||||
|     entity_type entt; | ||||
|     It it; | ||||
|     It last; | ||||
| }; | ||||
|  | ||||
| template<typename ILhs, typename IRhs> | ||||
| [[nodiscard]] constexpr bool operator==(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept { | ||||
|     return lhs.it == rhs.it; | ||||
| } | ||||
|  | ||||
| template<typename ILhs, typename IRhs> | ||||
| [[nodiscard]] constexpr bool operator!=(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept { | ||||
|     return !(lhs == rhs); | ||||
| } | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief Non-owning handle to an entity. | ||||
|  * | ||||
|  * Tiny wrapper around a registry and an entity. | ||||
|  * | ||||
|  * @tparam Registry Basic registry type. | ||||
|  * @tparam Scope Types to which to restrict the scope of a handle. | ||||
|  */ | ||||
| template<typename Registry, typename... Scope> | ||||
| struct basic_handle { | ||||
|     /*! @brief Type of registry accepted by the handle. */ | ||||
|     using registry_type = Registry; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = typename registry_type::entity_type; | ||||
|     /*! @brief Underlying version type. */ | ||||
|     using version_type = typename registry_type::version_type; | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using size_type = typename registry_type::size_type; | ||||
|  | ||||
|     /*! @brief Constructs an invalid handle. */ | ||||
|     basic_handle() noexcept | ||||
|         : reg{}, | ||||
|           entt{null} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a handle from a given registry and entity. | ||||
|      * @param ref An instance of the registry class. | ||||
|      * @param value A valid identifier. | ||||
|      */ | ||||
|     basic_handle(registry_type &ref, entity_type value) noexcept | ||||
|         : reg{&ref}, | ||||
|           entt{value} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterable object to use to _visit_ a handle. | ||||
|      * | ||||
|      * The iterable object returns a pair that contains the name and a reference | ||||
|      * to the current storage.<br/> | ||||
|      * Returned storage are those that contain the entity associated with the | ||||
|      * handle. | ||||
|      * | ||||
|      * @return An iterable object to use to _visit_ the handle. | ||||
|      */ | ||||
|     [[nodiscard]] auto storage() const noexcept { | ||||
|         auto iterable = reg->storage(); | ||||
|         using iterator_type = internal::handle_storage_iterator<typename decltype(iterable)::iterator>; | ||||
|         return iterable_adaptor{iterator_type{entt, iterable.begin(), iterable.end()}, iterator_type{entt, iterable.end(), iterable.end()}}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a const handle from a non-const one. | ||||
|      * @tparam Other A valid entity type (see entt_traits for more details). | ||||
|      * @tparam Args Scope of the handle to construct. | ||||
|      * @return A const handle referring to the same registry and the same | ||||
|      * entity. | ||||
|      */ | ||||
|     template<typename Other, typename... Args> | ||||
|     operator basic_handle<Other, Args...>() const noexcept { | ||||
|         static_assert(std::is_same_v<Other, Registry> || std::is_same_v<std::remove_const_t<Other>, Registry>, "Invalid conversion between different handles"); | ||||
|         static_assert((sizeof...(Scope) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Scope)) && ... && (type_list_contains_v<type_list<Scope...>, Args>))), "Invalid conversion between different handles"); | ||||
|  | ||||
|         return reg ? basic_handle<Other, Args...>{*reg, entt} : basic_handle<Other, Args...>{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Converts a handle to its underlying entity. | ||||
|      * @return The contained identifier. | ||||
|      */ | ||||
|     [[nodiscard]] operator entity_type() const noexcept { | ||||
|         return entity(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if a handle refers to non-null registry pointer and entity. | ||||
|      * @return True if the handle refers to non-null registry and entity, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] explicit operator bool() const noexcept { | ||||
|         return reg && reg->valid(entt); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if a handle refers to a valid entity or not. | ||||
|      * @return True if the handle refers to a valid entity, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool valid() const { | ||||
|         return reg->valid(entt); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns a pointer to the underlying registry, if any. | ||||
|      * @return A pointer to the underlying registry, if any. | ||||
|      */ | ||||
|     [[nodiscard]] registry_type *registry() const noexcept { | ||||
|         return reg; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the entity associated with a handle. | ||||
|      * @return The entity associated with the handle. | ||||
|      */ | ||||
|     [[nodiscard]] entity_type entity() const noexcept { | ||||
|         return entt; | ||||
|     } | ||||
|  | ||||
|     /*! @brief Destroys the entity associated with a handle. */ | ||||
|     void destroy() { | ||||
|         reg->destroy(entt); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Destroys the entity associated with a handle. | ||||
|      * @param version A desired version upon destruction. | ||||
|      */ | ||||
|     void destroy(const version_type version) { | ||||
|         reg->destroy(entt, version); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns the given component to a handle. | ||||
|      * @tparam Component Type of component to create. | ||||
|      * @tparam Args Types of arguments to use to construct the component. | ||||
|      * @param args Parameters to use to initialize the component. | ||||
|      * @return A reference to the newly created component. | ||||
|      */ | ||||
|     template<typename Component, typename... Args> | ||||
|     decltype(auto) emplace(Args &&...args) const { | ||||
|         static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type"); | ||||
|         return reg->template emplace<Component>(entt, std::forward<Args>(args)...); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns or replaces the given component for a handle. | ||||
|      * @tparam Component Type of component to assign or replace. | ||||
|      * @tparam Args Types of arguments to use to construct the component. | ||||
|      * @param args Parameters to use to initialize the component. | ||||
|      * @return A reference to the newly created component. | ||||
|      */ | ||||
|     template<typename Component, typename... Args> | ||||
|     decltype(auto) emplace_or_replace(Args &&...args) const { | ||||
|         static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type"); | ||||
|         return reg->template emplace_or_replace<Component>(entt, std::forward<Args>(args)...); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Patches the given component for a handle. | ||||
|      * @tparam Component Type of component to patch. | ||||
|      * @tparam Func Types of the function objects to invoke. | ||||
|      * @param func Valid function objects. | ||||
|      * @return A reference to the patched component. | ||||
|      */ | ||||
|     template<typename Component, typename... Func> | ||||
|     decltype(auto) patch(Func &&...func) const { | ||||
|         static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type"); | ||||
|         return reg->template patch<Component>(entt, std::forward<Func>(func)...); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Replaces the given component for a handle. | ||||
|      * @tparam Component Type of component to replace. | ||||
|      * @tparam Args Types of arguments to use to construct the component. | ||||
|      * @param args Parameters to use to initialize the component. | ||||
|      * @return A reference to the component being replaced. | ||||
|      */ | ||||
|     template<typename Component, typename... Args> | ||||
|     decltype(auto) replace(Args &&...args) const { | ||||
|         static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type"); | ||||
|         return reg->template replace<Component>(entt, std::forward<Args>(args)...); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Removes the given components from a handle. | ||||
|      * @tparam Component Types of components to remove. | ||||
|      * @return The number of components actually removed. | ||||
|      */ | ||||
|     template<typename... Component> | ||||
|     size_type remove() const { | ||||
|         static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type"); | ||||
|         return reg->template remove<Component...>(entt); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Erases the given components from a handle. | ||||
|      * @tparam Component Types of components to erase. | ||||
|      */ | ||||
|     template<typename... Component> | ||||
|     void erase() const { | ||||
|         static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type"); | ||||
|         reg->template erase<Component...>(entt); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if a handle has all the given components. | ||||
|      * @tparam Component Components for which to perform the check. | ||||
|      * @return True if the handle has all the components, false otherwise. | ||||
|      */ | ||||
|     template<typename... Component> | ||||
|     [[nodiscard]] decltype(auto) all_of() const { | ||||
|         return reg->template all_of<Component...>(entt); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if a handle has at least one of the given components. | ||||
|      * @tparam Component Components for which to perform the check. | ||||
|      * @return True if the handle has at least one of the given components, | ||||
|      * false otherwise. | ||||
|      */ | ||||
|     template<typename... Component> | ||||
|     [[nodiscard]] decltype(auto) any_of() const { | ||||
|         return reg->template any_of<Component...>(entt); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns references to the given components for a handle. | ||||
|      * @tparam Component Types of components to get. | ||||
|      * @return References to the components owned by the handle. | ||||
|      */ | ||||
|     template<typename... Component> | ||||
|     [[nodiscard]] decltype(auto) get() const { | ||||
|         static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type"); | ||||
|         return reg->template get<Component...>(entt); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns a reference to the given component for a handle. | ||||
|      * @tparam Component Type of component to get. | ||||
|      * @tparam Args Types of arguments to use to construct the component. | ||||
|      * @param args Parameters to use to initialize the component. | ||||
|      * @return Reference to the component owned by the handle. | ||||
|      */ | ||||
|     template<typename Component, typename... Args> | ||||
|     [[nodiscard]] decltype(auto) get_or_emplace(Args &&...args) const { | ||||
|         static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type"); | ||||
|         return reg->template get_or_emplace<Component>(entt, std::forward<Args>(args)...); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns pointers to the given components for a handle. | ||||
|      * @tparam Component Types of components to get. | ||||
|      * @return Pointers to the components owned by the handle. | ||||
|      */ | ||||
|     template<typename... Component> | ||||
|     [[nodiscard]] auto try_get() const { | ||||
|         static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type"); | ||||
|         return reg->template try_get<Component...>(entt); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if a handle has components assigned. | ||||
|      * @return True if the handle has no components assigned, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool orphan() const { | ||||
|         return reg->orphan(entt); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     registry_type *reg; | ||||
|     entity_type entt; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Compares two handles. | ||||
|  * @tparam Args Scope of the first handle. | ||||
|  * @tparam Other Scope of the second handle. | ||||
|  * @param lhs A valid handle. | ||||
|  * @param rhs A valid handle. | ||||
|  * @return True if both handles refer to the same registry and the same | ||||
|  * entity, false otherwise. | ||||
|  */ | ||||
| template<typename... Args, typename... Other> | ||||
| [[nodiscard]] bool operator==(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) noexcept { | ||||
|     return lhs.registry() == rhs.registry() && lhs.entity() == rhs.entity(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Compares two handles. | ||||
|  * @tparam Args Scope of the first handle. | ||||
|  * @tparam Other Scope of the second handle. | ||||
|  * @param lhs A valid handle. | ||||
|  * @param rhs A valid handle. | ||||
|  * @return False if both handles refer to the same registry and the same | ||||
|  * entity, true otherwise. | ||||
|  */ | ||||
| template<typename... Args, typename... Other> | ||||
| [[nodiscard]] bool operator!=(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) noexcept { | ||||
|     return !(lhs == rhs); | ||||
| } | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										144
									
								
								external/entt/entt/src/entt/entity/helper.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								external/entt/entt/src/entt/entity/helper.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | ||||
| #ifndef ENTT_ENTITY_HELPER_HPP | ||||
| #define ENTT_ENTITY_HELPER_HPP | ||||
|  | ||||
| #include <memory> | ||||
| #include <type_traits> | ||||
| #include "../core/fwd.hpp" | ||||
| #include "../core/type_traits.hpp" | ||||
| #include "../signal/delegate.hpp" | ||||
| #include "component.hpp" | ||||
| #include "fwd.hpp" | ||||
| #include "group.hpp" | ||||
| #include "view.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @brief Converts a registry to a view. | ||||
|  * @tparam Registry Basic registry type. | ||||
|  */ | ||||
| template<typename Registry> | ||||
| class as_view { | ||||
|     template<typename... Get, typename... Exclude> | ||||
|     auto dispatch(get_t<Get...>, exclude_t<Exclude...>) const { | ||||
|         return reg.template view<constness_as_t<typename Get::value_type, Get>...>(exclude_t<constness_as_t<typename Exclude::value_type, Exclude>...>{}); | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! @brief Type of registry to convert. */ | ||||
|     using registry_type = Registry; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = std::remove_const_t<typename registry_type::entity_type>; | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a converter for a given registry. | ||||
|      * @param source A valid reference to a registry. | ||||
|      */ | ||||
|     as_view(registry_type &source) noexcept | ||||
|         : reg{source} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Conversion function from a registry to a view. | ||||
|      * @tparam Get Type of storage used to construct the view. | ||||
|      * @tparam Exclude Types of storage used to filter the view. | ||||
|      * @return A newly created view. | ||||
|      */ | ||||
|     template<typename Get, typename Exclude> | ||||
|     operator basic_view<Get, Exclude>() const { | ||||
|         return dispatch(Get{}, Exclude{}); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     registry_type ® | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Converts a registry to a group. | ||||
|  * @tparam Registry Basic registry type. | ||||
|  */ | ||||
| template<typename Registry> | ||||
| class as_group { | ||||
|     template<typename... Owned, typename... Get, typename... Exclude> | ||||
|     auto dispatch(owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>) const { | ||||
|         if constexpr(std::is_const_v<registry_type>) { | ||||
|             return reg.template group_if_exists<typename Owned::value_type...>(get_t<typename Get::value_type...>{}, exclude_t<typename Exclude::value_type...>{}); | ||||
|         } else { | ||||
|             return reg.template group<constness_as_t<typename Owned::value_type, Owned>...>(get_t<constness_as_t<typename Get::value_type, Get>...>{}, exclude_t<constness_as_t<typename Exclude::value_type, Exclude>...>{}); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! @brief Type of registry to convert. */ | ||||
|     using registry_type = Registry; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = std::remove_const_t<typename registry_type::entity_type>; | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a converter for a given registry. | ||||
|      * @param source A valid reference to a registry. | ||||
|      */ | ||||
|     as_group(registry_type &source) noexcept | ||||
|         : reg{source} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Conversion function from a registry to a group. | ||||
|      * @tparam Owned Types of _owned_ by the group. | ||||
|      * @tparam Get Types of storage _observed_ by the group. | ||||
|      * @tparam Exclude Types of storage used to filter the group. | ||||
|      * @return A newly created group. | ||||
|      */ | ||||
|     template<typename Owned, typename Get, typename Exclude> | ||||
|     operator basic_group<Owned, Get, Exclude>() const { | ||||
|         return dispatch(Owned{}, Get{}, Exclude{}); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     registry_type ® | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper to create a listener that directly invokes a member function. | ||||
|  * @tparam Member Member function to invoke on a component of the given type. | ||||
|  * @tparam Registry Basic registry type. | ||||
|  * @param reg A registry that contains the given entity and its components. | ||||
|  * @param entt Entity from which to get the component. | ||||
|  */ | ||||
| template<auto Member, typename Registry = std::decay_t<nth_argument_t<0u, Member>>> | ||||
| void invoke(Registry ®, const typename Registry::entity_type entt) { | ||||
|     static_assert(std::is_member_function_pointer_v<decltype(Member)>, "Invalid pointer to non-static member function"); | ||||
|     delegate<void(Registry &, const typename Registry::entity_type)> func; | ||||
|     func.template connect<Member>(reg.template get<member_class_t<decltype(Member)>>(entt)); | ||||
|     func(reg, entt); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Returns the entity associated with a given component. | ||||
|  * | ||||
|  * @warning | ||||
|  * Currently, this function only works correctly with the default pool as it | ||||
|  * makes assumptions about how the components are laid out. | ||||
|  * | ||||
|  * @tparam Registry Basic registry type. | ||||
|  * @tparam Component Type of component. | ||||
|  * @param reg A registry that contains the given entity and its components. | ||||
|  * @param instance A valid component instance. | ||||
|  * @return The entity associated with the given component. | ||||
|  */ | ||||
| template<typename Registry, typename Component> | ||||
| typename Registry::entity_type to_entity(const Registry ®, const Component &instance) { | ||||
|     const auto &storage = reg.template storage<Component>(); | ||||
|     const typename Registry::base_type &base = storage; | ||||
|     const auto *addr = std::addressof(instance); | ||||
|  | ||||
|     for(auto it = base.rbegin(), last = base.rend(); it < last; it += component_traits<Component>::page_size) { | ||||
|         if(const auto dist = (addr - std::addressof(storage.get(*it))); dist >= 0 && dist < static_cast<decltype(dist)>(component_traits<Component>::page_size)) { | ||||
|             return *(it + dist); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return null; | ||||
| } | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										432
									
								
								external/entt/entt/src/entt/entity/observer.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										432
									
								
								external/entt/entt/src/entt/entity/observer.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,432 @@ | ||||
| #ifndef ENTT_ENTITY_OBSERVER_HPP | ||||
| #define ENTT_ENTITY_OBSERVER_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <cstdint> | ||||
| #include <limits> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include "../core/type_traits.hpp" | ||||
| #include "../signal/delegate.hpp" | ||||
| #include "fwd.hpp" | ||||
| #include "storage.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /*! @brief Grouping matcher. */ | ||||
| template<typename...> | ||||
| struct matcher {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Collector. | ||||
|  * | ||||
|  * Primary template isn't defined on purpose. All the specializations give a | ||||
|  * compile-time error, but for a few reasonable cases. | ||||
|  */ | ||||
| template<typename...> | ||||
| struct basic_collector; | ||||
|  | ||||
| /** | ||||
|  * @brief Collector. | ||||
|  * | ||||
|  * A collector contains a set of rules (literally, matchers) to use to track | ||||
|  * entities.<br/> | ||||
|  * Its main purpose is to generate a descriptor that allows an observer to know | ||||
|  * how to connect to a registry. | ||||
|  */ | ||||
| template<> | ||||
| struct basic_collector<> { | ||||
|     /** | ||||
|      * @brief Adds a grouping matcher to the collector. | ||||
|      * @tparam AllOf Types of components tracked by the matcher. | ||||
|      * @tparam NoneOf Types of components used to filter out entities. | ||||
|      * @return The updated collector. | ||||
|      */ | ||||
|     template<typename... AllOf, typename... NoneOf> | ||||
|     static constexpr auto group(exclude_t<NoneOf...> = {}) noexcept { | ||||
|         return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>>{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Adds an observing matcher to the collector. | ||||
|      * @tparam AnyOf Type of component for which changes should be detected. | ||||
|      * @return The updated collector. | ||||
|      */ | ||||
|     template<typename AnyOf> | ||||
|     static constexpr auto update() noexcept { | ||||
|         return basic_collector<matcher<type_list<>, type_list<>, AnyOf>>{}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Collector. | ||||
|  * @copydetails basic_collector<> | ||||
|  * @tparam Reject Untracked types used to filter out entities. | ||||
|  * @tparam Require Untracked types required by the matcher. | ||||
|  * @tparam Rule Specific details of the current matcher. | ||||
|  * @tparam Other Other matchers. | ||||
|  */ | ||||
| template<typename... Reject, typename... Require, typename... Rule, typename... Other> | ||||
| struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule...>, Other...> { | ||||
|     /*! @brief Current matcher. */ | ||||
|     using current_type = matcher<type_list<Reject...>, type_list<Require...>, Rule...>; | ||||
|  | ||||
|     /** | ||||
|      * @brief Adds a grouping matcher to the collector. | ||||
|      * @tparam AllOf Types of components tracked by the matcher. | ||||
|      * @tparam NoneOf Types of components used to filter out entities. | ||||
|      * @return The updated collector. | ||||
|      */ | ||||
|     template<typename... AllOf, typename... NoneOf> | ||||
|     static constexpr auto group(exclude_t<NoneOf...> = {}) noexcept { | ||||
|         return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>, current_type, Other...>{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Adds an observing matcher to the collector. | ||||
|      * @tparam AnyOf Type of component for which changes should be detected. | ||||
|      * @return The updated collector. | ||||
|      */ | ||||
|     template<typename AnyOf> | ||||
|     static constexpr auto update() noexcept { | ||||
|         return basic_collector<matcher<type_list<>, type_list<>, AnyOf>, current_type, Other...>{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Updates the filter of the last added matcher. | ||||
|      * @tparam AllOf Types of components required by the matcher. | ||||
|      * @tparam NoneOf Types of components used to filter out entities. | ||||
|      * @return The updated collector. | ||||
|      */ | ||||
|     template<typename... AllOf, typename... NoneOf> | ||||
|     static constexpr auto where(exclude_t<NoneOf...> = {}) noexcept { | ||||
|         using extended_type = matcher<type_list<Reject..., NoneOf...>, type_list<Require..., AllOf...>, Rule...>; | ||||
|         return basic_collector<extended_type, Other...>{}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /*! @brief Variable template used to ease the definition of collectors. */ | ||||
| inline constexpr basic_collector<> collector{}; | ||||
|  | ||||
| /** | ||||
|  * @brief Observer. | ||||
|  * | ||||
|  * An observer returns all the entities and only the entities that fit the | ||||
|  * requirements of at least one matcher. Moreover, it's guaranteed that the | ||||
|  * entity list is tightly packed in memory for fast iterations.<br/> | ||||
|  * In general, observers don't stay true to the order of any set of components. | ||||
|  * | ||||
|  * Observers work mainly with two types of matchers, provided through a | ||||
|  * collector: | ||||
|  * | ||||
|  * * Observing matcher: an observer will return at least all the living entities | ||||
|  *   for which one or more of the given components have been updated and not yet | ||||
|  *   destroyed. | ||||
|  * * Grouping matcher: an observer will return at least all the living entities | ||||
|  *   that would have entered the given group if it existed and that would have | ||||
|  *   not yet left it. | ||||
|  * | ||||
|  * If an entity respects the requirements of multiple matchers, it will be | ||||
|  * returned once and only once by the observer in any case. | ||||
|  * | ||||
|  * Matchers support also filtering by means of a _where_ clause that accepts | ||||
|  * both a list of types and an exclusion list.<br/> | ||||
|  * Whenever a matcher finds that an entity matches its requirements, the | ||||
|  * condition of the filter is verified before to register the entity itself. | ||||
|  * Moreover, a registered entity isn't returned by the observer if the condition | ||||
|  * set by the filter is broken in the meantime. | ||||
|  * | ||||
|  * @b Important | ||||
|  * | ||||
|  * Iterators aren't invalidated if: | ||||
|  * | ||||
|  * * New instances of the given components are created and assigned to entities. | ||||
|  * * The entity currently pointed is modified (as an example, if one of the | ||||
|  *   given components is removed from the entity to which the iterator points). | ||||
|  * * The entity currently pointed is destroyed. | ||||
|  * | ||||
|  * In all the other cases, modifying the pools of the given components in any | ||||
|  * way invalidates all the iterators and using them results in undefined | ||||
|  * behavior. | ||||
|  * | ||||
|  * @warning | ||||
|  * Lifetime of an observer doesn't necessarily have to overcome that of the | ||||
|  * registry to which it is connected. However, the observer must be disconnected | ||||
|  * from the registry before being destroyed to avoid crashes due to dangling | ||||
|  * pointers. | ||||
|  * | ||||
|  * @tparam Registry Basic registry type. | ||||
|  */ | ||||
| template<typename Registry> | ||||
| class basic_observer: private basic_storage<std::uint32_t, typename Registry::entity_type> { | ||||
|     using base_type = basic_storage<std::uint32_t, typename Registry::entity_type>; | ||||
|  | ||||
|     template<typename> | ||||
|     struct matcher_handler; | ||||
|  | ||||
|     template<typename... Reject, typename... Require, typename AnyOf> | ||||
|     struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, AnyOf>> { | ||||
|         template<std::size_t Index> | ||||
|         static void maybe_valid_if(basic_observer &obs, Registry ®, const typename Registry::entity_type entt) { | ||||
|             if(reg.template all_of<Require...>(entt) && !reg.template any_of<Reject...>(entt)) { | ||||
|                 if(!obs.contains(entt)) { | ||||
|                     obs.emplace(entt); | ||||
|                 } | ||||
|  | ||||
|                 obs.get(entt) |= (1 << Index); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         template<std::size_t Index> | ||||
|         static void discard_if(basic_observer &obs, Registry &, const typename Registry::entity_type entt) { | ||||
|             if(obs.contains(entt) && !(obs.get(entt) &= (~(1 << Index)))) { | ||||
|                 obs.erase(entt); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         template<std::size_t Index> | ||||
|         static void connect(basic_observer &obs, Registry ®) { | ||||
|             (reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...); | ||||
|             (reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...); | ||||
|             reg.template on_update<AnyOf>().template connect<&maybe_valid_if<Index>>(obs); | ||||
|             reg.template on_destroy<AnyOf>().template connect<&discard_if<Index>>(obs); | ||||
|         } | ||||
|  | ||||
|         static void disconnect(basic_observer &obs, Registry ®) { | ||||
|             (reg.template on_destroy<Require>().disconnect(obs), ...); | ||||
|             (reg.template on_construct<Reject>().disconnect(obs), ...); | ||||
|             reg.template on_update<AnyOf>().disconnect(obs); | ||||
|             reg.template on_destroy<AnyOf>().disconnect(obs); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     template<typename... Reject, typename... Require, typename... NoneOf, typename... AllOf> | ||||
|     struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, type_list<NoneOf...>, AllOf...>> { | ||||
|         template<std::size_t Index, typename... Ignore> | ||||
|         static void maybe_valid_if(basic_observer &obs, Registry ®, const typename Registry::entity_type entt) { | ||||
|             auto condition = [®, entt]() { | ||||
|                 if constexpr(sizeof...(Ignore) == 0) { | ||||
|                     return reg.template all_of<AllOf..., Require...>(entt) && !reg.template any_of<NoneOf..., Reject...>(entt); | ||||
|                 } else { | ||||
|                     return reg.template all_of<AllOf..., Require...>(entt) && ((std::is_same_v<Ignore..., NoneOf> || !reg.template any_of<NoneOf>(entt)) && ...) && !reg.template any_of<Reject...>(entt); | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             if(condition()) { | ||||
|                 if(!obs.contains(entt)) { | ||||
|                     obs.emplace(entt); | ||||
|                 } | ||||
|  | ||||
|                 obs.get(entt) |= (1 << Index); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         template<std::size_t Index> | ||||
|         static void discard_if(basic_observer &obs, Registry &, const typename Registry::entity_type entt) { | ||||
|             if(obs.contains(entt) && !(obs.get(entt) &= (~(1 << Index)))) { | ||||
|                 obs.erase(entt); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         template<std::size_t Index> | ||||
|         static void connect(basic_observer &obs, Registry ®) { | ||||
|             (reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...); | ||||
|             (reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...); | ||||
|             (reg.template on_construct<AllOf>().template connect<&maybe_valid_if<Index>>(obs), ...); | ||||
|             (reg.template on_destroy<NoneOf>().template connect<&maybe_valid_if<Index, NoneOf>>(obs), ...); | ||||
|             (reg.template on_destroy<AllOf>().template connect<&discard_if<Index>>(obs), ...); | ||||
|             (reg.template on_construct<NoneOf>().template connect<&discard_if<Index>>(obs), ...); | ||||
|         } | ||||
|  | ||||
|         static void disconnect(basic_observer &obs, Registry ®) { | ||||
|             (reg.template on_destroy<Require>().disconnect(obs), ...); | ||||
|             (reg.template on_construct<Reject>().disconnect(obs), ...); | ||||
|             (reg.template on_construct<AllOf>().disconnect(obs), ...); | ||||
|             (reg.template on_destroy<NoneOf>().disconnect(obs), ...); | ||||
|             (reg.template on_destroy<AllOf>().disconnect(obs), ...); | ||||
|             (reg.template on_construct<NoneOf>().disconnect(obs), ...); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     template<typename... Matcher> | ||||
|     static void disconnect(Registry ®, basic_observer &obs) { | ||||
|         (matcher_handler<Matcher>::disconnect(obs, reg), ...); | ||||
|     } | ||||
|  | ||||
|     template<typename... Matcher, std::size_t... Index> | ||||
|     void connect(Registry ®, std::index_sequence<Index...>) { | ||||
|         static_assert(sizeof...(Matcher) < std::numeric_limits<typename base_type::value_type>::digits, "Too many matchers"); | ||||
|         (matcher_handler<Matcher>::template connect<Index>(*this, reg), ...); | ||||
|         release.template connect<&basic_observer::disconnect<Matcher...>>(reg); | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! Basic registry type. */ | ||||
|     using registry_type = Registry; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = typename registry_type::entity_type; | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using size_type = std::size_t; | ||||
|     /*! @brief Random access iterator type. */ | ||||
|     using iterator = typename registry_type::base_type::iterator; | ||||
|  | ||||
|     /*! @brief Default constructor. */ | ||||
|     basic_observer() | ||||
|         : release{} {} | ||||
|  | ||||
|     /*! @brief Default copy constructor, deleted on purpose. */ | ||||
|     basic_observer(const basic_observer &) = delete; | ||||
|     /*! @brief Default move constructor, deleted on purpose. */ | ||||
|     basic_observer(basic_observer &&) = delete; | ||||
|  | ||||
|     /** | ||||
|      * @brief Creates an observer and connects it to a given registry. | ||||
|      * @tparam Matcher Types of matchers to use to initialize the observer. | ||||
|      * @param reg A valid reference to a registry. | ||||
|      */ | ||||
|     template<typename... Matcher> | ||||
|     basic_observer(registry_type ®, basic_collector<Matcher...>) | ||||
|         : basic_observer{} { | ||||
|         connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{}); | ||||
|     } | ||||
|  | ||||
|     /*! @brief Default destructor. */ | ||||
|     ~basic_observer() = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Default copy assignment operator, deleted on purpose. | ||||
|      * @return This observer. | ||||
|      */ | ||||
|     basic_observer &operator=(const basic_observer &) = delete; | ||||
|  | ||||
|     /** | ||||
|      * @brief Default move assignment operator, deleted on purpose. | ||||
|      * @return This observer. | ||||
|      */ | ||||
|     basic_observer &operator=(basic_observer &&) = delete; | ||||
|  | ||||
|     /** | ||||
|      * @brief Connects an observer to a given registry. | ||||
|      * @tparam Matcher Types of matchers to use to initialize the observer. | ||||
|      * @param reg A valid reference to a registry. | ||||
|      */ | ||||
|     template<typename... Matcher> | ||||
|     void connect(registry_type ®, basic_collector<Matcher...>) { | ||||
|         disconnect(); | ||||
|         connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{}); | ||||
|         base_type::clear(); | ||||
|     } | ||||
|  | ||||
|     /*! @brief Disconnects an observer from the registry it keeps track of. */ | ||||
|     void disconnect() { | ||||
|         if(release) { | ||||
|             release(*this); | ||||
|             release.reset(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the number of elements in an observer. | ||||
|      * @return Number of elements. | ||||
|      */ | ||||
|     [[nodiscard]] size_type size() const noexcept { | ||||
|         return base_type::size(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks whether an observer is empty. | ||||
|      * @return True if the observer is empty, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool empty() const noexcept { | ||||
|         return base_type::empty(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Direct access to the list of entities of the observer. | ||||
|      * | ||||
|      * The returned pointer is such that range `[data(), data() + size())` is | ||||
|      * always a valid range, even if the container is empty. | ||||
|      * | ||||
|      * @note | ||||
|      * Entities are in the reverse order as returned by the `begin`/`end` | ||||
|      * iterators. | ||||
|      * | ||||
|      * @return A pointer to the array of entities. | ||||
|      */ | ||||
|     [[nodiscard]] const entity_type *data() const noexcept { | ||||
|         return base_type::data(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the first entity of the observer. | ||||
|      * | ||||
|      * The returned iterator points to the first entity of the observer. If the | ||||
|      * container is empty, the returned iterator will be equal to `end()`. | ||||
|      * | ||||
|      * @return An iterator to the first entity of the observer. | ||||
|      */ | ||||
|     [[nodiscard]] iterator begin() const noexcept { | ||||
|         return base_type::base_type::begin(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator that is past the last entity of the observer. | ||||
|      * | ||||
|      * The returned iterator points to the entity following the last entity of | ||||
|      * the observer. Attempting to dereference the returned iterator results in | ||||
|      * undefined behavior. | ||||
|      * | ||||
|      * @return An iterator to the entity following the last entity of the | ||||
|      * observer. | ||||
|      */ | ||||
|     [[nodiscard]] iterator end() const noexcept { | ||||
|         return base_type::base_type::end(); | ||||
|     } | ||||
|  | ||||
|     /*! @brief Clears the underlying container. */ | ||||
|     void clear() noexcept { | ||||
|         base_type::clear(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Iterates entities and applies the given function object to them. | ||||
|      * | ||||
|      * The function object is invoked for each entity.<br/> | ||||
|      * The signature of the function must be equivalent to the following form: | ||||
|      * | ||||
|      * @code{.cpp} | ||||
|      * void(const entity_type); | ||||
|      * @endcode | ||||
|      * | ||||
|      * @tparam Func Type of the function object to invoke. | ||||
|      * @param func A valid function object. | ||||
|      */ | ||||
|     template<typename Func> | ||||
|     void each(Func func) const { | ||||
|         for(const auto entity: *this) { | ||||
|             func(entity); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Iterates entities and applies the given function object to them, | ||||
|      * then clears the observer. | ||||
|      * | ||||
|      * @sa each | ||||
|      * | ||||
|      * @tparam Func Type of the function object to invoke. | ||||
|      * @param func A valid function object. | ||||
|      */ | ||||
|     template<typename Func> | ||||
|     void each(Func func) { | ||||
|         std::as_const(*this).each(std::move(func)); | ||||
|         clear(); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     delegate<void(basic_observer &)> release; | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										412
									
								
								external/entt/entt/src/entt/entity/organizer.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										412
									
								
								external/entt/entt/src/entt/entity/organizer.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,412 @@ | ||||
| #ifndef ENTT_ENTITY_ORGANIZER_HPP | ||||
| #define ENTT_ENTITY_ORGANIZER_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include "../core/type_info.hpp" | ||||
| #include "../core/type_traits.hpp" | ||||
| #include "../core/utility.hpp" | ||||
| #include "../graph/adjacency_matrix.hpp" | ||||
| #include "../graph/flow.hpp" | ||||
| #include "fwd.hpp" | ||||
| #include "helper.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename> | ||||
| struct is_view: std::false_type {}; | ||||
|  | ||||
| template<typename... Args> | ||||
| struct is_view<basic_view<Args...>>: std::true_type {}; | ||||
|  | ||||
| template<typename Type> | ||||
| inline constexpr bool is_view_v = is_view<Type>::value; | ||||
|  | ||||
| template<typename Type, typename Override> | ||||
| struct unpack_type { | ||||
|     using ro = std::conditional_t< | ||||
|         type_list_contains_v<Override, const Type> || (std::is_const_v<Type> && !type_list_contains_v<Override, std::remove_const_t<Type>>), | ||||
|         type_list<std::remove_const_t<Type>>, | ||||
|         type_list<>>; | ||||
|  | ||||
|     using rw = std::conditional_t< | ||||
|         type_list_contains_v<Override, std::remove_const_t<Type>> || (!std::is_const_v<Type> && !type_list_contains_v<Override, const Type>), | ||||
|         type_list<Type>, | ||||
|         type_list<>>; | ||||
| }; | ||||
|  | ||||
| template<typename... Args, typename... Override> | ||||
| struct unpack_type<basic_registry<Args...>, type_list<Override...>> { | ||||
|     using ro = type_list<>; | ||||
|     using rw = type_list<>; | ||||
| }; | ||||
|  | ||||
| template<typename... Args, typename... Override> | ||||
| struct unpack_type<const basic_registry<Args...>, type_list<Override...>> | ||||
|     : unpack_type<basic_registry<Args...>, type_list<Override...>> {}; | ||||
|  | ||||
| template<typename... Get, typename... Exclude, typename... Override> | ||||
| struct unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> { | ||||
|     using ro = type_list_cat_t<type_list<typename Exclude::value_type...>, typename unpack_type<constness_as_t<typename Get::value_type, Get>, type_list<Override...>>::ro...>; | ||||
|     using rw = type_list_cat_t<typename unpack_type<constness_as_t<typename Get::value_type, Get>, type_list<Override...>>::rw...>; | ||||
| }; | ||||
|  | ||||
| template<typename... Get, typename... Exclude, typename... Override> | ||||
| struct unpack_type<const basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> | ||||
|     : unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {}; | ||||
|  | ||||
| template<typename, typename> | ||||
| struct resource_traits; | ||||
|  | ||||
| template<typename... Args, typename... Req> | ||||
| struct resource_traits<type_list<Args...>, type_list<Req...>> { | ||||
|     using args = type_list<std::remove_const_t<Args>...>; | ||||
|     using ro = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::ro..., typename unpack_type<Req, type_list<>>::ro...>; | ||||
|     using rw = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::rw..., typename unpack_type<Req, type_list<>>::rw...>; | ||||
| }; | ||||
|  | ||||
| template<typename... Req, typename Ret, typename... Args> | ||||
| resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> free_function_to_resource_traits(Ret (*)(Args...)); | ||||
|  | ||||
| template<typename... Req, typename Ret, typename Type, typename... Args> | ||||
| resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (*)(Type &, Args...)); | ||||
|  | ||||
| template<typename... Req, typename Ret, typename Class, typename... Args> | ||||
| resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...)); | ||||
|  | ||||
| template<typename... Req, typename Ret, typename Class, typename... Args> | ||||
| resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const); | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief Utility class for creating a static task graph. | ||||
|  * | ||||
|  * This class offers minimal support (but sufficient in many cases) for creating | ||||
|  * an execution graph from functions and their requirements on resources.<br/> | ||||
|  * Note that the resulting tasks aren't executed in any case. This isn't the | ||||
|  * goal of the tool. Instead, they are returned to the user in the form of a | ||||
|  * graph that allows for safe execution. | ||||
|  * | ||||
|  * @tparam Registry Basic registry type. | ||||
|  */ | ||||
| template<typename Registry> | ||||
| class basic_organizer final { | ||||
|     using callback_type = void(const void *, Registry &); | ||||
|     using prepare_type = void(Registry &); | ||||
|     using dependency_type = std::size_t(const bool, const type_info **, const std::size_t); | ||||
|  | ||||
|     struct vertex_data final { | ||||
|         std::size_t ro_count{}; | ||||
|         std::size_t rw_count{}; | ||||
|         const char *name{}; | ||||
|         const void *payload{}; | ||||
|         callback_type *callback{}; | ||||
|         dependency_type *dependency; | ||||
|         prepare_type *prepare{}; | ||||
|         const type_info *info{}; | ||||
|     }; | ||||
|  | ||||
|     template<typename Type> | ||||
|     [[nodiscard]] static decltype(auto) extract(Registry ®) { | ||||
|         if constexpr(std::is_same_v<Type, Registry>) { | ||||
|             return reg; | ||||
|         } else if constexpr(internal::is_view_v<Type>) { | ||||
|             return as_view{reg}; | ||||
|         } else { | ||||
|             return reg.ctx().template emplace<std::remove_reference_t<Type>>(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template<typename... Args> | ||||
|     [[nodiscard]] static auto to_args(Registry ®, type_list<Args...>) { | ||||
|         return std::tuple<decltype(extract<Args>(reg))...>(extract<Args>(reg)...); | ||||
|     } | ||||
|  | ||||
|     template<typename... Type> | ||||
|     static std::size_t fill_dependencies(type_list<Type...>, [[maybe_unused]] const type_info **buffer, [[maybe_unused]] const std::size_t count) { | ||||
|         if constexpr(sizeof...(Type) == 0u) { | ||||
|             return {}; | ||||
|         } else { | ||||
|             const type_info *info[sizeof...(Type)]{&type_id<Type>()...}; | ||||
|             const auto length = count < sizeof...(Type) ? count : sizeof...(Type); | ||||
|  | ||||
|             for(std::size_t pos{}; pos < length; ++pos) { | ||||
|                 buffer[pos] = info[pos]; | ||||
|             } | ||||
|  | ||||
|             return length; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template<typename... RO, typename... RW> | ||||
|     void track_dependencies(std::size_t index, const bool requires_registry, type_list<RO...>, type_list<RW...>) { | ||||
|         builder.bind(static_cast<id_type>(index)); | ||||
|         builder.set(type_hash<Registry>::value(), requires_registry || (sizeof...(RO) + sizeof...(RW) == 0u)); | ||||
|         (builder.ro(type_hash<RO>::value()), ...); | ||||
|         (builder.rw(type_hash<RW>::value()), ...); | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! Basic registry type. */ | ||||
|     using registry_type = Registry; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = typename registry_type::entity_type; | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using size_type = std::size_t; | ||||
|     /*! @brief Raw task function type. */ | ||||
|     using function_type = callback_type; | ||||
|  | ||||
|     /*! @brief Vertex type of a task graph defined as an adjacency list. */ | ||||
|     struct vertex { | ||||
|         /** | ||||
|          * @brief Constructs a vertex of the task graph. | ||||
|          * @param vtype True if the vertex is a top-level one, false otherwise. | ||||
|          * @param data The data associated with the vertex. | ||||
|          * @param edges The indices of the children in the adjacency list. | ||||
|          */ | ||||
|         vertex(const bool vtype, vertex_data data, std::vector<std::size_t> edges) | ||||
|             : is_top_level{vtype}, | ||||
|               node{std::move(data)}, | ||||
|               reachable{std::move(edges)} {} | ||||
|  | ||||
|         /** | ||||
|          * @brief Fills a buffer with the type info objects for the writable | ||||
|          * resources of a vertex. | ||||
|          * @param buffer A buffer pre-allocated by the user. | ||||
|          * @param length The length of the user-supplied buffer. | ||||
|          * @return The number of type info objects written to the buffer. | ||||
|          */ | ||||
|         size_type ro_dependency(const type_info **buffer, const std::size_t length) const noexcept { | ||||
|             return node.dependency(false, buffer, length); | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * @brief Fills a buffer with the type info objects for the read-only | ||||
|          * resources of a vertex. | ||||
|          * @param buffer A buffer pre-allocated by the user. | ||||
|          * @param length The length of the user-supplied buffer. | ||||
|          * @return The number of type info objects written to the buffer. | ||||
|          */ | ||||
|         size_type rw_dependency(const type_info **buffer, const std::size_t length) const noexcept { | ||||
|             return node.dependency(true, buffer, length); | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * @brief Returns the number of read-only resources of a vertex. | ||||
|          * @return The number of read-only resources of the vertex. | ||||
|          */ | ||||
|         size_type ro_count() const noexcept { | ||||
|             return node.ro_count; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * @brief Returns the number of writable resources of a vertex. | ||||
|          * @return The number of writable resources of the vertex. | ||||
|          */ | ||||
|         size_type rw_count() const noexcept { | ||||
|             return node.rw_count; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * @brief Checks if a vertex is also a top-level one. | ||||
|          * @return True if the vertex is a top-level one, false otherwise. | ||||
|          */ | ||||
|         bool top_level() const noexcept { | ||||
|             return is_top_level; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * @brief Returns a type info object associated with a vertex. | ||||
|          * @return A properly initialized type info object. | ||||
|          */ | ||||
|         const type_info &info() const noexcept { | ||||
|             return *node.info; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * @brief Returns a user defined name associated with a vertex, if any. | ||||
|          * @return The user defined name associated with the vertex, if any. | ||||
|          */ | ||||
|         const char *name() const noexcept { | ||||
|             return node.name; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * @brief Returns the function associated with a vertex. | ||||
|          * @return The function associated with the vertex. | ||||
|          */ | ||||
|         function_type *callback() const noexcept { | ||||
|             return node.callback; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * @brief Returns the payload associated with a vertex, if any. | ||||
|          * @return The payload associated with the vertex, if any. | ||||
|          */ | ||||
|         const void *data() const noexcept { | ||||
|             return node.payload; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * @brief Returns the list of nodes reachable from a given vertex. | ||||
|          * @return The list of nodes reachable from the vertex. | ||||
|          */ | ||||
|         const std::vector<std::size_t> &children() const noexcept { | ||||
|             return reachable; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * @brief Prepares a registry and assures that all required resources | ||||
|          * are properly instantiated before using them. | ||||
|          * @param reg A valid registry. | ||||
|          */ | ||||
|         void prepare(registry_type ®) const { | ||||
|             node.prepare ? node.prepare(reg) : void(); | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         bool is_top_level; | ||||
|         vertex_data node; | ||||
|         std::vector<std::size_t> reachable; | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * @brief Adds a free function to the task list. | ||||
|      * @tparam Candidate Function to add to the task list. | ||||
|      * @tparam Req Additional requirements and/or override resource access mode. | ||||
|      * @param name Optional name to associate with the task. | ||||
|      */ | ||||
|     template<auto Candidate, typename... Req> | ||||
|     void emplace(const char *name = nullptr) { | ||||
|         using resource_type = decltype(internal::free_function_to_resource_traits<Req...>(Candidate)); | ||||
|         constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>; | ||||
|  | ||||
|         callback_type *callback = +[](const void *, registry_type ®) { | ||||
|             std::apply(Candidate, to_args(reg, typename resource_type::args{})); | ||||
|         }; | ||||
|  | ||||
|         vertex_data vdata{ | ||||
|             resource_type::ro::size, | ||||
|             resource_type::rw::size, | ||||
|             name, | ||||
|             nullptr, | ||||
|             callback, | ||||
|             +[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); }, | ||||
|             +[](registry_type ®) { void(to_args(reg, typename resource_type::args{})); }, | ||||
|             &type_id<std::integral_constant<decltype(Candidate), Candidate>>()}; | ||||
|  | ||||
|         track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{}); | ||||
|         vertices.push_back(std::move(vdata)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Adds a free function with payload or a member function with an | ||||
|      * instance to the task list. | ||||
|      * @tparam Candidate Function or member to add to the task list. | ||||
|      * @tparam Req Additional requirements and/or override resource access mode. | ||||
|      * @tparam Type Type of class or type of payload. | ||||
|      * @param value_or_instance A valid object that fits the purpose. | ||||
|      * @param name Optional name to associate with the task. | ||||
|      */ | ||||
|     template<auto Candidate, typename... Req, typename Type> | ||||
|     void emplace(Type &value_or_instance, const char *name = nullptr) { | ||||
|         using resource_type = decltype(internal::constrained_function_to_resource_traits<Req...>(Candidate)); | ||||
|         constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>; | ||||
|  | ||||
|         callback_type *callback = +[](const void *payload, registry_type ®) { | ||||
|             Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload)); | ||||
|             std::apply(Candidate, std::tuple_cat(std::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{}))); | ||||
|         }; | ||||
|  | ||||
|         vertex_data vdata{ | ||||
|             resource_type::ro::size, | ||||
|             resource_type::rw::size, | ||||
|             name, | ||||
|             &value_or_instance, | ||||
|             callback, | ||||
|             +[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); }, | ||||
|             +[](registry_type ®) { void(to_args(reg, typename resource_type::args{})); }, | ||||
|             &type_id<std::integral_constant<decltype(Candidate), Candidate>>()}; | ||||
|  | ||||
|         track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{}); | ||||
|         vertices.push_back(std::move(vdata)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Adds an user defined function with optional payload to the task | ||||
|      * list. | ||||
|      * @tparam Req Additional requirements and/or override resource access mode. | ||||
|      * @param func Function to add to the task list. | ||||
|      * @param payload User defined arbitrary data. | ||||
|      * @param name Optional name to associate with the task. | ||||
|      */ | ||||
|     template<typename... Req> | ||||
|     void emplace(function_type *func, const void *payload = nullptr, const char *name = nullptr) { | ||||
|         using resource_type = internal::resource_traits<type_list<>, type_list<Req...>>; | ||||
|         track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{}); | ||||
|  | ||||
|         vertex_data vdata{ | ||||
|             resource_type::ro::size, | ||||
|             resource_type::rw::size, | ||||
|             name, | ||||
|             payload, | ||||
|             func, | ||||
|             +[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); }, | ||||
|             nullptr, | ||||
|             &type_id<void>()}; | ||||
|  | ||||
|         vertices.push_back(std::move(vdata)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Generates a task graph for the current content. | ||||
|      * @return The adjacency list of the task graph. | ||||
|      */ | ||||
|     std::vector<vertex> graph() { | ||||
|         std::vector<vertex> adjacency_list{}; | ||||
|         adjacency_list.reserve(vertices.size()); | ||||
|         auto adjacency_matrix = builder.graph(); | ||||
|  | ||||
|         for(auto curr: adjacency_matrix.vertices()) { | ||||
|             const auto iterable = adjacency_matrix.in_edges(curr); | ||||
|             std::vector<std::size_t> reachable{}; | ||||
|  | ||||
|             for(auto &&edge: adjacency_matrix.out_edges(curr)) { | ||||
|                 reachable.push_back(edge.second); | ||||
|             } | ||||
|  | ||||
|             adjacency_list.emplace_back(iterable.cbegin() == iterable.cend(), vertices[curr], std::move(reachable)); | ||||
|         } | ||||
|  | ||||
|         return adjacency_list; | ||||
|     } | ||||
|  | ||||
|     /*! @brief Erases all elements from a container. */ | ||||
|     void clear() { | ||||
|         builder.clear(); | ||||
|         vertices.clear(); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     std::vector<vertex_data> vertices; | ||||
|     flow builder; | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1530
									
								
								external/entt/entt/src/entt/entity/registry.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1530
									
								
								external/entt/entt/src/entt/entity/registry.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										335
									
								
								external/entt/entt/src/entt/entity/runtime_view.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								external/entt/entt/src/entt/entity/runtime_view.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,335 @@ | ||||
| #ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP | ||||
| #define ENTT_ENTITY_RUNTIME_VIEW_HPP | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <cstddef> | ||||
| #include <iterator> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include "entity.hpp" | ||||
| #include "fwd.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename Set> | ||||
| class runtime_view_iterator final { | ||||
|     using iterator_type = typename Set::iterator; | ||||
|  | ||||
|     [[nodiscard]] bool valid() const { | ||||
|         return (!tombstone_check || *it != tombstone) | ||||
|                && std::all_of(++pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); }) | ||||
|                && std::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); }); | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     using difference_type = typename iterator_type::difference_type; | ||||
|     using value_type = typename iterator_type::value_type; | ||||
|     using pointer = typename iterator_type::pointer; | ||||
|     using reference = typename iterator_type::reference; | ||||
|     using iterator_category = std::bidirectional_iterator_tag; | ||||
|  | ||||
|     constexpr runtime_view_iterator() noexcept | ||||
|         : pools{}, | ||||
|           filter{}, | ||||
|           it{}, | ||||
|           tombstone_check{} {} | ||||
|  | ||||
|     runtime_view_iterator(const std::vector<Set *> &cpools, const std::vector<Set *> &ignore, iterator_type curr) noexcept | ||||
|         : pools{&cpools}, | ||||
|           filter{&ignore}, | ||||
|           it{curr}, | ||||
|           tombstone_check{pools->size() == 1u && (*pools)[0u]->policy() == deletion_policy::in_place} { | ||||
|         if(it != (*pools)[0]->end() && !valid()) { | ||||
|             ++(*this); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     runtime_view_iterator &operator++() { | ||||
|         while(++it != (*pools)[0]->end() && !valid()) {} | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     runtime_view_iterator operator++(int) { | ||||
|         runtime_view_iterator orig = *this; | ||||
|         return ++(*this), orig; | ||||
|     } | ||||
|  | ||||
|     runtime_view_iterator &operator--() { | ||||
|         while(--it != (*pools)[0]->begin() && !valid()) {} | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     runtime_view_iterator operator--(int) { | ||||
|         runtime_view_iterator orig = *this; | ||||
|         return operator--(), orig; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] pointer operator->() const noexcept { | ||||
|         return it.operator->(); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] reference operator*() const noexcept { | ||||
|         return *operator->(); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr bool operator==(const runtime_view_iterator &other) const noexcept { | ||||
|         return it == other.it; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr bool operator!=(const runtime_view_iterator &other) const noexcept { | ||||
|         return !(*this == other); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     const std::vector<Set *> *pools; | ||||
|     const std::vector<Set *> *filter; | ||||
|     iterator_type it; | ||||
|     bool tombstone_check; | ||||
| }; | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief Generic runtime view. | ||||
|  * | ||||
|  * Runtime views iterate over those entities that have at least all the given | ||||
|  * components in their bags. During initialization, a runtime view looks at the | ||||
|  * number of entities available for each component and picks up a reference to | ||||
|  * the smallest set of candidate entities in order to get a performance boost | ||||
|  * when iterate.<br/> | ||||
|  * Order of elements during iterations are highly dependent on the order of the | ||||
|  * underlying data structures. See sparse_set and its specializations for more | ||||
|  * details. | ||||
|  * | ||||
|  * @b Important | ||||
|  * | ||||
|  * Iterators aren't invalidated if: | ||||
|  * | ||||
|  * * New instances of the given components are created and assigned to entities. | ||||
|  * * The entity currently pointed is modified (as an example, if one of the | ||||
|  *   given components is removed from the entity to which the iterator points). | ||||
|  * * The entity currently pointed is destroyed. | ||||
|  * | ||||
|  * In all the other cases, modifying the pools of the given components in any | ||||
|  * way invalidates all the iterators and using them results in undefined | ||||
|  * behavior. | ||||
|  * | ||||
|  * @note | ||||
|  * Views share references to the underlying data structures of the registry that | ||||
|  * generated them. Therefore any change to the entities and to the components | ||||
|  * made by means of the registry are immediately reflected by the views, unless | ||||
|  * a pool was missing when the view was built (in this case, the view won't | ||||
|  * have a valid reference and won't be updated accordingly). | ||||
|  * | ||||
|  * @warning | ||||
|  * Lifetime of a view must not overcome that of the registry that generated it. | ||||
|  * In any other case, attempting to use a view results in undefined behavior. | ||||
|  * | ||||
|  * @tparam Type Common base type. | ||||
|  * @tparam Allocator Type of allocator used to manage memory and elements. | ||||
|  */ | ||||
| template<typename Type, typename Allocator> | ||||
| class basic_runtime_view { | ||||
|     using alloc_traits = std::allocator_traits<Allocator>; | ||||
|     static_assert(std::is_same_v<typename alloc_traits::value_type, Type *>, "Invalid value type"); | ||||
|     using container_type = std::vector<Type *, Allocator>; | ||||
|  | ||||
| public: | ||||
|     /*! @brief Allocator type. */ | ||||
|     using allocator_type = Allocator; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = typename Type::entity_type; | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using size_type = std::size_t; | ||||
|     /*! @brief Common type among all storage types. */ | ||||
|     using base_type = Type; | ||||
|     /*! @brief Bidirectional iterator type. */ | ||||
|     using iterator = internal::runtime_view_iterator<base_type>; | ||||
|  | ||||
|     /*! @brief Default constructor to use to create empty, invalid views. */ | ||||
|     basic_runtime_view() noexcept | ||||
|         : basic_runtime_view{allocator_type{}} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an empty, invalid view with a given allocator. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     explicit basic_runtime_view(const allocator_type &allocator) | ||||
|         : pools{allocator}, | ||||
|           filter{allocator} {} | ||||
|  | ||||
|     /*! @brief Default copy constructor. */ | ||||
|     basic_runtime_view(const basic_runtime_view &) = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Allocator-extended copy constructor. | ||||
|      * @param other The instance to copy from. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     basic_runtime_view(const basic_runtime_view &other, const allocator_type &allocator) | ||||
|         : pools{other.pools, allocator}, | ||||
|           filter{other.filter, allocator} {} | ||||
|  | ||||
|     /*! @brief Default move constructor. */ | ||||
|     basic_runtime_view(basic_runtime_view &&) noexcept(std::is_nothrow_move_constructible_v<container_type>) = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Allocator-extended move constructor. | ||||
|      * @param other The instance to move from. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     basic_runtime_view(basic_runtime_view &&other, const allocator_type &allocator) | ||||
|         : pools{std::move(other.pools), allocator}, | ||||
|           filter{std::move(other.filter), allocator} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Default copy assignment operator. | ||||
|      * @return This container. | ||||
|      */ | ||||
|     basic_runtime_view &operator=(const basic_runtime_view &) = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Default move assignment operator. | ||||
|      * @return This container. | ||||
|      */ | ||||
|     basic_runtime_view &operator=(basic_runtime_view &&) noexcept(std::is_nothrow_move_assignable_v<container_type>) = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Exchanges the contents with those of a given view. | ||||
|      * @param other View to exchange the content with. | ||||
|      */ | ||||
|     void swap(basic_runtime_view &other) { | ||||
|         using std::swap; | ||||
|         swap(pools, other.pools); | ||||
|         swap(filter, other.filter); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the associated allocator. | ||||
|      * @return The associated allocator. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { | ||||
|         return pools.get_allocator(); | ||||
|     } | ||||
|  | ||||
|     /*! @brief Clears the view. */ | ||||
|     void clear() { | ||||
|         pools.clear(); | ||||
|         filter.clear(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Appends an opaque storage object to a runtime view. | ||||
|      * @param base An opaque reference to a storage object. | ||||
|      * @return This runtime view. | ||||
|      */ | ||||
|     basic_runtime_view &iterate(base_type &base) { | ||||
|         if(pools.empty() || !(base.size() < pools[0u]->size())) { | ||||
|             pools.push_back(&base); | ||||
|         } else { | ||||
|             pools.push_back(std::exchange(pools[0u], &base)); | ||||
|         } | ||||
|  | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Adds an opaque storage object as a filter of a runtime view. | ||||
|      * @param base An opaque reference to a storage object. | ||||
|      * @return This runtime view. | ||||
|      */ | ||||
|     basic_runtime_view &exclude(base_type &base) { | ||||
|         filter.push_back(&base); | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Estimates the number of entities iterated by the view. | ||||
|      * @return Estimated number of entities iterated by the view. | ||||
|      */ | ||||
|     [[nodiscard]] size_type size_hint() const { | ||||
|         return pools.empty() ? size_type{} : pools.front()->size(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the first entity that has the given | ||||
|      * components. | ||||
|      * | ||||
|      * The returned iterator points to the first entity that has the given | ||||
|      * components. If the view is empty, the returned iterator will be equal to | ||||
|      * `end()`. | ||||
|      * | ||||
|      * @return An iterator to the first entity that has the given components. | ||||
|      */ | ||||
|     [[nodiscard]] iterator begin() const { | ||||
|         return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->begin()}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator that is past the last entity that has the | ||||
|      * given components. | ||||
|      * | ||||
|      * The returned iterator points to the entity following the last entity that | ||||
|      * has the given components. Attempting to dereference the returned iterator | ||||
|      * results in undefined behavior. | ||||
|      * | ||||
|      * @return An iterator to the entity following the last entity that has the | ||||
|      * given components. | ||||
|      */ | ||||
|     [[nodiscard]] iterator end() const { | ||||
|         return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->end()}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if a view contains an entity. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return True if the view contains the given entity, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool contains(const entity_type entt) const { | ||||
|         return !pools.empty() | ||||
|                && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); }) | ||||
|                && std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); }); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Iterates entities and applies the given function object to them. | ||||
|      * | ||||
|      * The function object is invoked for each entity. It is provided only with | ||||
|      * the entity itself. To get the components, users can use the registry with | ||||
|      * which the view was built.<br/> | ||||
|      * The signature of the function should be equivalent to the following: | ||||
|      * | ||||
|      * @code{.cpp} | ||||
|      * void(const entity_type); | ||||
|      * @endcode | ||||
|      * | ||||
|      * @tparam Func Type of the function object to invoke. | ||||
|      * @param func A valid function object. | ||||
|      */ | ||||
|     template<typename Func> | ||||
|     void each(Func func) const { | ||||
|         for(const auto entity: *this) { | ||||
|             func(entity); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     container_type pools; | ||||
|     container_type filter; | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										567
									
								
								external/entt/entt/src/entt/entity/snapshot.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										567
									
								
								external/entt/entt/src/entt/entity/snapshot.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,567 @@ | ||||
| #ifndef ENTT_ENTITY_SNAPSHOT_HPP | ||||
| #define ENTT_ENTITY_SNAPSHOT_HPP | ||||
|  | ||||
| #include <array> | ||||
| #include <cstddef> | ||||
| #include <iterator> | ||||
| #include <tuple> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include "../config/config.h" | ||||
| #include "../container/dense_map.hpp" | ||||
| #include "../core/type_traits.hpp" | ||||
| #include "component.hpp" | ||||
| #include "entity.hpp" | ||||
| #include "fwd.hpp" | ||||
| #include "view.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @brief Utility class to create snapshots from a registry. | ||||
|  * | ||||
|  * A _snapshot_ can be either a dump of the entire registry or a narrower | ||||
|  * selection of components of interest.<br/> | ||||
|  * This type can be used in both cases if provided with a correctly configured | ||||
|  * output archive. | ||||
|  * | ||||
|  * @tparam Registry Basic registry type. | ||||
|  */ | ||||
| template<typename Registry> | ||||
| class basic_snapshot { | ||||
|     using entity_traits = entt_traits<typename Registry::entity_type>; | ||||
|  | ||||
|     template<typename Component, typename Archive, typename It> | ||||
|     void get(Archive &archive, std::size_t sz, It first, It last) const { | ||||
|         const auto view = reg->template view<const Component>(); | ||||
|         archive(typename entity_traits::entity_type(sz)); | ||||
|  | ||||
|         while(first != last) { | ||||
|             const auto entt = *(first++); | ||||
|  | ||||
|             if(reg->template all_of<Component>(entt)) { | ||||
|                 std::apply(archive, std::tuple_cat(std::make_tuple(entt), view.get(entt))); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template<typename... Component, typename Archive, typename It, std::size_t... Index> | ||||
|     void component(Archive &archive, It first, It last, std::index_sequence<Index...>) const { | ||||
|         std::array<std::size_t, sizeof...(Index)> size{}; | ||||
|         auto begin = first; | ||||
|  | ||||
|         while(begin != last) { | ||||
|             const auto entt = *(begin++); | ||||
|             ((reg->template all_of<Component>(entt) ? ++size[Index] : 0u), ...); | ||||
|         } | ||||
|  | ||||
|         (get<Component>(archive, size[Index], first, last), ...); | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! Basic registry type. */ | ||||
|     using registry_type = Registry; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = typename registry_type::entity_type; | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an instance that is bound to a given registry. | ||||
|      * @param source A valid reference to a registry. | ||||
|      */ | ||||
|     basic_snapshot(const registry_type &source) noexcept | ||||
|         : reg{&source} {} | ||||
|  | ||||
|     /*! @brief Default move constructor. */ | ||||
|     basic_snapshot(basic_snapshot &&) noexcept = default; | ||||
|  | ||||
|     /*! @brief Default move assignment operator. @return This snapshot. */ | ||||
|     basic_snapshot &operator=(basic_snapshot &&) noexcept = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Puts aside all the entities from the underlying registry. | ||||
|      * | ||||
|      * Entities are serialized along with their versions. Destroyed entities are | ||||
|      * taken in consideration as well by this function. | ||||
|      * | ||||
|      * @tparam Archive Type of output archive. | ||||
|      * @param archive A valid reference to an output archive. | ||||
|      * @return An object of this type to continue creating the snapshot. | ||||
|      */ | ||||
|     template<typename Archive> | ||||
|     const basic_snapshot &entities(Archive &archive) const { | ||||
|         const auto sz = reg->size(); | ||||
|  | ||||
|         archive(typename entity_traits::entity_type(sz + 1u)); | ||||
|         archive(reg->released()); | ||||
|  | ||||
|         for(auto first = reg->data(), last = first + sz; first != last; ++first) { | ||||
|             archive(*first); | ||||
|         } | ||||
|  | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Puts aside the given components. | ||||
|      * | ||||
|      * Each instance is serialized together with the entity to which it belongs. | ||||
|      * Entities are serialized along with their versions. | ||||
|      * | ||||
|      * @tparam Component Types of components to serialize. | ||||
|      * @tparam Archive Type of output archive. | ||||
|      * @param archive A valid reference to an output archive. | ||||
|      * @return An object of this type to continue creating the snapshot. | ||||
|      */ | ||||
|     template<typename... Component, typename Archive> | ||||
|     const basic_snapshot &component(Archive &archive) const { | ||||
|         if constexpr(sizeof...(Component) == 1u) { | ||||
|             const auto view = reg->template view<const Component...>(); | ||||
|             (component<Component>(archive, view.rbegin(), view.rend()), ...); | ||||
|             return *this; | ||||
|         } else { | ||||
|             (component<Component>(archive), ...); | ||||
|             return *this; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Puts aside the given components for the entities in a range. | ||||
|      * | ||||
|      * Each instance is serialized together with the entity to which it belongs. | ||||
|      * Entities are serialized along with their versions. | ||||
|      * | ||||
|      * @tparam Component Types of components to serialize. | ||||
|      * @tparam Archive Type of output archive. | ||||
|      * @tparam It Type of input iterator. | ||||
|      * @param archive A valid reference to an output archive. | ||||
|      * @param first An iterator to the first element of the range to serialize. | ||||
|      * @param last An iterator past the last element of the range to serialize. | ||||
|      * @return An object of this type to continue creating the snapshot. | ||||
|      */ | ||||
|     template<typename... Component, typename Archive, typename It> | ||||
|     const basic_snapshot &component(Archive &archive, It first, It last) const { | ||||
|         component<Component...>(archive, first, last, std::index_sequence_for<Component...>{}); | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     const registry_type *reg; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Utility class to restore a snapshot as a whole. | ||||
|  * | ||||
|  * A snapshot loader requires that the destination registry be empty and loads | ||||
|  * all the data at once while keeping intact the identifiers that the entities | ||||
|  * originally had.<br/> | ||||
|  * An example of use is the implementation of a save/restore utility. | ||||
|  * | ||||
|  * @tparam Registry Basic registry type. | ||||
|  */ | ||||
| template<typename Registry> | ||||
| class basic_snapshot_loader { | ||||
|     using entity_traits = entt_traits<typename Registry::entity_type>; | ||||
|  | ||||
|     template<typename Component, typename Archive> | ||||
|     void assign(Archive &archive) const { | ||||
|         typename entity_traits::entity_type length{}; | ||||
|         entity_type entt; | ||||
|  | ||||
|         archive(length); | ||||
|  | ||||
|         if constexpr(ignore_as_empty_v<Component>) { | ||||
|             while(length--) { | ||||
|                 archive(entt); | ||||
|                 const auto entity = reg->valid(entt) ? entt : reg->create(entt); | ||||
|                 ENTT_ASSERT(entity == entt, "Entity not available for use"); | ||||
|                 reg->template emplace<Component>(entt); | ||||
|             } | ||||
|         } else { | ||||
|             Component instance; | ||||
|  | ||||
|             while(length--) { | ||||
|                 archive(entt, instance); | ||||
|                 const auto entity = reg->valid(entt) ? entt : reg->create(entt); | ||||
|                 ENTT_ASSERT(entity == entt, "Entity not available for use"); | ||||
|                 reg->template emplace<Component>(entt, std::move(instance)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! Basic registry type. */ | ||||
|     using registry_type = Registry; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = typename registry_type::entity_type; | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an instance that is bound to a given registry. | ||||
|      * @param source A valid reference to a registry. | ||||
|      */ | ||||
|     basic_snapshot_loader(registry_type &source) noexcept | ||||
|         : reg{&source} { | ||||
|         // restoring a snapshot as a whole requires a clean registry | ||||
|         ENTT_ASSERT(reg->empty(), "Registry must be empty"); | ||||
|     } | ||||
|  | ||||
|     /*! @brief Default move constructor. */ | ||||
|     basic_snapshot_loader(basic_snapshot_loader &&) noexcept = default; | ||||
|  | ||||
|     /*! @brief Default move assignment operator. @return This loader. */ | ||||
|     basic_snapshot_loader &operator=(basic_snapshot_loader &&) noexcept = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Restores entities that were in use during serialization. | ||||
|      * | ||||
|      * This function restores the entities that were in use during serialization | ||||
|      * and gives them the versions they originally had. | ||||
|      * | ||||
|      * @tparam Archive Type of input archive. | ||||
|      * @param archive A valid reference to an input archive. | ||||
|      * @return A valid loader to continue restoring data. | ||||
|      */ | ||||
|     template<typename Archive> | ||||
|     const basic_snapshot_loader &entities(Archive &archive) const { | ||||
|         typename entity_traits::entity_type length{}; | ||||
|  | ||||
|         archive(length); | ||||
|         std::vector<entity_type> all(length); | ||||
|  | ||||
|         for(std::size_t pos{}; pos < length; ++pos) { | ||||
|             archive(all[pos]); | ||||
|         } | ||||
|  | ||||
|         reg->assign(++all.cbegin(), all.cend(), all[0u]); | ||||
|  | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Restores components and assigns them to the right entities. | ||||
|      * | ||||
|      * The template parameter list must be exactly the same used during | ||||
|      * serialization. In the event that the entity to which the component is | ||||
|      * assigned doesn't exist yet, the loader will take care to create it with | ||||
|      * the version it originally had. | ||||
|      * | ||||
|      * @tparam Component Types of components to restore. | ||||
|      * @tparam Archive Type of input archive. | ||||
|      * @param archive A valid reference to an input archive. | ||||
|      * @return A valid loader to continue restoring data. | ||||
|      */ | ||||
|     template<typename... Component, typename Archive> | ||||
|     const basic_snapshot_loader &component(Archive &archive) const { | ||||
|         (assign<Component>(archive), ...); | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Destroys those entities that have no components. | ||||
|      * | ||||
|      * In case all the entities were serialized but only part of the components | ||||
|      * was saved, it could happen that some of the entities have no components | ||||
|      * once restored.<br/> | ||||
|      * This functions helps to identify and destroy those entities. | ||||
|      * | ||||
|      * @return A valid loader to continue restoring data. | ||||
|      */ | ||||
|     const basic_snapshot_loader &orphans() const { | ||||
|         reg->each([this](const auto entt) { | ||||
|             if(reg->orphan(entt)) { | ||||
|                 reg->release(entt); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     registry_type *reg; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Utility class for _continuous loading_. | ||||
|  * | ||||
|  * A _continuous loader_ is designed to load data from a source registry to a | ||||
|  * (possibly) non-empty destination. The loader can accommodate in a registry | ||||
|  * more than one snapshot in a sort of _continuous loading_ that updates the | ||||
|  * destination one step at a time.<br/> | ||||
|  * Identifiers that entities originally had are not transferred to the target. | ||||
|  * Instead, the loader maps remote identifiers to local ones while restoring a | ||||
|  * snapshot.<br/> | ||||
|  * An example of use is the implementation of a client-server applications with | ||||
|  * the requirement of transferring somehow parts of the representation side to | ||||
|  * side. | ||||
|  * | ||||
|  * @tparam Registry Basic registry type. | ||||
|  */ | ||||
| template<typename Registry> | ||||
| class basic_continuous_loader { | ||||
|     using entity_traits = entt_traits<typename Registry::entity_type>; | ||||
|  | ||||
|     void destroy(typename Registry::entity_type entt) { | ||||
|         if(const auto it = remloc.find(entt); it == remloc.cend()) { | ||||
|             const auto local = reg->create(); | ||||
|             remloc.emplace(entt, std::make_pair(local, true)); | ||||
|             reg->destroy(local); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void restore(typename Registry::entity_type entt) { | ||||
|         const auto it = remloc.find(entt); | ||||
|  | ||||
|         if(it == remloc.cend()) { | ||||
|             const auto local = reg->create(); | ||||
|             remloc.emplace(entt, std::make_pair(local, true)); | ||||
|         } else { | ||||
|             if(!reg->valid(remloc[entt].first)) { | ||||
|                 remloc[entt].first = reg->create(); | ||||
|             } | ||||
|  | ||||
|             // set the dirty flag | ||||
|             remloc[entt].second = true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template<typename Container> | ||||
|     auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) { | ||||
|         // map like container | ||||
|         Container other; | ||||
|  | ||||
|         for(auto &&pair: container) { | ||||
|             using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>; | ||||
|             using second_type = typename std::decay_t<decltype(pair)>::second_type; | ||||
|  | ||||
|             if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) { | ||||
|                 other.emplace(map(pair.first), map(pair.second)); | ||||
|             } else if constexpr(std::is_same_v<first_type, entity_type>) { | ||||
|                 other.emplace(map(pair.first), std::move(pair.second)); | ||||
|             } else { | ||||
|                 static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type"); | ||||
|                 other.emplace(std::move(pair.first), map(pair.second)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         using std::swap; | ||||
|         swap(container, other); | ||||
|     } | ||||
|  | ||||
|     template<typename Container> | ||||
|     auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) { | ||||
|         // vector like container | ||||
|         static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type"); | ||||
|  | ||||
|         for(auto &&entt: container) { | ||||
|             entt = map(entt); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template<typename Component, typename Other, typename Member> | ||||
|     void update([[maybe_unused]] Component &instance, [[maybe_unused]] Member Other::*member) { | ||||
|         if constexpr(!std::is_same_v<Component, Other>) { | ||||
|             return; | ||||
|         } else if constexpr(std::is_same_v<Member, entity_type>) { | ||||
|             instance.*member = map(instance.*member); | ||||
|         } else { | ||||
|             // maybe a container? let's try... | ||||
|             update(0, instance.*member); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template<typename Component> | ||||
|     void remove_if_exists() { | ||||
|         for(auto &&ref: remloc) { | ||||
|             const auto local = ref.second.first; | ||||
|  | ||||
|             if(reg->valid(local)) { | ||||
|                 reg->template remove<Component>(local); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template<typename Component, typename Archive, typename... Other, typename... Member> | ||||
|     void assign(Archive &archive, [[maybe_unused]] Member Other::*...member) { | ||||
|         typename entity_traits::entity_type length{}; | ||||
|         entity_type entt; | ||||
|  | ||||
|         archive(length); | ||||
|  | ||||
|         if constexpr(ignore_as_empty_v<Component>) { | ||||
|             while(length--) { | ||||
|                 archive(entt); | ||||
|                 restore(entt); | ||||
|                 reg->template emplace_or_replace<Component>(map(entt)); | ||||
|             } | ||||
|         } else { | ||||
|             Component instance; | ||||
|  | ||||
|             while(length--) { | ||||
|                 archive(entt, instance); | ||||
|                 (update(instance, member), ...); | ||||
|                 restore(entt); | ||||
|                 reg->template emplace_or_replace<Component>(map(entt), std::move(instance)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! Basic registry type. */ | ||||
|     using registry_type = Registry; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = typename registry_type::entity_type; | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an instance that is bound to a given registry. | ||||
|      * @param source A valid reference to a registry. | ||||
|      */ | ||||
|     basic_continuous_loader(registry_type &source) noexcept | ||||
|         : reg{&source} {} | ||||
|  | ||||
|     /*! @brief Default move constructor. */ | ||||
|     basic_continuous_loader(basic_continuous_loader &&) = default; | ||||
|  | ||||
|     /*! @brief Default move assignment operator. @return This loader. */ | ||||
|     basic_continuous_loader &operator=(basic_continuous_loader &&) = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Restores entities that were in use during serialization. | ||||
|      * | ||||
|      * This function restores the entities that were in use during serialization | ||||
|      * and creates local counterparts for them if required. | ||||
|      * | ||||
|      * @tparam Archive Type of input archive. | ||||
|      * @param archive A valid reference to an input archive. | ||||
|      * @return A non-const reference to this loader. | ||||
|      */ | ||||
|     template<typename Archive> | ||||
|     basic_continuous_loader &entities(Archive &archive) { | ||||
|         typename entity_traits::entity_type length{}; | ||||
|         entity_type entt{}; | ||||
|  | ||||
|         archive(length); | ||||
|         // discards the head of the list of destroyed entities | ||||
|         archive(entt); | ||||
|  | ||||
|         for(std::size_t pos{}, last = length - 1u; pos < last; ++pos) { | ||||
|             archive(entt); | ||||
|  | ||||
|             if(const auto entity = entity_traits::to_entity(entt); entity == pos) { | ||||
|                 restore(entt); | ||||
|             } else { | ||||
|                 destroy(entt); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Restores components and assigns them to the right entities. | ||||
|      * | ||||
|      * The template parameter list must be exactly the same used during | ||||
|      * serialization. In the event that the entity to which the component is | ||||
|      * assigned doesn't exist yet, the loader will take care to create a local | ||||
|      * counterpart for it.<br/> | ||||
|      * Members can be either data members of type entity_type or containers of | ||||
|      * entities. In both cases, the loader will visit them and update the | ||||
|      * entities by replacing each one with its local counterpart. | ||||
|      * | ||||
|      * @tparam Component Type of component to restore. | ||||
|      * @tparam Archive Type of input archive. | ||||
|      * @tparam Other Types of components to update with local counterparts. | ||||
|      * @tparam Member Types of members to update with their local counterparts. | ||||
|      * @param archive A valid reference to an input archive. | ||||
|      * @param member Members to update with their local counterparts. | ||||
|      * @return A non-const reference to this loader. | ||||
|      */ | ||||
|     template<typename... Component, typename Archive, typename... Other, typename... Member> | ||||
|     basic_continuous_loader &component(Archive &archive, Member Other::*...member) { | ||||
|         (remove_if_exists<Component>(), ...); | ||||
|         (assign<Component>(archive, member...), ...); | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Helps to purge entities that no longer have a conterpart. | ||||
|      * | ||||
|      * Users should invoke this member function after restoring each snapshot, | ||||
|      * unless they know exactly what they are doing. | ||||
|      * | ||||
|      * @return A non-const reference to this loader. | ||||
|      */ | ||||
|     basic_continuous_loader &shrink() { | ||||
|         auto it = remloc.begin(); | ||||
|  | ||||
|         while(it != remloc.cend()) { | ||||
|             const auto local = it->second.first; | ||||
|             bool &dirty = it->second.second; | ||||
|  | ||||
|             if(dirty) { | ||||
|                 dirty = false; | ||||
|                 ++it; | ||||
|             } else { | ||||
|                 if(reg->valid(local)) { | ||||
|                     reg->destroy(local); | ||||
|                 } | ||||
|  | ||||
|                 it = remloc.erase(it); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Destroys those entities that have no components. | ||||
|      * | ||||
|      * In case all the entities were serialized but only part of the components | ||||
|      * was saved, it could happen that some of the entities have no components | ||||
|      * once restored.<br/> | ||||
|      * This functions helps to identify and destroy those entities. | ||||
|      * | ||||
|      * @return A non-const reference to this loader. | ||||
|      */ | ||||
|     basic_continuous_loader &orphans() { | ||||
|         reg->each([this](const auto entt) { | ||||
|             if(reg->orphan(entt)) { | ||||
|                 reg->release(entt); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Tests if a loader knows about a given entity. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return True if `entity` is managed by the loader, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool contains(entity_type entt) const noexcept { | ||||
|         return (remloc.find(entt) != remloc.cend()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the identifier to which an entity refers. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return The local identifier if any, the null entity otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] entity_type map(entity_type entt) const noexcept { | ||||
|         const auto it = remloc.find(entt); | ||||
|         entity_type other = null; | ||||
|  | ||||
|         if(it != remloc.cend()) { | ||||
|             other = it->second.first; | ||||
|         } | ||||
|  | ||||
|         return other; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     dense_map<entity_type, std::pair<entity_type, bool>> remloc; | ||||
|     registry_type *reg; | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										976
									
								
								external/entt/entt/src/entt/entity/sparse_set.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										976
									
								
								external/entt/entt/src/entt/entity/sparse_set.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,976 @@ | ||||
| #ifndef ENTT_ENTITY_SPARSE_SET_HPP | ||||
| #define ENTT_ENTITY_SPARSE_SET_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <iterator> | ||||
| #include <memory> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include "../config/config.h" | ||||
| #include "../core/algorithm.hpp" | ||||
| #include "../core/any.hpp" | ||||
| #include "../core/memory.hpp" | ||||
| #include "../core/type_info.hpp" | ||||
| #include "entity.hpp" | ||||
| #include "fwd.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename Container> | ||||
| struct sparse_set_iterator final { | ||||
|     using value_type = typename Container::value_type; | ||||
|     using pointer = typename Container::const_pointer; | ||||
|     using reference = typename Container::const_reference; | ||||
|     using difference_type = typename Container::difference_type; | ||||
|     using iterator_category = std::random_access_iterator_tag; | ||||
|  | ||||
|     constexpr sparse_set_iterator() noexcept | ||||
|         : packed{}, | ||||
|           offset{} {} | ||||
|  | ||||
|     constexpr sparse_set_iterator(const Container &ref, const difference_type idx) noexcept | ||||
|         : packed{std::addressof(ref)}, | ||||
|           offset{idx} {} | ||||
|  | ||||
|     constexpr sparse_set_iterator &operator++() noexcept { | ||||
|         return --offset, *this; | ||||
|     } | ||||
|  | ||||
|     constexpr sparse_set_iterator operator++(int) noexcept { | ||||
|         sparse_set_iterator orig = *this; | ||||
|         return ++(*this), orig; | ||||
|     } | ||||
|  | ||||
|     constexpr sparse_set_iterator &operator--() noexcept { | ||||
|         return ++offset, *this; | ||||
|     } | ||||
|  | ||||
|     constexpr sparse_set_iterator operator--(int) noexcept { | ||||
|         sparse_set_iterator orig = *this; | ||||
|         return operator--(), orig; | ||||
|     } | ||||
|  | ||||
|     constexpr sparse_set_iterator &operator+=(const difference_type value) noexcept { | ||||
|         offset -= value; | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     constexpr sparse_set_iterator operator+(const difference_type value) const noexcept { | ||||
|         sparse_set_iterator copy = *this; | ||||
|         return (copy += value); | ||||
|     } | ||||
|  | ||||
|     constexpr sparse_set_iterator &operator-=(const difference_type value) noexcept { | ||||
|         return (*this += -value); | ||||
|     } | ||||
|  | ||||
|     constexpr sparse_set_iterator operator-(const difference_type value) const noexcept { | ||||
|         return (*this + -value); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { | ||||
|         return packed->data()[index() - value]; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr pointer operator->() const noexcept { | ||||
|         return packed->data() + index(); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr reference operator*() const noexcept { | ||||
|         return *operator->(); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr difference_type index() const noexcept { | ||||
|         return offset - 1; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     const Container *packed; | ||||
|     difference_type offset; | ||||
| }; | ||||
|  | ||||
| template<typename Type, typename Other> | ||||
| [[nodiscard]] constexpr std::ptrdiff_t operator-(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) noexcept { | ||||
|     return rhs.index() - lhs.index(); | ||||
| } | ||||
|  | ||||
| template<typename Type, typename Other> | ||||
| [[nodiscard]] constexpr bool operator==(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) noexcept { | ||||
|     return lhs.index() == rhs.index(); | ||||
| } | ||||
|  | ||||
| template<typename Type, typename Other> | ||||
| [[nodiscard]] constexpr bool operator!=(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) noexcept { | ||||
|     return !(lhs == rhs); | ||||
| } | ||||
|  | ||||
| template<typename Type, typename Other> | ||||
| [[nodiscard]] constexpr bool operator<(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) noexcept { | ||||
|     return lhs.index() > rhs.index(); | ||||
| } | ||||
|  | ||||
| template<typename Type, typename Other> | ||||
| [[nodiscard]] constexpr bool operator>(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) noexcept { | ||||
|     return lhs.index() < rhs.index(); | ||||
| } | ||||
|  | ||||
| template<typename Type, typename Other> | ||||
| [[nodiscard]] constexpr bool operator<=(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) noexcept { | ||||
|     return !(lhs > rhs); | ||||
| } | ||||
|  | ||||
| template<typename Type, typename Other> | ||||
| [[nodiscard]] constexpr bool operator>=(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) noexcept { | ||||
|     return !(lhs < rhs); | ||||
| } | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /*! @brief Sparse set deletion policy. */ | ||||
| enum class deletion_policy : std::uint8_t { | ||||
|     /*! @brief Swap-and-pop deletion policy. */ | ||||
|     swap_and_pop = 0u, | ||||
|     /*! @brief In-place deletion policy. */ | ||||
|     in_place = 1u | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Basic sparse set implementation. | ||||
|  * | ||||
|  * Sparse set or packed array or whatever is the name users give it.<br/> | ||||
|  * Two arrays: an _external_ one and an _internal_ one; a _sparse_ one and a | ||||
|  * _packed_ one; one used for direct access through contiguous memory, the other | ||||
|  * one used to get the data through an extra level of indirection.<br/> | ||||
|  * This is largely used by the registry to offer users the fastest access ever | ||||
|  * to the components. Views and groups in general are almost entirely designed | ||||
|  * around sparse sets. | ||||
|  * | ||||
|  * This type of data structure is widely documented in the literature and on the | ||||
|  * web. This is nothing more than a customized implementation suitable for the | ||||
|  * purpose of the framework. | ||||
|  * | ||||
|  * @note | ||||
|  * Internal data structures arrange elements to maximize performance. There are | ||||
|  * no guarantees that entities are returned in the insertion order when iterate | ||||
|  * a sparse set. Do not make assumption on the order in any case. | ||||
|  * | ||||
|  * @tparam Entity A valid entity type (see entt_traits for more details). | ||||
|  * @tparam Allocator Type of allocator used to manage memory and elements. | ||||
|  */ | ||||
| template<typename Entity, typename Allocator> | ||||
| class basic_sparse_set { | ||||
|     using alloc_traits = std::allocator_traits<Allocator>; | ||||
|     static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type"); | ||||
|     using sparse_container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>; | ||||
|     using packed_container_type = std::vector<Entity, Allocator>; | ||||
|     using entity_traits = entt_traits<Entity>; | ||||
|  | ||||
|     [[nodiscard]] auto sparse_ptr(const Entity entt) const { | ||||
|         const auto pos = static_cast<size_type>(entity_traits::to_entity(entt)); | ||||
|         const auto page = pos / entity_traits::page_size; | ||||
|         return (page < sparse.size() && sparse[page]) ? (sparse[page] + fast_mod(pos, entity_traits::page_size)) : nullptr; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] auto &sparse_ref(const Entity entt) const { | ||||
|         ENTT_ASSERT(sparse_ptr(entt), "Invalid element"); | ||||
|         const auto pos = static_cast<size_type>(entity_traits::to_entity(entt)); | ||||
|         return sparse[pos / entity_traits::page_size][fast_mod(pos, entity_traits::page_size)]; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] auto &assure_at_least(const Entity entt) { | ||||
|         const auto pos = static_cast<size_type>(entity_traits::to_entity(entt)); | ||||
|         const auto page = pos / entity_traits::page_size; | ||||
|  | ||||
|         if(!(page < sparse.size())) { | ||||
|             sparse.resize(page + 1u, nullptr); | ||||
|         } | ||||
|  | ||||
|         if(!sparse[page]) { | ||||
|             auto page_allocator{packed.get_allocator()}; | ||||
|             sparse[page] = alloc_traits::allocate(page_allocator, entity_traits::page_size); | ||||
|             std::uninitialized_fill(sparse[page], sparse[page] + entity_traits::page_size, null); | ||||
|         } | ||||
|  | ||||
|         auto &elem = sparse[page][fast_mod(pos, entity_traits::page_size)]; | ||||
|         ENTT_ASSERT(elem == null, "Slot not available"); | ||||
|         return elem; | ||||
|     } | ||||
|  | ||||
|     void release_sparse_pages() { | ||||
|         auto page_allocator{packed.get_allocator()}; | ||||
|  | ||||
|         for(auto &&page: sparse) { | ||||
|             if(page != nullptr) { | ||||
|                 std::destroy(page, page + entity_traits::page_size); | ||||
|                 alloc_traits::deallocate(page_allocator, page, entity_traits::page_size); | ||||
|                 page = nullptr; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     virtual const void *get_at(const std::size_t) const { | ||||
|         return nullptr; | ||||
|     } | ||||
|  | ||||
|     virtual void swap_at(const std::size_t, const std::size_t) {} | ||||
|     virtual void move_element(const std::size_t, const std::size_t) {} | ||||
|  | ||||
| protected: | ||||
|     /*! @brief Random access iterator type. */ | ||||
|     using basic_iterator = internal::sparse_set_iterator<packed_container_type>; | ||||
|  | ||||
|     /** | ||||
|      * @brief Erases an entity from a sparse set. | ||||
|      * @param it An iterator to the element to pop. | ||||
|      */ | ||||
|     void swap_and_pop(const basic_iterator it) { | ||||
|         ENTT_ASSERT(mode == deletion_policy::swap_and_pop, "Deletion policy mismatched"); | ||||
|         auto &self = sparse_ref(*it); | ||||
|         const auto entt = entity_traits::to_entity(self); | ||||
|         sparse_ref(packed.back()) = entity_traits::combine(entt, entity_traits::to_integral(packed.back())); | ||||
|         packed[static_cast<size_type>(entt)] = packed.back(); | ||||
|         // unnecessary but it helps to detect nasty bugs | ||||
|         ENTT_ASSERT((packed.back() = null, true), ""); | ||||
|         // lazy self-assignment guard | ||||
|         self = null; | ||||
|         packed.pop_back(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Erases an entity from a sparse set. | ||||
|      * @param it An iterator to the element to pop. | ||||
|      */ | ||||
|     void in_place_pop(const basic_iterator it) { | ||||
|         ENTT_ASSERT(mode == deletion_policy::in_place, "Deletion policy mismatched"); | ||||
|         const auto entt = entity_traits::to_entity(std::exchange(sparse_ref(*it), null)); | ||||
|         packed[static_cast<size_type>(entt)] = std::exchange(free_list, entity_traits::combine(entt, entity_traits::reserved)); | ||||
|     } | ||||
|  | ||||
| protected: | ||||
|     /** | ||||
|      * @brief Erases entities from a sparse set. | ||||
|      * @param first An iterator to the first element of the range of entities. | ||||
|      * @param last An iterator past the last element of the range of entities. | ||||
|      */ | ||||
|     virtual void pop(basic_iterator first, basic_iterator last) { | ||||
|         if(mode == deletion_policy::swap_and_pop) { | ||||
|             for(; first != last; ++first) { | ||||
|                 swap_and_pop(first); | ||||
|             } | ||||
|         } else { | ||||
|             for(; first != last; ++first) { | ||||
|                 in_place_pop(first); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns an entity to a sparse set. | ||||
|      * @param entt A valid identifier. | ||||
|      * @param force_back Force back insertion. | ||||
|      * @return Iterator pointing to the emplaced element. | ||||
|      */ | ||||
|     virtual basic_iterator try_emplace(const Entity entt, const bool force_back, const void * = nullptr) { | ||||
|         ENTT_ASSERT(!contains(entt), "Set already contains entity"); | ||||
|  | ||||
|         if(auto &elem = assure_at_least(entt); free_list == null || force_back) { | ||||
|             packed.push_back(entt); | ||||
|             elem = entity_traits::combine(static_cast<typename entity_traits::entity_type>(packed.size() - 1u), entity_traits::to_integral(entt)); | ||||
|             return begin(); | ||||
|         } else { | ||||
|             const auto pos = static_cast<size_type>(entity_traits::to_entity(free_list)); | ||||
|             elem = entity_traits::combine(entity_traits::to_integral(free_list), entity_traits::to_integral(entt)); | ||||
|             free_list = std::exchange(packed[pos], entt); | ||||
|             return --(end() - pos); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! @brief Allocator type. */ | ||||
|     using allocator_type = Allocator; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = typename entity_traits::value_type; | ||||
|     /*! @brief Underlying version type. */ | ||||
|     using version_type = typename entity_traits::version_type; | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using size_type = std::size_t; | ||||
|     /*! @brief Pointer type to contained entities. */ | ||||
|     using pointer = typename packed_container_type::const_pointer; | ||||
|     /*! @brief Random access iterator type. */ | ||||
|     using iterator = basic_iterator; | ||||
|     /*! @brief Constant random access iterator type. */ | ||||
|     using const_iterator = iterator; | ||||
|     /*! @brief Reverse iterator type. */ | ||||
|     using reverse_iterator = std::reverse_iterator<iterator>; | ||||
|     /*! @brief Constant reverse iterator type. */ | ||||
|     using const_reverse_iterator = reverse_iterator; | ||||
|  | ||||
|     /*! @brief Default constructor. */ | ||||
|     basic_sparse_set() | ||||
|         : basic_sparse_set{type_id<void>()} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an empty container with a given allocator. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     explicit basic_sparse_set(const allocator_type &allocator) | ||||
|         : basic_sparse_set{type_id<void>(), deletion_policy::swap_and_pop, allocator} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an empty container with the given policy and allocator. | ||||
|      * @param pol Type of deletion policy. | ||||
|      * @param allocator The allocator to use (possibly default-constructed). | ||||
|      */ | ||||
|     explicit basic_sparse_set(deletion_policy pol, const allocator_type &allocator = {}) | ||||
|         : basic_sparse_set{type_id<void>(), pol, allocator} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an empty container with the given value type, policy | ||||
|      * and allocator. | ||||
|      * @param value Returned value type, if any. | ||||
|      * @param pol Type of deletion policy. | ||||
|      * @param allocator The allocator to use (possibly default-constructed). | ||||
|      */ | ||||
|     explicit basic_sparse_set(const type_info &value, deletion_policy pol = deletion_policy::swap_and_pop, const allocator_type &allocator = {}) | ||||
|         : sparse{allocator}, | ||||
|           packed{allocator}, | ||||
|           info{&value}, | ||||
|           free_list{tombstone}, | ||||
|           mode{pol} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Move constructor. | ||||
|      * @param other The instance to move from. | ||||
|      */ | ||||
|     basic_sparse_set(basic_sparse_set &&other) noexcept | ||||
|         : sparse{std::move(other.sparse)}, | ||||
|           packed{std::move(other.packed)}, | ||||
|           info{other.info}, | ||||
|           free_list{std::exchange(other.free_list, tombstone)}, | ||||
|           mode{other.mode} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Allocator-extended move constructor. | ||||
|      * @param other The instance to move from. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator) noexcept | ||||
|         : sparse{std::move(other.sparse), allocator}, | ||||
|           packed{std::move(other.packed), allocator}, | ||||
|           info{other.info}, | ||||
|           free_list{std::exchange(other.free_list, tombstone)}, | ||||
|           mode{other.mode} { | ||||
|         ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.get_allocator() == other.packed.get_allocator(), "Copying a sparse set is not allowed"); | ||||
|     } | ||||
|  | ||||
|     /*! @brief Default destructor. */ | ||||
|     virtual ~basic_sparse_set() { | ||||
|         release_sparse_pages(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Move assignment operator. | ||||
|      * @param other The instance to move from. | ||||
|      * @return This sparse set. | ||||
|      */ | ||||
|     basic_sparse_set &operator=(basic_sparse_set &&other) noexcept { | ||||
|         ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.get_allocator() == other.packed.get_allocator(), "Copying a sparse set is not allowed"); | ||||
|  | ||||
|         release_sparse_pages(); | ||||
|         sparse = std::move(other.sparse); | ||||
|         packed = std::move(other.packed); | ||||
|         info = other.info; | ||||
|         free_list = std::exchange(other.free_list, tombstone); | ||||
|         mode = other.mode; | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Exchanges the contents with those of a given sparse set. | ||||
|      * @param other Sparse set to exchange the content with. | ||||
|      */ | ||||
|     void swap(basic_sparse_set &other) { | ||||
|         using std::swap; | ||||
|         swap(sparse, other.sparse); | ||||
|         swap(packed, other.packed); | ||||
|         swap(info, other.info); | ||||
|         swap(free_list, other.free_list); | ||||
|         swap(mode, other.mode); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the associated allocator. | ||||
|      * @return The associated allocator. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { | ||||
|         return packed.get_allocator(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the deletion policy of a sparse set. | ||||
|      * @return The deletion policy of the sparse set. | ||||
|      */ | ||||
|     [[nodiscard]] deletion_policy policy() const noexcept { | ||||
|         return mode; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Increases the capacity of a sparse set. | ||||
|      * | ||||
|      * If the new capacity is greater than the current capacity, new storage is | ||||
|      * allocated, otherwise the method does nothing. | ||||
|      * | ||||
|      * @param cap Desired capacity. | ||||
|      */ | ||||
|     virtual void reserve(const size_type cap) { | ||||
|         packed.reserve(cap); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the number of elements that a sparse set has currently | ||||
|      * allocated space for. | ||||
|      * @return Capacity of the sparse set. | ||||
|      */ | ||||
|     [[nodiscard]] virtual size_type capacity() const noexcept { | ||||
|         return packed.capacity(); | ||||
|     } | ||||
|  | ||||
|     /*! @brief Requests the removal of unused capacity. */ | ||||
|     virtual void shrink_to_fit() { | ||||
|         packed.shrink_to_fit(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the extent of a sparse set. | ||||
|      * | ||||
|      * The extent of a sparse set is also the size of the internal sparse array. | ||||
|      * There is no guarantee that the internal packed array has the same size. | ||||
|      * Usually the size of the internal sparse array is equal or greater than | ||||
|      * the one of the internal packed array. | ||||
|      * | ||||
|      * @return Extent of the sparse set. | ||||
|      */ | ||||
|     [[nodiscard]] size_type extent() const noexcept { | ||||
|         return sparse.size() * entity_traits::page_size; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the number of elements in a sparse set. | ||||
|      * | ||||
|      * The number of elements is also the size of the internal packed array. | ||||
|      * There is no guarantee that the internal sparse array has the same size. | ||||
|      * Usually the size of the internal sparse array is equal or greater than | ||||
|      * the one of the internal packed array. | ||||
|      * | ||||
|      * @return Number of elements. | ||||
|      */ | ||||
|     [[nodiscard]] size_type size() const noexcept { | ||||
|         return packed.size(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks whether a sparse set is empty. | ||||
|      * @return True if the sparse set is empty, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool empty() const noexcept { | ||||
|         return packed.empty(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Direct access to the internal packed array. | ||||
|      * @return A pointer to the internal packed array. | ||||
|      */ | ||||
|     [[nodiscard]] pointer data() const noexcept { | ||||
|         return packed.data(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the beginning. | ||||
|      * | ||||
|      * The returned iterator points to the first entity of the internal packed | ||||
|      * array. If the sparse set is empty, the returned iterator will be equal to | ||||
|      * `end()`. | ||||
|      * | ||||
|      * @return An iterator to the first entity of the sparse set. | ||||
|      */ | ||||
|     [[nodiscard]] const_iterator begin() const noexcept { | ||||
|         const auto pos = static_cast<typename iterator::difference_type>(packed.size()); | ||||
|         return iterator{packed, pos}; | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc begin */ | ||||
|     [[nodiscard]] const_iterator cbegin() const noexcept { | ||||
|         return begin(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the end. | ||||
|      * | ||||
|      * The returned iterator points to the element following the last entity in | ||||
|      * a sparse set. Attempting to dereference the returned iterator results in | ||||
|      * undefined behavior. | ||||
|      * | ||||
|      * @return An iterator to the element following the last entity of a sparse | ||||
|      * set. | ||||
|      */ | ||||
|     [[nodiscard]] iterator end() const noexcept { | ||||
|         return iterator{packed, {}}; | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc end */ | ||||
|     [[nodiscard]] const_iterator cend() const noexcept { | ||||
|         return end(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns a reverse iterator to the beginning. | ||||
|      * | ||||
|      * The returned iterator points to the first entity of the reversed internal | ||||
|      * packed array. If the sparse set is empty, the returned iterator will be | ||||
|      * equal to `rend()`. | ||||
|      * | ||||
|      * @return An iterator to the first entity of the reversed internal packed | ||||
|      * array. | ||||
|      */ | ||||
|     [[nodiscard]] const_reverse_iterator rbegin() const noexcept { | ||||
|         return std::make_reverse_iterator(end()); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc rbegin */ | ||||
|     [[nodiscard]] const_reverse_iterator crbegin() const noexcept { | ||||
|         return rbegin(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns a reverse iterator to the end. | ||||
|      * | ||||
|      * The returned iterator points to the element following the last entity in | ||||
|      * the reversed sparse set. Attempting to dereference the returned iterator | ||||
|      * results in undefined behavior. | ||||
|      * | ||||
|      * @return An iterator to the element following the last entity of the | ||||
|      * reversed sparse set. | ||||
|      */ | ||||
|     [[nodiscard]] reverse_iterator rend() const noexcept { | ||||
|         return std::make_reverse_iterator(begin()); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc rend */ | ||||
|     [[nodiscard]] const_reverse_iterator crend() const noexcept { | ||||
|         return rend(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Finds an entity. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return An iterator to the given entity if it's found, past the end | ||||
|      * iterator otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] iterator find(const entity_type entt) const noexcept { | ||||
|         return contains(entt) ? --(end() - index(entt)) : end(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Checks if a sparse set contains an entity. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return True if the sparse set contains the entity, false otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] bool contains(const entity_type entt) const noexcept { | ||||
|         const auto elem = sparse_ptr(entt); | ||||
|         constexpr auto cap = entity_traits::to_entity(null); | ||||
|         // testing versions permits to avoid accessing the packed array | ||||
|         return elem && (((~cap & entity_traits::to_integral(entt)) ^ entity_traits::to_integral(*elem)) < cap); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the contained version for an identifier. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return The version for the given identifier if present, the tombstone | ||||
|      * version otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] version_type current(const entity_type entt) const noexcept { | ||||
|         const auto elem = sparse_ptr(entt); | ||||
|         constexpr auto fallback = entity_traits::to_version(tombstone); | ||||
|         return elem ? entity_traits::to_version(*elem) : fallback; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the position of an entity in a sparse set. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to get the position of an entity that doesn't belong to the | ||||
|      * sparse set results in undefined behavior. | ||||
|      * | ||||
|      * @param entt A valid identifier. | ||||
|      * @return The position of the entity in the sparse set. | ||||
|      */ | ||||
|     [[nodiscard]] size_type index(const entity_type entt) const noexcept { | ||||
|         ENTT_ASSERT(contains(entt), "Set does not contain entity"); | ||||
|         return static_cast<size_type>(entity_traits::to_entity(sparse_ref(entt))); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the entity at specified location, with bounds checking. | ||||
|      * @param pos The position for which to return the entity. | ||||
|      * @return The entity at specified location if any, a null entity otherwise. | ||||
|      */ | ||||
|     [[nodiscard]] entity_type at(const size_type pos) const noexcept { | ||||
|         return pos < packed.size() ? packed[pos] : null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the entity at specified location, without bounds checking. | ||||
|      * @param pos The position for which to return the entity. | ||||
|      * @return The entity at specified location. | ||||
|      */ | ||||
|     [[nodiscard]] entity_type operator[](const size_type pos) const noexcept { | ||||
|         ENTT_ASSERT(pos < packed.size(), "Position is out of bounds"); | ||||
|         return packed[pos]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the element assigned to an entity, if any. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to use an entity that doesn't belong to the sparse set results | ||||
|      * in undefined behavior. | ||||
|      * | ||||
|      * @param entt A valid identifier. | ||||
|      * @return An opaque pointer to the element assigned to the entity, if any. | ||||
|      */ | ||||
|     [[nodiscard]] const void *get(const entity_type entt) const noexcept { | ||||
|         return get_at(index(entt)); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc get */ | ||||
|     [[nodiscard]] void *get(const entity_type entt) noexcept { | ||||
|         return const_cast<void *>(std::as_const(*this).get(entt)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns an entity to a sparse set. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to assign an entity that already belongs to the sparse set | ||||
|      * results in undefined behavior. | ||||
|      * | ||||
|      * @param entt A valid identifier. | ||||
|      * @param value Optional opaque value to forward to mixins, if any. | ||||
|      * @return Iterator pointing to the emplaced element in case of success, the | ||||
|      * `end()` iterator otherwise. | ||||
|      */ | ||||
|     iterator emplace(const entity_type entt, const void *value = nullptr) { | ||||
|         return try_emplace(entt, false, value); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Bump the version number of an entity. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to bump the version of an entity that doesn't belong to the | ||||
|      * sparse set results in undefined behavior. | ||||
|      * | ||||
|      * @param entt A valid identifier. | ||||
|      */ | ||||
|     void bump(const entity_type entt) { | ||||
|         auto &entity = sparse_ref(entt); | ||||
|         ENTT_ASSERT(entt != tombstone && entity != null, "Cannot set the required version"); | ||||
|         entity = entity_traits::combine(entity_traits::to_integral(entity), entity_traits::to_integral(entt)); | ||||
|         packed[static_cast<size_type>(entity_traits::to_entity(entity))] = entt; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns one or more entities to a sparse set. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to assign an entity that already belongs to the sparse set | ||||
|      * results in undefined behavior. | ||||
|      * | ||||
|      * @tparam It Type of input iterator. | ||||
|      * @param first An iterator to the first element of the range of entities. | ||||
|      * @param last An iterator past the last element of the range of entities. | ||||
|      * @return Iterator pointing to the first element inserted in case of | ||||
|      * success, the `end()` iterator otherwise. | ||||
|      */ | ||||
|     template<typename It> | ||||
|     iterator insert(It first, It last) { | ||||
|         for(auto it = first; it != last; ++it) { | ||||
|             try_emplace(*it, true); | ||||
|         } | ||||
|  | ||||
|         return first == last ? end() : find(*first); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Erases an entity from a sparse set. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to erase an entity that doesn't belong to the sparse set | ||||
|      * results in undefined behavior. | ||||
|      * | ||||
|      * @param entt A valid identifier. | ||||
|      */ | ||||
|     void erase(const entity_type entt) { | ||||
|         const auto it = --(end() - index(entt)); | ||||
|         pop(it, it + 1u); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Erases entities from a set. | ||||
|      * | ||||
|      * @sa erase | ||||
|      * | ||||
|      * @tparam It Type of input iterator. | ||||
|      * @param first An iterator to the first element of the range of entities. | ||||
|      * @param last An iterator past the last element of the range of entities. | ||||
|      */ | ||||
|     template<typename It> | ||||
|     void erase(It first, It last) { | ||||
|         if constexpr(std::is_same_v<It, basic_iterator>) { | ||||
|             pop(first, last); | ||||
|         } else { | ||||
|             for(; first != last; ++first) { | ||||
|                 erase(*first); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Removes an entity from a sparse set if it exists. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return True if the entity is actually removed, false otherwise. | ||||
|      */ | ||||
|     bool remove(const entity_type entt) { | ||||
|         return contains(entt) && (erase(entt), true); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Removes entities from a sparse set if they exist. | ||||
|      * @tparam It Type of input iterator. | ||||
|      * @param first An iterator to the first element of the range of entities. | ||||
|      * @param last An iterator past the last element of the range of entities. | ||||
|      * @return The number of entities actually removed. | ||||
|      */ | ||||
|     template<typename It> | ||||
|     size_type remove(It first, It last) { | ||||
|         size_type count{}; | ||||
|  | ||||
|         for(; first != last; ++first) { | ||||
|             count += remove(*first); | ||||
|         } | ||||
|  | ||||
|         return count; | ||||
|     } | ||||
|  | ||||
|     /*! @brief Removes all tombstones from the packed array of a sparse set. */ | ||||
|     void compact() { | ||||
|         size_type from = packed.size(); | ||||
|         for(; from && packed[from - 1u] == tombstone; --from) {} | ||||
|  | ||||
|         for(auto *it = &free_list; *it != null && from; it = std::addressof(packed[entity_traits::to_entity(*it)])) { | ||||
|             if(const size_type to = entity_traits::to_entity(*it); to < from) { | ||||
|                 --from; | ||||
|                 move_element(from, to); | ||||
|  | ||||
|                 using std::swap; | ||||
|                 swap(packed[from], packed[to]); | ||||
|  | ||||
|                 const auto entity = static_cast<typename entity_traits::entity_type>(to); | ||||
|                 sparse_ref(packed[to]) = entity_traits::combine(entity, entity_traits::to_integral(packed[to])); | ||||
|                 *it = entity_traits::combine(static_cast<typename entity_traits::entity_type>(from), entity_traits::reserved); | ||||
|                 for(; from && packed[from - 1u] == tombstone; --from) {} | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         free_list = tombstone; | ||||
|         packed.resize(from); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Swaps two entities in a sparse set. | ||||
|      * | ||||
|      * For what it's worth, this function affects both the internal sparse array | ||||
|      * and the internal packed array. Users should not care of that anyway. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to swap entities that don't belong to the sparse set results | ||||
|      * in undefined behavior. | ||||
|      * | ||||
|      * @param lhs A valid identifier. | ||||
|      * @param rhs A valid identifier. | ||||
|      */ | ||||
|     void swap_elements(const entity_type lhs, const entity_type rhs) { | ||||
|         ENTT_ASSERT(contains(lhs) && contains(rhs), "Set does not contain entities"); | ||||
|  | ||||
|         auto &entt = sparse_ref(lhs); | ||||
|         auto &other = sparse_ref(rhs); | ||||
|  | ||||
|         const auto from = entity_traits::to_entity(entt); | ||||
|         const auto to = entity_traits::to_entity(other); | ||||
|  | ||||
|         // basic no-leak guarantee (with invalid state) if swapping throws | ||||
|         swap_at(static_cast<size_type>(from), static_cast<size_type>(to)); | ||||
|         entt = entity_traits::combine(to, entity_traits::to_integral(packed[from])); | ||||
|         other = entity_traits::combine(from, entity_traits::to_integral(packed[to])); | ||||
|  | ||||
|         using std::swap; | ||||
|         swap(packed[from], packed[to]); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Sort the first count elements according to the given comparison | ||||
|      * function. | ||||
|      * | ||||
|      * The comparison function object must return `true` if the first element | ||||
|      * is _less_ than the second one, `false` otherwise. The signature of the | ||||
|      * comparison function should be equivalent to the following: | ||||
|      * | ||||
|      * @code{.cpp} | ||||
|      * bool(const Entity, const Entity); | ||||
|      * @endcode | ||||
|      * | ||||
|      * Moreover, the comparison function object shall induce a | ||||
|      * _strict weak ordering_ on the values. | ||||
|      * | ||||
|      * The sort function object must offer a member function template | ||||
|      * `operator()` that accepts three arguments: | ||||
|      * | ||||
|      * * An iterator to the first element of the range to sort. | ||||
|      * * An iterator past the last element of the range to sort. | ||||
|      * * A comparison function to use to compare the elements. | ||||
|      * | ||||
|      * @tparam Compare Type of comparison function object. | ||||
|      * @tparam Sort Type of sort function object. | ||||
|      * @tparam Args Types of arguments to forward to the sort function object. | ||||
|      * @param length Number of elements to sort. | ||||
|      * @param compare A valid comparison function object. | ||||
|      * @param algo A valid sort function object. | ||||
|      * @param args Arguments to forward to the sort function object, if any. | ||||
|      */ | ||||
|     template<typename Compare, typename Sort = std_sort, typename... Args> | ||||
|     void sort_n(const size_type length, Compare compare, Sort algo = Sort{}, Args &&...args) { | ||||
|         ENTT_ASSERT(!(length > packed.size()), "Length exceeds the number of elements"); | ||||
|         ENTT_ASSERT(free_list == null, "Partial sorting with tombstones is not supported"); | ||||
|  | ||||
|         algo(packed.rend() - length, packed.rend(), std::move(compare), std::forward<Args>(args)...); | ||||
|  | ||||
|         for(size_type pos{}; pos < length; ++pos) { | ||||
|             auto curr = pos; | ||||
|             auto next = index(packed[curr]); | ||||
|  | ||||
|             while(curr != next) { | ||||
|                 const auto idx = index(packed[next]); | ||||
|                 const auto entt = packed[curr]; | ||||
|  | ||||
|                 swap_at(next, idx); | ||||
|                 const auto entity = static_cast<typename entity_traits::entity_type>(curr); | ||||
|                 sparse_ref(entt) = entity_traits::combine(entity, entity_traits::to_integral(packed[curr])); | ||||
|                 curr = std::exchange(next, idx); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Sort all elements according to the given comparison function. | ||||
|      * | ||||
|      * @sa sort_n | ||||
|      * | ||||
|      * @tparam Compare Type of comparison function object. | ||||
|      * @tparam Sort Type of sort function object. | ||||
|      * @tparam Args Types of arguments to forward to the sort function object. | ||||
|      * @param compare A valid comparison function object. | ||||
|      * @param algo A valid sort function object. | ||||
|      * @param args Arguments to forward to the sort function object, if any. | ||||
|      */ | ||||
|     template<typename Compare, typename Sort = std_sort, typename... Args> | ||||
|     void sort(Compare compare, Sort algo = Sort{}, Args &&...args) { | ||||
|         compact(); | ||||
|         sort_n(packed.size(), std::move(compare), std::move(algo), std::forward<Args>(args)...); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Sort entities according to their order in another sparse set. | ||||
|      * | ||||
|      * Entities that are part of both the sparse sets are ordered internally | ||||
|      * according to the order they have in `other`. All the other entities goes | ||||
|      * to the end of the list and there are no guarantees on their order.<br/> | ||||
|      * In other terms, this function can be used to impose the same order on two | ||||
|      * sets by using one of them as a master and the other one as a slave. | ||||
|      * | ||||
|      * Iterating the sparse set with a couple of iterators returns elements in | ||||
|      * the expected order after a call to `respect`. See `begin` and `end` for | ||||
|      * more details. | ||||
|      * | ||||
|      * @param other The sparse sets that imposes the order of the entities. | ||||
|      */ | ||||
|     void respect(const basic_sparse_set &other) { | ||||
|         compact(); | ||||
|  | ||||
|         const auto to = other.end(); | ||||
|         auto from = other.begin(); | ||||
|  | ||||
|         for(size_type pos = packed.size() - 1; pos && from != to; ++from) { | ||||
|             if(contains(*from)) { | ||||
|                 if(*from != packed[pos]) { | ||||
|                     // basic no-leak guarantee (with invalid state) if swapping throws | ||||
|                     swap_elements(packed[pos], *from); | ||||
|                 } | ||||
|  | ||||
|                 --pos; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /*! @brief Clears a sparse set. */ | ||||
|     void clear() { | ||||
|         if(const auto last = end(); free_list == null) { | ||||
|             pop(begin(), last); | ||||
|         } else { | ||||
|             for(auto &&entity: *this) { | ||||
|                 // tombstone filter on itself | ||||
|                 if(const auto it = find(entity); it != last) { | ||||
|                     pop(it, it + 1u); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         free_list = tombstone; | ||||
|         packed.clear(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returned value type, if any. | ||||
|      * @return Returned value type, if any. | ||||
|      */ | ||||
|     const type_info &type() const noexcept { | ||||
|         return *info; | ||||
|     } | ||||
|  | ||||
|     /*! @brief Forwards variables to derived classes, if any. */ | ||||
|     virtual void bind(any) noexcept {} | ||||
|  | ||||
| private: | ||||
|     sparse_container_type sparse; | ||||
|     packed_container_type packed; | ||||
|     const type_info *info; | ||||
|     entity_type free_list; | ||||
|     deletion_policy mode; | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										903
									
								
								external/entt/entt/src/entt/entity/storage.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										903
									
								
								external/entt/entt/src/entt/entity/storage.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,903 @@ | ||||
| #ifndef ENTT_ENTITY_STORAGE_HPP | ||||
| #define ENTT_ENTITY_STORAGE_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <iterator> | ||||
| #include <memory> | ||||
| #include <tuple> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include "../config/config.h" | ||||
| #include "../core/compressed_pair.hpp" | ||||
| #include "../core/iterator.hpp" | ||||
| #include "../core/memory.hpp" | ||||
| #include "../core/type_info.hpp" | ||||
| #include "component.hpp" | ||||
| #include "entity.hpp" | ||||
| #include "fwd.hpp" | ||||
| #include "sparse_set.hpp" | ||||
| #include "storage_mixin.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @cond TURN_OFF_DOXYGEN | ||||
|  * Internal details not to be documented. | ||||
|  */ | ||||
|  | ||||
| namespace internal { | ||||
|  | ||||
| template<typename Container> | ||||
| class storage_iterator final { | ||||
|     friend storage_iterator<const Container>; | ||||
|  | ||||
|     using container_type = std::remove_const_t<Container>; | ||||
|     using alloc_traits = std::allocator_traits<typename container_type::allocator_type>; | ||||
|     using comp_traits = component_traits<std::remove_pointer_t<typename container_type::value_type>>; | ||||
|  | ||||
|     using iterator_traits = std::iterator_traits<std::conditional_t< | ||||
|         std::is_const_v<Container>, | ||||
|         typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::const_pointer, | ||||
|         typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::pointer>>; | ||||
|  | ||||
| public: | ||||
|     using value_type = typename iterator_traits::value_type; | ||||
|     using pointer = typename iterator_traits::pointer; | ||||
|     using reference = typename iterator_traits::reference; | ||||
|     using difference_type = typename iterator_traits::difference_type; | ||||
|     using iterator_category = std::random_access_iterator_tag; | ||||
|  | ||||
|     constexpr storage_iterator() noexcept = default; | ||||
|  | ||||
|     constexpr storage_iterator(Container *ref, const difference_type idx) noexcept | ||||
|         : packed{ref}, | ||||
|           offset{idx} {} | ||||
|  | ||||
|     template<bool Const = std::is_const_v<Container>, typename = std::enable_if_t<Const>> | ||||
|     constexpr storage_iterator(const storage_iterator<std::remove_const_t<Container>> &other) noexcept | ||||
|         : storage_iterator{other.packed, other.offset} {} | ||||
|  | ||||
|     constexpr storage_iterator &operator++() noexcept { | ||||
|         return --offset, *this; | ||||
|     } | ||||
|  | ||||
|     constexpr storage_iterator operator++(int) noexcept { | ||||
|         storage_iterator orig = *this; | ||||
|         return ++(*this), orig; | ||||
|     } | ||||
|  | ||||
|     constexpr storage_iterator &operator--() noexcept { | ||||
|         return ++offset, *this; | ||||
|     } | ||||
|  | ||||
|     constexpr storage_iterator operator--(int) noexcept { | ||||
|         storage_iterator orig = *this; | ||||
|         return operator--(), orig; | ||||
|     } | ||||
|  | ||||
|     constexpr storage_iterator &operator+=(const difference_type value) noexcept { | ||||
|         offset -= value; | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     constexpr storage_iterator operator+(const difference_type value) const noexcept { | ||||
|         storage_iterator copy = *this; | ||||
|         return (copy += value); | ||||
|     } | ||||
|  | ||||
|     constexpr storage_iterator &operator-=(const difference_type value) noexcept { | ||||
|         return (*this += -value); | ||||
|     } | ||||
|  | ||||
|     constexpr storage_iterator operator-(const difference_type value) const noexcept { | ||||
|         return (*this + -value); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { | ||||
|         const auto pos = index() - value; | ||||
|         return (*packed)[pos / comp_traits::page_size][fast_mod(pos, comp_traits::page_size)]; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr pointer operator->() const noexcept { | ||||
|         const auto pos = index(); | ||||
|         return (*packed)[pos / comp_traits::page_size] + fast_mod(pos, comp_traits::page_size); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr reference operator*() const noexcept { | ||||
|         return *operator->(); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr difference_type index() const noexcept { | ||||
|         return offset - 1; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     Container *packed; | ||||
|     difference_type offset; | ||||
| }; | ||||
|  | ||||
| template<typename CLhs, typename CRhs> | ||||
| [[nodiscard]] constexpr std::ptrdiff_t operator-(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) noexcept { | ||||
|     return rhs.index() - lhs.index(); | ||||
| } | ||||
|  | ||||
| template<typename CLhs, typename CRhs> | ||||
| [[nodiscard]] constexpr bool operator==(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) noexcept { | ||||
|     return lhs.index() == rhs.index(); | ||||
| } | ||||
|  | ||||
| template<typename CLhs, typename CRhs> | ||||
| [[nodiscard]] constexpr bool operator!=(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) noexcept { | ||||
|     return !(lhs == rhs); | ||||
| } | ||||
|  | ||||
| template<typename CLhs, typename CRhs> | ||||
| [[nodiscard]] constexpr bool operator<(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) noexcept { | ||||
|     return lhs.index() > rhs.index(); | ||||
| } | ||||
|  | ||||
| template<typename CLhs, typename CRhs> | ||||
| [[nodiscard]] constexpr bool operator>(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) noexcept { | ||||
|     return lhs.index() < rhs.index(); | ||||
| } | ||||
|  | ||||
| template<typename CLhs, typename CRhs> | ||||
| [[nodiscard]] constexpr bool operator<=(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) noexcept { | ||||
|     return !(lhs > rhs); | ||||
| } | ||||
|  | ||||
| template<typename CLhs, typename CRhs> | ||||
| [[nodiscard]] constexpr bool operator>=(const storage_iterator<CLhs> &lhs, const storage_iterator<CRhs> &rhs) noexcept { | ||||
|     return !(lhs < rhs); | ||||
| } | ||||
|  | ||||
| template<typename It, typename... Other> | ||||
| class extended_storage_iterator final { | ||||
|     template<typename Iter, typename... Args> | ||||
|     friend class extended_storage_iterator; | ||||
|  | ||||
| public: | ||||
|     using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::forward_as_tuple(*std::declval<Other>()...))); | ||||
|     using pointer = input_iterator_pointer<value_type>; | ||||
|     using reference = value_type; | ||||
|     using difference_type = std::ptrdiff_t; | ||||
|     using iterator_category = std::input_iterator_tag; | ||||
|  | ||||
|     constexpr extended_storage_iterator() | ||||
|         : it{} {} | ||||
|  | ||||
|     constexpr extended_storage_iterator(It base, Other... other) | ||||
|         : it{base, other...} {} | ||||
|  | ||||
|     template<typename... Args, typename = std::enable_if_t<(!std::is_same_v<Other, Args> && ...) && (std::is_constructible_v<Other, Args> && ...)>> | ||||
|     constexpr extended_storage_iterator(const extended_storage_iterator<It, Args...> &other) | ||||
|         : it{other.it} {} | ||||
|  | ||||
|     constexpr extended_storage_iterator &operator++() noexcept { | ||||
|         return ++std::get<It>(it), (++std::get<Other>(it), ...), *this; | ||||
|     } | ||||
|  | ||||
|     constexpr extended_storage_iterator operator++(int) noexcept { | ||||
|         extended_storage_iterator orig = *this; | ||||
|         return ++(*this), orig; | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr pointer operator->() const noexcept { | ||||
|         return operator*(); | ||||
|     } | ||||
|  | ||||
|     [[nodiscard]] constexpr reference operator*() const noexcept { | ||||
|         return {*std::get<It>(it), *std::get<Other>(it)...}; | ||||
|     } | ||||
|  | ||||
|     template<typename... CLhs, typename... CRhs> | ||||
|     friend constexpr bool operator==(const extended_storage_iterator<CLhs...> &, const extended_storage_iterator<CRhs...> &) noexcept; | ||||
|  | ||||
| private: | ||||
|     std::tuple<It, Other...> it; | ||||
| }; | ||||
|  | ||||
| template<typename... CLhs, typename... CRhs> | ||||
| [[nodiscard]] constexpr bool operator==(const extended_storage_iterator<CLhs...> &lhs, const extended_storage_iterator<CRhs...> &rhs) noexcept { | ||||
|     return std::get<0>(lhs.it) == std::get<0>(rhs.it); | ||||
| } | ||||
|  | ||||
| template<typename... CLhs, typename... CRhs> | ||||
| [[nodiscard]] constexpr bool operator!=(const extended_storage_iterator<CLhs...> &lhs, const extended_storage_iterator<CRhs...> &rhs) noexcept { | ||||
|     return !(lhs == rhs); | ||||
| } | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief Basic storage implementation. | ||||
|  * | ||||
|  * Internal data structures arrange elements to maximize performance. There are | ||||
|  * no guarantees that objects are returned in the insertion order when iterate | ||||
|  * a storage. Do not make assumption on the order in any case. | ||||
|  * | ||||
|  * @warning | ||||
|  * Empty types aren't explicitly instantiated. Therefore, many of the functions | ||||
|  * normally available for non-empty types will not be available for empty ones. | ||||
|  * | ||||
|  * @tparam Type Type of objects assigned to the entities. | ||||
|  * @tparam Entity A valid entity type (see entt_traits for more details). | ||||
|  * @tparam Allocator Type of allocator used to manage memory and elements. | ||||
|  */ | ||||
| template<typename Type, typename Entity, typename Allocator, typename> | ||||
| class basic_storage: public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> { | ||||
|     using alloc_traits = std::allocator_traits<Allocator>; | ||||
|     static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type"); | ||||
|     using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>; | ||||
|     using container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>; | ||||
|     using comp_traits = component_traits<Type>; | ||||
|  | ||||
|     static constexpr bool is_pinned_type_v = !(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>); | ||||
|  | ||||
|     [[nodiscard]] auto &element_at(const std::size_t pos) const { | ||||
|         return packed.first()[pos / comp_traits::page_size][fast_mod(pos, comp_traits::page_size)]; | ||||
|     } | ||||
|  | ||||
|     auto assure_at_least(const std::size_t pos) { | ||||
|         auto &&container = packed.first(); | ||||
|         const auto idx = pos / comp_traits::page_size; | ||||
|  | ||||
|         if(!(idx < container.size())) { | ||||
|             auto curr = container.size(); | ||||
|             container.resize(idx + 1u, nullptr); | ||||
|  | ||||
|             ENTT_TRY { | ||||
|                 for(const auto last = container.size(); curr < last; ++curr) { | ||||
|                     container[curr] = alloc_traits::allocate(packed.second(), comp_traits::page_size); | ||||
|                 } | ||||
|             } | ||||
|             ENTT_CATCH { | ||||
|                 container.resize(curr); | ||||
|                 ENTT_THROW; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return container[idx] + fast_mod(pos, comp_traits::page_size); | ||||
|     } | ||||
|  | ||||
|     template<typename... Args> | ||||
|     auto emplace_element(const Entity entt, const bool force_back, Args &&...args) { | ||||
|         const auto it = base_type::try_emplace(entt, force_back); | ||||
|  | ||||
|         ENTT_TRY { | ||||
|             auto elem = assure_at_least(static_cast<size_type>(it.index())); | ||||
|             entt::uninitialized_construct_using_allocator(to_address(elem), packed.second(), std::forward<Args>(args)...); | ||||
|         } | ||||
|         ENTT_CATCH { | ||||
|             base_type::pop(it, it + 1u); | ||||
|             ENTT_THROW; | ||||
|         } | ||||
|  | ||||
|         return it; | ||||
|     } | ||||
|  | ||||
|     void shrink_to_size(const std::size_t sz) { | ||||
|         for(auto pos = sz, length = base_type::size(); pos < length; ++pos) { | ||||
|             if constexpr(comp_traits::in_place_delete) { | ||||
|                 if(base_type::at(pos) != tombstone) { | ||||
|                     std::destroy_at(std::addressof(element_at(pos))); | ||||
|                 } | ||||
|             } else { | ||||
|                 std::destroy_at(std::addressof(element_at(pos))); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         auto &&container = packed.first(); | ||||
|         auto page_allocator{packed.second()}; | ||||
|         const auto from = (sz + comp_traits::page_size - 1u) / comp_traits::page_size; | ||||
|  | ||||
|         for(auto pos = from, last = container.size(); pos < last; ++pos) { | ||||
|             alloc_traits::deallocate(page_allocator, container[pos], comp_traits::page_size); | ||||
|         } | ||||
|  | ||||
|         container.resize(from); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     const void *get_at(const std::size_t pos) const final { | ||||
|         return std::addressof(element_at(pos)); | ||||
|     } | ||||
|  | ||||
|     void swap_at([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) final { | ||||
|         // use a runtime value to avoid compile-time suppression that drives the code coverage tool crazy | ||||
|         ENTT_ASSERT((lhs + 1u) && !is_pinned_type_v, "Pinned type"); | ||||
|  | ||||
|         if constexpr(!is_pinned_type_v) { | ||||
|             using std::swap; | ||||
|             swap(element_at(lhs), element_at(rhs)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void move_element([[maybe_unused]] const std::size_t from, [[maybe_unused]] const std::size_t to) final { | ||||
|         // use a runtime value to avoid compile-time suppression that drives the code coverage tool crazy | ||||
|         ENTT_ASSERT((from + 1u) && !is_pinned_type_v, "Pinned type"); | ||||
|  | ||||
|         if constexpr(!is_pinned_type_v) { | ||||
|             auto &elem = element_at(from); | ||||
|             entt::uninitialized_construct_using_allocator(to_address(assure_at_least(to)), packed.second(), std::move(elem)); | ||||
|             std::destroy_at(std::addressof(elem)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| protected: | ||||
|     /*! @brief Random access iterator type. */ | ||||
|     using basic_iterator = typename underlying_type::basic_iterator; | ||||
|  | ||||
|     /** | ||||
|      * @brief Erases entities from a sparse set. | ||||
|      * @param first An iterator to the first element of the range of entities. | ||||
|      * @param last An iterator past the last element of the range of entities. | ||||
|      */ | ||||
|     void pop(basic_iterator first, basic_iterator last) override { | ||||
|         for(; first != last; ++first) { | ||||
|             // cannot use first.index() because it would break with cross iterators | ||||
|             auto &elem = element_at(base_type::index(*first)); | ||||
|  | ||||
|             if constexpr(comp_traits::in_place_delete) { | ||||
|                 base_type::in_place_pop(first); | ||||
|                 std::destroy_at(std::addressof(elem)); | ||||
|             } else { | ||||
|                 auto &other = element_at(base_type::size() - 1u); | ||||
|                 // destroying on exit allows reentrant destructors | ||||
|                 [[maybe_unused]] auto unused = std::exchange(elem, std::move(other)); | ||||
|                 std::destroy_at(std::addressof(other)); | ||||
|                 base_type::swap_and_pop(first); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns an entity to a storage. | ||||
|      * @param entt A valid identifier. | ||||
|      * @param value Optional opaque value. | ||||
|      * @param force_back Force back insertion. | ||||
|      * @return Iterator pointing to the emplaced element. | ||||
|      */ | ||||
|     basic_iterator try_emplace([[maybe_unused]] const Entity entt, [[maybe_unused]] const bool force_back, const void *value) override { | ||||
|         if(value) { | ||||
|             if constexpr(std::is_copy_constructible_v<value_type>) { | ||||
|                 return emplace_element(entt, force_back, *static_cast<const value_type *>(value)); | ||||
|             } else { | ||||
|                 return base_type::end(); | ||||
|             } | ||||
|         } else { | ||||
|             if constexpr(std::is_default_constructible_v<value_type>) { | ||||
|                 return emplace_element(entt, force_back); | ||||
|             } else { | ||||
|                 return base_type::end(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! @brief Base type. */ | ||||
|     using base_type = underlying_type; | ||||
|     /*! @brief Allocator type. */ | ||||
|     using allocator_type = Allocator; | ||||
|     /*! @brief Type of the objects assigned to entities. */ | ||||
|     using value_type = Type; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = Entity; | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using size_type = std::size_t; | ||||
|     /*! @brief Pointer type to contained elements. */ | ||||
|     using pointer = typename container_type::pointer; | ||||
|     /*! @brief Constant pointer type to contained elements. */ | ||||
|     using const_pointer = typename alloc_traits::template rebind_traits<typename alloc_traits::const_pointer>::const_pointer; | ||||
|     /*! @brief Random access iterator type. */ | ||||
|     using iterator = internal::storage_iterator<container_type>; | ||||
|     /*! @brief Constant random access iterator type. */ | ||||
|     using const_iterator = internal::storage_iterator<const container_type>; | ||||
|     /*! @brief Reverse iterator type. */ | ||||
|     using reverse_iterator = std::reverse_iterator<iterator>; | ||||
|     /*! @brief Constant reverse iterator type. */ | ||||
|     using const_reverse_iterator = std::reverse_iterator<const_iterator>; | ||||
|     /*! @brief Extended iterable storage proxy. */ | ||||
|     using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator, iterator>>; | ||||
|     /*! @brief Constant extended iterable storage proxy. */ | ||||
|     using const_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_iterator, const_iterator>>; | ||||
|  | ||||
|     /*! @brief Default constructor. */ | ||||
|     basic_storage() | ||||
|         : basic_storage{allocator_type{}} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an empty storage with a given allocator. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     explicit basic_storage(const allocator_type &allocator) | ||||
|         : base_type{type_id<value_type>(), deletion_policy{comp_traits::in_place_delete}, allocator}, | ||||
|           packed{container_type{allocator}, allocator} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Move constructor. | ||||
|      * @param other The instance to move from. | ||||
|      */ | ||||
|     basic_storage(basic_storage &&other) noexcept | ||||
|         : base_type{std::move(other)}, | ||||
|           packed{std::move(other.packed)} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Allocator-extended move constructor. | ||||
|      * @param other The instance to move from. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     basic_storage(basic_storage &&other, const allocator_type &allocator) noexcept | ||||
|         : base_type{std::move(other), allocator}, | ||||
|           packed{container_type{std::move(other.packed.first()), allocator}, allocator} { | ||||
|         ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.second() == other.packed.second(), "Copying a storage is not allowed"); | ||||
|     } | ||||
|  | ||||
|     /*! @brief Default destructor. */ | ||||
|     ~basic_storage() override { | ||||
|         shrink_to_size(0u); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Move assignment operator. | ||||
|      * @param other The instance to move from. | ||||
|      * @return This storage. | ||||
|      */ | ||||
|     basic_storage &operator=(basic_storage &&other) noexcept { | ||||
|         ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.second() == other.packed.second(), "Copying a storage is not allowed"); | ||||
|  | ||||
|         shrink_to_size(0u); | ||||
|         base_type::operator=(std::move(other)); | ||||
|         packed.first() = std::move(other.packed.first()); | ||||
|         propagate_on_container_move_assignment(packed.second(), other.packed.second()); | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Exchanges the contents with those of a given storage. | ||||
|      * @param other Storage to exchange the content with. | ||||
|      */ | ||||
|     void swap(basic_storage &other) { | ||||
|         using std::swap; | ||||
|         underlying_type::swap(other); | ||||
|         propagate_on_container_swap(packed.second(), other.packed.second()); | ||||
|         swap(packed.first(), other.packed.first()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the associated allocator. | ||||
|      * @return The associated allocator. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { | ||||
|         return allocator_type{packed.second()}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Increases the capacity of a storage. | ||||
|      * | ||||
|      * If the new capacity is greater than the current capacity, new storage is | ||||
|      * allocated, otherwise the method does nothing. | ||||
|      * | ||||
|      * @param cap Desired capacity. | ||||
|      */ | ||||
|     void reserve(const size_type cap) override { | ||||
|         if(cap != 0u) { | ||||
|             base_type::reserve(cap); | ||||
|             assure_at_least(cap - 1u); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the number of elements that a storage has currently | ||||
|      * allocated space for. | ||||
|      * @return Capacity of the storage. | ||||
|      */ | ||||
|     [[nodiscard]] size_type capacity() const noexcept override { | ||||
|         return packed.first().size() * comp_traits::page_size; | ||||
|     } | ||||
|  | ||||
|     /*! @brief Requests the removal of unused capacity. */ | ||||
|     void shrink_to_fit() override { | ||||
|         base_type::shrink_to_fit(); | ||||
|         shrink_to_size(base_type::size()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Direct access to the array of objects. | ||||
|      * @return A pointer to the array of objects. | ||||
|      */ | ||||
|     [[nodiscard]] const_pointer raw() const noexcept { | ||||
|         return packed.first().data(); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc raw */ | ||||
|     [[nodiscard]] pointer raw() noexcept { | ||||
|         return packed.first().data(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the beginning. | ||||
|      * | ||||
|      * The returned iterator points to the first instance of the internal array. | ||||
|      * If the storage is empty, the returned iterator will be equal to `end()`. | ||||
|      * | ||||
|      * @return An iterator to the first instance of the internal array. | ||||
|      */ | ||||
|     [[nodiscard]] const_iterator cbegin() const noexcept { | ||||
|         const auto pos = static_cast<typename iterator::difference_type>(base_type::size()); | ||||
|         return const_iterator{&packed.first(), pos}; | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc cbegin */ | ||||
|     [[nodiscard]] const_iterator begin() const noexcept { | ||||
|         return cbegin(); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc begin */ | ||||
|     [[nodiscard]] iterator begin() noexcept { | ||||
|         const auto pos = static_cast<typename iterator::difference_type>(base_type::size()); | ||||
|         return iterator{&packed.first(), pos}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterator to the end. | ||||
|      * | ||||
|      * The returned iterator points to the element following the last instance | ||||
|      * of the internal array. Attempting to dereference the returned iterator | ||||
|      * results in undefined behavior. | ||||
|      * | ||||
|      * @return An iterator to the element following the last instance of the | ||||
|      * internal array. | ||||
|      */ | ||||
|     [[nodiscard]] const_iterator cend() const noexcept { | ||||
|         return const_iterator{&packed.first(), {}}; | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc cend */ | ||||
|     [[nodiscard]] const_iterator end() const noexcept { | ||||
|         return cend(); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc end */ | ||||
|     [[nodiscard]] iterator end() noexcept { | ||||
|         return iterator{&packed.first(), {}}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns a reverse iterator to the beginning. | ||||
|      * | ||||
|      * The returned iterator points to the first instance of the reversed | ||||
|      * internal array. If the storage is empty, the returned iterator will be | ||||
|      * equal to `rend()`. | ||||
|      * | ||||
|      * @return An iterator to the first instance of the reversed internal array. | ||||
|      */ | ||||
|     [[nodiscard]] const_reverse_iterator crbegin() const noexcept { | ||||
|         return std::make_reverse_iterator(cend()); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc crbegin */ | ||||
|     [[nodiscard]] const_reverse_iterator rbegin() const noexcept { | ||||
|         return crbegin(); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc rbegin */ | ||||
|     [[nodiscard]] reverse_iterator rbegin() noexcept { | ||||
|         return std::make_reverse_iterator(end()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns a reverse iterator to the end. | ||||
|      * | ||||
|      * The returned iterator points to the element following the last instance | ||||
|      * of the reversed internal array. Attempting to dereference the returned | ||||
|      * iterator results in undefined behavior. | ||||
|      * | ||||
|      * @return An iterator to the element following the last instance of the | ||||
|      * reversed internal array. | ||||
|      */ | ||||
|     [[nodiscard]] const_reverse_iterator crend() const noexcept { | ||||
|         return std::make_reverse_iterator(cbegin()); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc crend */ | ||||
|     [[nodiscard]] const_reverse_iterator rend() const noexcept { | ||||
|         return crend(); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc rend */ | ||||
|     [[nodiscard]] reverse_iterator rend() noexcept { | ||||
|         return std::make_reverse_iterator(begin()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the object assigned to an entity. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to use an entity that doesn't belong to the storage results in | ||||
|      * undefined behavior. | ||||
|      * | ||||
|      * @param entt A valid identifier. | ||||
|      * @return The object assigned to the entity. | ||||
|      */ | ||||
|     [[nodiscard]] const value_type &get(const entity_type entt) const noexcept { | ||||
|         return element_at(base_type::index(entt)); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc get */ | ||||
|     [[nodiscard]] value_type &get(const entity_type entt) noexcept { | ||||
|         return const_cast<value_type &>(std::as_const(*this).get(entt)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the object assigned to an entity as a tuple. | ||||
|      * @param entt A valid identifier. | ||||
|      * @return The object assigned to the entity as a tuple. | ||||
|      */ | ||||
|     [[nodiscard]] std::tuple<const value_type &> get_as_tuple(const entity_type entt) const noexcept { | ||||
|         return std::forward_as_tuple(get(entt)); | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc get_as_tuple */ | ||||
|     [[nodiscard]] std::tuple<value_type &> get_as_tuple(const entity_type entt) noexcept { | ||||
|         return std::forward_as_tuple(get(entt)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns an entity to a storage and constructs its object. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to use an entity that already belongs to the storage results | ||||
|      * in undefined behavior. | ||||
|      * | ||||
|      * @tparam Args Types of arguments to use to construct the object. | ||||
|      * @param entt A valid identifier. | ||||
|      * @param args Parameters to use to construct an object for the entity. | ||||
|      * @return A reference to the newly created object. | ||||
|      */ | ||||
|     template<typename... Args> | ||||
|     value_type &emplace(const entity_type entt, Args &&...args) { | ||||
|         if constexpr(std::is_aggregate_v<value_type>) { | ||||
|             const auto it = emplace_element(entt, false, Type{std::forward<Args>(args)...}); | ||||
|             return element_at(static_cast<size_type>(it.index())); | ||||
|         } else { | ||||
|             const auto it = emplace_element(entt, false, std::forward<Args>(args)...); | ||||
|             return element_at(static_cast<size_type>(it.index())); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Updates the instance assigned to a given entity in-place. | ||||
|      * @tparam Func Types of the function objects to invoke. | ||||
|      * @param entt A valid identifier. | ||||
|      * @param func Valid function objects. | ||||
|      * @return A reference to the updated instance. | ||||
|      */ | ||||
|     template<typename... Func> | ||||
|     value_type &patch(const entity_type entt, Func &&...func) { | ||||
|         const auto idx = base_type::index(entt); | ||||
|         auto &elem = element_at(idx); | ||||
|         (std::forward<Func>(func)(elem), ...); | ||||
|         return elem; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns one or more entities to a storage and constructs their | ||||
|      * objects from a given instance. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to assign an entity that already belongs to the storage | ||||
|      * results in undefined behavior. | ||||
|      * | ||||
|      * @tparam It Type of input iterator. | ||||
|      * @param first An iterator to the first element of the range of entities. | ||||
|      * @param last An iterator past the last element of the range of entities. | ||||
|      * @param value An instance of the object to construct. | ||||
|      */ | ||||
|     template<typename It> | ||||
|     void insert(It first, It last, const value_type &value = {}) { | ||||
|         for(; first != last; ++first) { | ||||
|             emplace_element(*first, true, value); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns one or more entities to a storage and constructs their | ||||
|      * objects from a given range. | ||||
|      * | ||||
|      * @sa construct | ||||
|      * | ||||
|      * @tparam EIt Type of input iterator. | ||||
|      * @tparam CIt Type of input iterator. | ||||
|      * @param first An iterator to the first element of the range of entities. | ||||
|      * @param last An iterator past the last element of the range of entities. | ||||
|      * @param from An iterator to the first element of the range of objects. | ||||
|      */ | ||||
|     template<typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<CIt>::value_type, value_type>>> | ||||
|     void insert(EIt first, EIt last, CIt from) { | ||||
|         for(; first != last; ++first, ++from) { | ||||
|             emplace_element(*first, true, *from); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterable object to use to _visit_ a storage. | ||||
|      * | ||||
|      * The iterable object returns a tuple that contains the current entity and | ||||
|      * a reference to its component. | ||||
|      * | ||||
|      * @return An iterable object to use to _visit_ the storage. | ||||
|      */ | ||||
|     [[nodiscard]] iterable each() noexcept { | ||||
|         return {internal::extended_storage_iterator{base_type::begin(), begin()}, internal::extended_storage_iterator{base_type::end(), end()}}; | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc each */ | ||||
|     [[nodiscard]] const_iterable each() const noexcept { | ||||
|         return {internal::extended_storage_iterator{base_type::cbegin(), cbegin()}, internal::extended_storage_iterator{base_type::cend(), cend()}}; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     compressed_pair<container_type, allocator_type> packed; | ||||
| }; | ||||
|  | ||||
| /*! @copydoc basic_storage */ | ||||
| template<typename Type, typename Entity, typename Allocator> | ||||
| class basic_storage<Type, Entity, Allocator, std::enable_if_t<ignore_as_empty_v<Type>>> | ||||
|     : public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> { | ||||
|     using alloc_traits = std::allocator_traits<Allocator>; | ||||
|     static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type"); | ||||
|     using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>; | ||||
|     using comp_traits = component_traits<Type>; | ||||
|  | ||||
| public: | ||||
|     /*! @brief Base type. */ | ||||
|     using base_type = underlying_type; | ||||
|     /*! @brief Allocator type. */ | ||||
|     using allocator_type = Allocator; | ||||
|     /*! @brief Type of the objects assigned to entities. */ | ||||
|     using value_type = Type; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = Entity; | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using size_type = std::size_t; | ||||
|     /*! @brief Extended iterable storage proxy. */ | ||||
|     using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator>>; | ||||
|     /*! @brief Constant extended iterable storage proxy. */ | ||||
|     using const_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_iterator>>; | ||||
|  | ||||
|     /*! @brief Default constructor. */ | ||||
|     basic_storage() | ||||
|         : basic_storage{allocator_type{}} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an empty container with a given allocator. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     explicit basic_storage(const allocator_type &allocator) | ||||
|         : base_type{type_id<value_type>(), deletion_policy{comp_traits::in_place_delete}, allocator} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Move constructor. | ||||
|      * @param other The instance to move from. | ||||
|      */ | ||||
|     basic_storage(basic_storage &&other) noexcept = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Allocator-extended move constructor. | ||||
|      * @param other The instance to move from. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     basic_storage(basic_storage &&other, const allocator_type &allocator) noexcept | ||||
|         : base_type{std::move(other), allocator} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Move assignment operator. | ||||
|      * @param other The instance to move from. | ||||
|      * @return This storage. | ||||
|      */ | ||||
|     basic_storage &operator=(basic_storage &&other) noexcept = default; | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the associated allocator. | ||||
|      * @return The associated allocator. | ||||
|      */ | ||||
|     [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { | ||||
|         return allocator_type{base_type::get_allocator()}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the object assigned to an entity, that is `void`. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to use an entity that doesn't belong to the storage results in | ||||
|      * undefined behavior. | ||||
|      * | ||||
|      * @param entt A valid identifier. | ||||
|      */ | ||||
|     void get([[maybe_unused]] const entity_type entt) const noexcept { | ||||
|         ENTT_ASSERT(base_type::contains(entt), "Storage does not contain entity"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an empty tuple. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to use an entity that doesn't belong to the storage results in | ||||
|      * undefined behavior. | ||||
|      * | ||||
|      * @param entt A valid identifier. | ||||
|      * @return Returns an empty tuple. | ||||
|      */ | ||||
|     [[nodiscard]] std::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept { | ||||
|         ENTT_ASSERT(base_type::contains(entt), "Storage does not contain entity"); | ||||
|         return std::tuple{}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns an entity to a storage and constructs its object. | ||||
|      * | ||||
|      * @warning | ||||
|      * Attempting to use an entity that already belongs to the storage results | ||||
|      * in undefined behavior. | ||||
|      * | ||||
|      * @tparam Args Types of arguments to use to construct the object. | ||||
|      * @param entt A valid identifier. | ||||
|      */ | ||||
|     template<typename... Args> | ||||
|     void emplace(const entity_type entt, Args &&...) { | ||||
|         base_type::try_emplace(entt, false); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Updates the instance assigned to a given entity in-place. | ||||
|      * @tparam Func Types of the function objects to invoke. | ||||
|      * @param entt A valid identifier. | ||||
|      * @param func Valid function objects. | ||||
|      */ | ||||
|     template<typename... Func> | ||||
|     void patch([[maybe_unused]] const entity_type entt, Func &&...func) { | ||||
|         ENTT_ASSERT(base_type::contains(entt), "Storage does not contain entity"); | ||||
|         (std::forward<Func>(func)(), ...); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns entities to a storage. | ||||
|      * @tparam It Type of input iterator. | ||||
|      * @tparam Args Types of optional arguments. | ||||
|      * @param first An iterator to the first element of the range of entities. | ||||
|      * @param last An iterator past the last element of the range of entities. | ||||
|      */ | ||||
|     template<typename It, typename... Args> | ||||
|     void insert(It first, It last, Args &&...) { | ||||
|         for(; first != last; ++first) { | ||||
|             base_type::try_emplace(*first, true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns an iterable object to use to _visit_ a storage. | ||||
|      * | ||||
|      * The iterable object returns a tuple that contains the current entity. | ||||
|      * | ||||
|      * @return An iterable object to use to _visit_ the storage. | ||||
|      */ | ||||
|     [[nodiscard]] iterable each() noexcept { | ||||
|         return {internal::extended_storage_iterator{base_type::begin()}, internal::extended_storage_iterator{base_type::end()}}; | ||||
|     } | ||||
|  | ||||
|     /*! @copydoc each */ | ||||
|     [[nodiscard]] const_iterable each() const noexcept { | ||||
|         return {internal::extended_storage_iterator{base_type::cbegin()}, internal::extended_storage_iterator{base_type::cend()}}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										236
									
								
								external/entt/entt/src/entt/entity/storage_mixin.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								external/entt/entt/src/entt/entity/storage_mixin.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,236 @@ | ||||
| #ifndef ENTT_ENTITY_SIGH_STORAGE_MIXIN_HPP | ||||
| #define ENTT_ENTITY_SIGH_STORAGE_MIXIN_HPP | ||||
|  | ||||
| #include <utility> | ||||
| #include "../config/config.h" | ||||
| #include "../core/any.hpp" | ||||
| #include "../signal/sigh.hpp" | ||||
| #include "fwd.hpp" | ||||
|  | ||||
| namespace entt { | ||||
|  | ||||
| /** | ||||
|  * @brief Mixin type used to add signal support to storage types. | ||||
|  * | ||||
|  * The function type of a listener is equivalent to: | ||||
|  * | ||||
|  * @code{.cpp} | ||||
|  * void(basic_registry<entity_type> &, entity_type); | ||||
|  * @endcode | ||||
|  * | ||||
|  * This applies to all signals made available. | ||||
|  * | ||||
|  * @tparam Type The type of the underlying storage. | ||||
|  */ | ||||
| template<typename Type> | ||||
| class sigh_storage_mixin final: public Type { | ||||
|     using basic_registry_type = basic_registry<typename Type::entity_type, typename Type::base_type::allocator_type>; | ||||
|     using sigh_type = sigh<void(basic_registry_type &, const typename Type::entity_type), typename Type::allocator_type>; | ||||
|     using basic_iterator = typename Type::basic_iterator; | ||||
|  | ||||
|     void pop(basic_iterator first, basic_iterator last) override { | ||||
|         ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); | ||||
|  | ||||
|         for(; first != last; ++first) { | ||||
|             const auto entt = *first; | ||||
|             destruction.publish(*owner, entt); | ||||
|             const auto it = Type::find(entt); | ||||
|             Type::pop(it, it + 1u); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     basic_iterator try_emplace(const typename basic_registry_type::entity_type entt, const bool force_back, const void *value) final { | ||||
|         ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); | ||||
|         Type::try_emplace(entt, force_back, value); | ||||
|         construction.publish(*owner, entt); | ||||
|         return Type::find(entt); | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! @brief Allocator type. */ | ||||
|     using allocator_type = typename Type::allocator_type; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = typename Type::entity_type; | ||||
|     /*! @brief Expected registry type. */ | ||||
|     using registry_type = basic_registry_type; | ||||
|  | ||||
|     /*! @brief Default constructor. */ | ||||
|     sigh_storage_mixin() | ||||
|         : sigh_storage_mixin{allocator_type{}} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an empty storage with a given allocator. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     explicit sigh_storage_mixin(const allocator_type &allocator) | ||||
|         : Type{allocator}, | ||||
|           owner{}, | ||||
|           construction{allocator}, | ||||
|           destruction{allocator}, | ||||
|           update{allocator} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Move constructor. | ||||
|      * @param other The instance to move from. | ||||
|      */ | ||||
|     sigh_storage_mixin(sigh_storage_mixin &&other) noexcept | ||||
|         : Type{std::move(other)}, | ||||
|           owner{other.owner}, | ||||
|           construction{std::move(other.construction)}, | ||||
|           destruction{std::move(other.destruction)}, | ||||
|           update{std::move(other.update)} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Allocator-extended move constructor. | ||||
|      * @param other The instance to move from. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     sigh_storage_mixin(sigh_storage_mixin &&other, const allocator_type &allocator) noexcept | ||||
|         : Type{std::move(other), allocator}, | ||||
|           owner{other.owner}, | ||||
|           construction{std::move(other.construction), allocator}, | ||||
|           destruction{std::move(other.destruction), allocator}, | ||||
|           update{std::move(other.update), allocator} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Move assignment operator. | ||||
|      * @param other The instance to move from. | ||||
|      * @return This storage. | ||||
|      */ | ||||
|     sigh_storage_mixin &operator=(sigh_storage_mixin &&other) noexcept { | ||||
|         Type::operator=(std::move(other)); | ||||
|         owner = other.owner; | ||||
|         construction = std::move(other.construction); | ||||
|         destruction = std::move(other.destruction); | ||||
|         update = std::move(other.update); | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Exchanges the contents with those of a given storage. | ||||
|      * @param other Storage to exchange the content with. | ||||
|      */ | ||||
|     void swap(sigh_storage_mixin &other) { | ||||
|         using std::swap; | ||||
|         Type::swap(other); | ||||
|         swap(owner, other.owner); | ||||
|         swap(construction, other.construction); | ||||
|         swap(destruction, other.destruction); | ||||
|         swap(update, other.update); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns a sink object. | ||||
|      * | ||||
|      * The sink returned by this function can be used to receive notifications | ||||
|      * whenever a new instance is created and assigned to an entity.<br/> | ||||
|      * Listeners are invoked after the object has been assigned to the entity. | ||||
|      * | ||||
|      * @sa sink | ||||
|      * | ||||
|      * @return A temporary sink object. | ||||
|      */ | ||||
|     [[nodiscard]] auto on_construct() noexcept { | ||||
|         return sink{construction}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns a sink object. | ||||
|      * | ||||
|      * The sink returned by this function can be used to receive notifications | ||||
|      * whenever an instance is explicitly updated.<br/> | ||||
|      * Listeners are invoked after the object has been updated. | ||||
|      * | ||||
|      * @sa sink | ||||
|      * | ||||
|      * @return A temporary sink object. | ||||
|      */ | ||||
|     [[nodiscard]] auto on_update() noexcept { | ||||
|         return sink{update}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns a sink object. | ||||
|      * | ||||
|      * The sink returned by this function can be used to receive notifications | ||||
|      * whenever an instance is removed from an entity and thus destroyed.<br/> | ||||
|      * Listeners are invoked before the object has been removed from the entity. | ||||
|      * | ||||
|      * @sa sink | ||||
|      * | ||||
|      * @return A temporary sink object. | ||||
|      */ | ||||
|     [[nodiscard]] auto on_destroy() noexcept { | ||||
|         return sink{destruction}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns entities to a storage. | ||||
|      * @tparam Args Types of arguments to use to construct the object. | ||||
|      * @param entt A valid identifier. | ||||
|      * @param args Parameters to use to initialize the object. | ||||
|      * @return A reference to the newly created object. | ||||
|      */ | ||||
|     template<typename... Args> | ||||
|     decltype(auto) emplace(const entity_type entt, Args &&...args) { | ||||
|         ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); | ||||
|         Type::emplace(entt, std::forward<Args>(args)...); | ||||
|         construction.publish(*owner, entt); | ||||
|         return this->get(entt); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Patches the given instance for an entity. | ||||
|      * @tparam Func Types of the function objects to invoke. | ||||
|      * @param entt A valid identifier. | ||||
|      * @param func Valid function objects. | ||||
|      * @return A reference to the patched instance. | ||||
|      */ | ||||
|     template<typename... Func> | ||||
|     decltype(auto) patch(const entity_type entt, Func &&...func) { | ||||
|         ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); | ||||
|         Type::patch(entt, std::forward<Func>(func)...); | ||||
|         update.publish(*owner, entt); | ||||
|         return this->get(entt); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Assigns entities to a storage. | ||||
|      * @tparam It Type of input iterator. | ||||
|      * @tparam Args Types of arguments to use to construct the objects assigned | ||||
|      * to the entities. | ||||
|      * @param first An iterator to the first element of the range of entities. | ||||
|      * @param last An iterator past the last element of the range of entities. | ||||
|      * @param args Parameters to use to initialize the objects assigned to the | ||||
|      * entities. | ||||
|      */ | ||||
|     template<typename It, typename... Args> | ||||
|     void insert(It first, It last, Args &&...args) { | ||||
|         ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); | ||||
|         Type::insert(first, last, std::forward<Args>(args)...); | ||||
|  | ||||
|         for(auto it = construction.empty() ? last : first; it != last; ++it) { | ||||
|             construction.publish(*owner, *it); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Forwards variables to derived classes, if any. | ||||
|      * @param value A variable wrapped in an opaque container. | ||||
|      */ | ||||
|     void bind(any value) noexcept final { | ||||
|         auto *reg = any_cast<basic_registry_type>(&value); | ||||
|         owner = reg ? reg : owner; | ||||
|         Type::bind(std::move(value)); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     basic_registry_type *owner; | ||||
|     sigh_type construction; | ||||
|     sigh_type destruction; | ||||
|     sigh_type update; | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user