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