Compare commits
	
		
			226 Commits
		
	
	
		
			f077a29cf0
			...
			7194000
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 719400068a | |||
| aaf8c6adc1 | |||
| dc081ae2aa | |||
| 3cf3097094 | |||
| e801626232 | |||
| a5093c4aa3 | |||
| c311bb5c95 | |||
| 887705969f | |||
| 316871523d | |||
| a3d193516c | |||
| 6709dba0e7 | |||
| a8d8613f2c | |||
| aae086cc65 | |||
| 6ec6fe96e4 | |||
| 2d31b57097 | |||
| b1d4848b81 | |||
| 3678301916 | |||
| 459ccf7d6b | |||
| db54afd180 | |||
| f4fe94dfe6 | |||
| 28b92b0f4c | |||
| c966fc6954 | |||
| d0761bf60e | |||
| 0f41ee6a2e | |||
| 0aeafec019 | |||
| 9a0df4f577 | |||
| 61714836bb | |||
| cff0c100ec | |||
| 010c49d100 | |||
| ff5dbaffc0 | |||
| b56d581e4b | |||
| aa661aaaa7 | |||
| cc3f430bab | |||
| 139db5b03b | |||
| 7d0e5c80bd | |||
| f716ad9dd1 | |||
| 671772a20e | |||
| b0173f6d68 | |||
| 3da5872df8 | |||
| 3deb6e8469 | |||
| 0c674e0137 | |||
| 7948d820c3 | |||
| 5aac3422aa | |||
| e8eaa7a232 | |||
| 04b3382029 | |||
| 7fe6df5889 | |||
| 2647c85323 | |||
| 93140231c6 | |||
| e76e56e025 | |||
| b1062e701e | |||
| e72aebc043 | |||
| 865dfa994f | |||
| 25be42e308 | |||
| c6a0df409d | |||
| a15a9af2b3 | |||
| ca6909b64a | |||
| 5af8cfa879 | |||
| f701b7d2f8 | |||
| 852f2a6343 | |||
| 7359e30c3e | |||
| 61accfe184 | |||
| 5effe64474 | |||
| b1fe064484 | |||
| 2f44996edc | |||
| 18ca88a0d4 | |||
| 565aa4b7eb | |||
| b117da5ccf | |||
| 8eb4892b49 | |||
| 82fe4c3dd7 | |||
| 78b0e9a77f | |||
| 7fa6aa7ac2 | |||
| 20b4cdc5f1 | |||
| 7c576dd4d0 | |||
| f6cda522ca | |||
| 3d2f5b644b | |||
| 9ace11a0e2 | |||
| 6104d3b6d1 | |||
| f637c7c942 | |||
| afb886ea7c | |||
| 74129cabef | |||
| be8ceb861c | |||
| da0f59a3f5 | |||
| 000254320e | |||
| 2fac7206d2 | |||
| e8234f2a4a | |||
| a0ba0b39d8 | |||
| 845967cf12 | |||
| 92b58cbfa9 | |||
| 5a0651eaf0 | |||
| 14fcaf1d7e | |||
| 5a0252d8d0 | |||
| 9c0ffd38ce | |||
| b2ae9530a4 | |||
| ae1fb0fde3 | |||
| 35ebbbef93 | |||
| 83e200df43 | |||
| 260d3b7818 | |||
| 4ebffd8c63 | |||
| 8923e09b36 | |||
| ec4195f18a | |||
| 062ad7ae80 | |||
| aad07611c7 | |||
| 0dcb66f143 | |||
| 331c25b0e6 | |||
| e50844be06 | |||
| 4dd7c98c1a | |||
| 63bad2e99a | |||
| 9ddeea3d06 | |||
| b95f0498b6 | |||
| 7495a50723 | |||
| 1cdde5170b | |||
| 4248d1d9ab | |||
| 4f02c2b55b | |||
| 05d1648209 | |||
| fd9d14d00c | |||
| 4e4f62dd20 | |||
| cdc4284cb5 | |||
| bedbacddde | |||
| 32a8dba185 | |||
| d6e5051b15 | |||
| 780a67a40d | |||
| 0c7fff3029 | |||
| e7db39d20a | |||
| 869edb8d84 | |||
| dce42b866a | |||
| da19b0ac31 | |||
| bc090bdaa8 | |||
| 2a5937652e | |||
| b9d4f594ce | |||
| c79068c561 | |||
| e7095a1849 | |||
| 3f78e17888 | |||
| 897253e1d6 | |||
| cd28b26761 | |||
| a3126d581b | |||
| 1da4a12104 | |||
| 8725bafbdb | |||
| c24dc45e93 | |||
| 62b00a4bd6 | |||
| f1f67fe1ba | |||
| 621327bf55 | |||
| 9dabdd32fa | |||
| b479db4989 | |||
| 8633c5eafd | |||
| 440489f228 | |||
| bb824a9fb7 | |||
| c98dd8a584 | |||
| e12d7b1458 | |||
| 58edc97787 | |||
| ca6853e2c0 | |||
| fc90106d83 | |||
| 89bc11eca7 | |||
| 5c4c397f6c | |||
| da774e10e8 | |||
| 2f8eca71a4 | |||
| 90ce4bda4e | |||
| 4afe39dacc | |||
| dd316d2589 | |||
| 644725478f | |||
| 12e8b5d6c4 | |||
| f5c7261805 | |||
| 73ee0f905b | |||
| 0b46b891c2 | |||
| d131b5a02f | |||
| 9d9a486537 | |||
| 610ed10011 | |||
| 4edab11616 | |||
| 4d48f9d237 | |||
| 6df0417667 | |||
| bd9bbf67d4 | |||
| 8cab1307ab | |||
| 5bfc429450 | |||
| 7a7b55bebf | |||
| b4eda033c6 | |||
| c9672bf352 | |||
| 5547ff6d2b | |||
| ea8cc85c61 | |||
| 5ecec26731 | |||
| 01fddd19cd | |||
| e362af8271 | |||
| 2dba4f8fbb | |||
| bdfe44399a | |||
| 67653bbe50 | |||
| a144459e8d | |||
| d725ed8cd0 | |||
| 3cd551098b | |||
| 87d7eb69af | |||
| 95b77cb696 | |||
| 2e28ad7bb9 | |||
| 75f78f8c7f | |||
| ef59386e5c | |||
| c0b57c30bd | |||
| 42b3866753 | |||
| aff239377d | |||
| 3aaa1b0350 | |||
| 823a4ae189 | |||
| 40cd04f9dd | |||
| 6a979d31a0 | |||
| 56f7db9ae6 | |||
| d5e2dd2e1f | |||
| 93e5bb867b | |||
| 4cd295065b | |||
| 5a9aacc603 | |||
| 082c4febdf | |||
| a848a01527 | |||
| 3a1c15f313 | |||
| e92c7cbfa0 | |||
| 4d09e1fd4a | |||
| 07765b4ad7 | |||
| 88f6091665 | |||
| f66b8d3ea2 | |||
| a0122d38f2 | |||
| e4d2987c54 | |||
| dec0d4ec41 | |||
| b8e444eaa8 | |||
| b38ea75e56 | |||
| 8613511928 | |||
| 7650d0ff23 | |||
| 4ec6a26d91 | |||
| efa781e9ba | |||
| 41d0fc02c3 | |||
| 227425b90e | |||
| 5568b70d31 | |||
| 5c7231b7a3 | |||
| 310a099f14 | |||
| df9fc529e2 | 
							
								
								
									
										1
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| github: Green-Sky | ||||
							
								
								
									
										219
									
								
								.github/workflows/cd.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								.github/workflows/cd.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,219 @@ | ||||
| name: ContinuousDelivery | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: [ master ] | ||||
|   pull_request: | ||||
|     branches: [ master ] | ||||
|  | ||||
| env: | ||||
|   BUILD_TYPE: Release | ||||
|   BRANCH_NAME: ${{ github.head_ref || github.ref_name }} | ||||
|  | ||||
| jobs: | ||||
|   linux-ubuntu: | ||||
|     timeout-minutes: 10 | ||||
|  | ||||
|     runs-on: ubuntu-20.04 | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v3 | ||||
|       with: | ||||
|         submodules: recursive | ||||
|  | ||||
|     - name: Install Dependencies | ||||
|       run: sudo apt update && sudo apt -y install libsodium-dev | ||||
|  | ||||
|     - name: Configure CMake | ||||
|       run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} | ||||
|  | ||||
|     - name: Build | ||||
|       run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 | ||||
|  | ||||
|     - name: Determine tag name | ||||
|       id: tag | ||||
|       shell: bash | ||||
|       # taken from llama.cpp | ||||
|       run: | | ||||
|         SHORT_HASH="$(git rev-parse --short=7 HEAD)" | ||||
|         if [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then | ||||
|           echo "name=${SHORT_HASH}" >> $GITHUB_OUTPUT | ||||
|         else | ||||
|           SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-') | ||||
|           echo "name=${SAFE_NAME}-${SHORT_HASH}" >> $GITHUB_OUTPUT | ||||
|         fi | ||||
|  | ||||
|     - name: Compress artifacts | ||||
|       shell: bash | ||||
|       run: | | ||||
|         tar -czvf ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-ubuntu20.04-x86_64.tar.gz -C ${{github.workspace}}/build/bin/ . | ||||
|  | ||||
|     - uses: actions/upload-artifact@v4 | ||||
|       with: | ||||
|         # TODO: simpler name? | ||||
|         name: ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-ubuntu20.04-x86_64 | ||||
|         # TODO: do propper packing | ||||
|         path: | | ||||
|           ${{github.workspace}}/${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-ubuntu20.04-x86_64.tar.gz | ||||
|  | ||||
|  | ||||
|   windows: | ||||
|     timeout-minutes: 15 | ||||
|  | ||||
|     runs-on: windows-2019 | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v3 | ||||
|       with: | ||||
|         submodules: recursive | ||||
|  | ||||
|     - name: Install Dependencies | ||||
|       run: vcpkg install libsodium:x64-windows-static pthreads:x64-windows-static | ||||
|  | ||||
|     # setup vs env | ||||
|     - uses: ilammy/msvc-dev-cmd@v1 | ||||
|       with: | ||||
|         arch: amd64 | ||||
|  | ||||
|     - name: Configure CMake | ||||
|       run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static | ||||
|  | ||||
|     - name: Build | ||||
|       run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} | ||||
|  | ||||
|     - name: Determine tag name | ||||
|       id: tag | ||||
|       shell: bash | ||||
|       # taken from llama.cpp | ||||
|       run: | | ||||
|         SHORT_HASH="$(git rev-parse --short=7 HEAD)" | ||||
|         if [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then | ||||
|           echo "name=${SHORT_HASH}" >> $GITHUB_OUTPUT | ||||
|         else | ||||
|           SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-') | ||||
|           echo "name=${SAFE_NAME}-${SHORT_HASH}" >> $GITHUB_OUTPUT | ||||
|         fi | ||||
|  | ||||
|     - name: Compress artifacts | ||||
|       shell: powershell | ||||
|       run: | | ||||
|         Compress-Archive -Path ${{github.workspace}}/build/bin/* -Destination ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-x86_64.zip | ||||
|  | ||||
|     - uses: actions/upload-artifact@v4 | ||||
|       with: | ||||
|         # TODO: simpler name? | ||||
|         name: ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-x86_64 | ||||
|         # TODO: do propper packing | ||||
|         path: | | ||||
|           ${{github.workspace}}/${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-x86_64.zip | ||||
|  | ||||
|  | ||||
|   windows-asan: | ||||
|     timeout-minutes: 15 | ||||
|  | ||||
|     runs-on: windows-2019 | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v3 | ||||
|       with: | ||||
|         submodules: recursive | ||||
|  | ||||
|     - name: Install Dependencies | ||||
|       run: vcpkg install libsodium:x64-windows-static pthreads:x64-windows-static | ||||
|  | ||||
|     # setup vs env | ||||
|     - uses: ilammy/msvc-dev-cmd@v1 | ||||
|       with: | ||||
|         arch: amd64 | ||||
|  | ||||
|     - name: Configure CMake | ||||
|       run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static -DTOMATO_ASAN=ON -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded | ||||
|  | ||||
|     - name: Build | ||||
|       run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 | ||||
|  | ||||
|     - name: Determine tag name | ||||
|       id: tag | ||||
|       shell: bash | ||||
|       # taken from llama.cpp | ||||
|       run: | | ||||
|         SHORT_HASH="$(git rev-parse --short=7 HEAD)" | ||||
|         if [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then | ||||
|           echo "name=${SHORT_HASH}" >> $GITHUB_OUTPUT | ||||
|         else | ||||
|           SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-') | ||||
|           echo "name=${SAFE_NAME}-${SHORT_HASH}" >> $GITHUB_OUTPUT | ||||
|         fi | ||||
|  | ||||
|     - name: Compress artifacts | ||||
|       shell: powershell | ||||
|       run: | | ||||
|         Compress-Archive -Path ${{github.workspace}}/build/bin/* -Destination ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-asan-x86_64.zip | ||||
|  | ||||
|     - uses: actions/upload-artifact@v4 | ||||
|       with: | ||||
|         # TODO: simpler name? | ||||
|         name: ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-asan-x86_64 | ||||
|         # TODO: do propper packing | ||||
|         path: | | ||||
|           ${{github.workspace}}/${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-asan-x86_64.zip | ||||
|  | ||||
|   release: | ||||
|     if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) }} | ||||
|  | ||||
|     runs-on: ubuntu-latest | ||||
|  | ||||
|     needs: | ||||
|       - linux-ubuntu | ||||
|       - windows | ||||
|       - windows-asan | ||||
|  | ||||
|     permissions: | ||||
|       contents: write | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v3 | ||||
|       with: | ||||
|         submodules: recursive | ||||
|  | ||||
|     - name: Determine tag name | ||||
|       id: tag | ||||
|       shell: bash | ||||
|       # taken from llama.cpp | ||||
|       run: | | ||||
|         SHORT_HASH="$(git rev-parse --short=7 HEAD)" | ||||
|         if [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then | ||||
|           echo "name=${SHORT_HASH}" >> $GITHUB_OUTPUT | ||||
|         else | ||||
|           SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-') | ||||
|           echo "name=${SAFE_NAME}-${SHORT_HASH}" >> $GITHUB_OUTPUT | ||||
|         fi | ||||
|  | ||||
|     - name: Download artifacts | ||||
|       id: download-artifact | ||||
|       uses: actions/download-artifact@v4 | ||||
|       with: | ||||
|         path: ./artifacts/ | ||||
|  | ||||
|     - name: Create release | ||||
|       env: | ||||
|         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|         tag: ${{ steps.tag.outputs.name }} | ||||
|       shell: bash | ||||
|       run: | | ||||
|         gh release create "$tag" \ | ||||
|             --repo="$GITHUB_REPOSITORY" \ | ||||
|             --title="nightly ${tag#v}" \ | ||||
|             --notes="nightly build" \ | ||||
|             --prerelease | ||||
|  | ||||
|     - name: Upload artifacts | ||||
|       env: | ||||
|         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|         tag: ${{ steps.tag.outputs.name }} | ||||
|       shell: bash | ||||
|       run: | | ||||
|         ls -laR ./artifacts | ||||
|         gh release upload "$tag" ./artifacts/*/* \ | ||||
|             --repo="$GITHUB_REPOSITORY" | ||||
|  | ||||
							
								
								
									
										74
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| name: ContinuousIntegration | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: [ master ] | ||||
|   pull_request: | ||||
|     branches: [ master ] | ||||
|  | ||||
| env: | ||||
|   BUILD_TYPE: Debug | ||||
|  | ||||
| jobs: | ||||
|   linux: | ||||
|     timeout-minutes: 10 | ||||
|  | ||||
|     runs-on: ubuntu-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v3 | ||||
|       with: | ||||
|         submodules: recursive | ||||
|  | ||||
|     - name: Install Dependencies | ||||
|       run: sudo apt update && sudo apt -y install libsodium-dev | ||||
|  | ||||
|     - name: Configure CMake | ||||
|       run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} | ||||
|  | ||||
|     - name: Build | ||||
|       run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 | ||||
|  | ||||
|   macos: | ||||
|     timeout-minutes: 10 | ||||
|  | ||||
|     runs-on: macos-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v3 | ||||
|       with: | ||||
|         submodules: recursive | ||||
|  | ||||
|     - name: Install Dependencies | ||||
|       run: brew install libsodium | ||||
|  | ||||
|     - name: Configure CMake | ||||
|       run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} | ||||
|  | ||||
|     - name: Build | ||||
|       run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 | ||||
|  | ||||
|   windows: | ||||
|     timeout-minutes: 10 | ||||
|  | ||||
|     runs-on: windows-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v3 | ||||
|       with: | ||||
|         submodules: recursive | ||||
|  | ||||
|     - name: Install Dependencies | ||||
|       run: vcpkg install libsodium:x64-windows-static pthreads:x64-windows-static | ||||
|  | ||||
|     # setup vs env | ||||
|     - uses: ilammy/msvc-dev-cmd@v1 | ||||
|       with: | ||||
|         arch: amd64 | ||||
|  | ||||
|     - name: Configure CMake | ||||
|       run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static | ||||
|  | ||||
|     - name: Build | ||||
|       run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 | ||||
|  | ||||
							
								
								
									
										26
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| .vs/ | ||||
| *.o | ||||
| *.swp | ||||
| ~* | ||||
| *~ | ||||
| .idea/ | ||||
| cmake-build-debug/ | ||||
| cmake-build-debugandtest/ | ||||
| cmake-build-release/ | ||||
| *.stackdump | ||||
| *.coredump | ||||
| compile_commands.json | ||||
| /build* | ||||
| /result* | ||||
| .clangd | ||||
| .cache | ||||
|  | ||||
| .DS_Store | ||||
| .AppleDouble | ||||
| .LSOverride | ||||
|  | ||||
| CMakeLists.txt.user* | ||||
| CMakeCache.txt | ||||
|  | ||||
| *.tox | ||||
| imgui.ini | ||||
							
								
								
									
										4
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,7 @@ | ||||
| [submodule "external/toxcore/c-toxcore/third_party/cmp"] | ||||
| 	path = external/toxcore/c-toxcore/third_party/cmp | ||||
| 	url = https://github.com/camgunz/cmp.git | ||||
| 	shallow = true | ||||
| [submodule "external/solanaceae_toxcore"] | ||||
| 	path = external/solanaceae_toxcore | ||||
| 	url = https://github.com/Green-Sky/solanaceae_toxcore.git | ||||
|   | ||||
							
								
								
									
										67
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| cmake_minimum_required(VERSION 3.14...3.24 FATAL_ERROR) | ||||
|  | ||||
| # cmake setup begin | ||||
| project(tomato) | ||||
|  | ||||
| set(CMAKE_POSITION_INDEPENDENT_CODE ON) | ||||
|  | ||||
| # defaulting to debug mode, if not specified | ||||
| if (NOT CMAKE_BUILD_TYPE) | ||||
| 	set(CMAKE_BUILD_TYPE "Debug") | ||||
| endif() | ||||
|  | ||||
| # setup my vim ycm :D | ||||
| set(CMAKE_EXPORT_COMPILE_COMMANDS ON) | ||||
|  | ||||
| # more paths | ||||
| set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") | ||||
| set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") | ||||
| set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") | ||||
|  | ||||
| option(TOMATO_ASAN "Build tomato with asan (gcc/clang/msvc)" OFF) | ||||
|  | ||||
| if (TOMATO_ASAN) | ||||
| 	if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") | ||||
| 		if (NOT WIN32) # exclude mingw | ||||
| 			link_libraries(-fsanitize=address) | ||||
| 			#link_libraries(-fsanitize=address,undefined) | ||||
| 			#link_libraries(-fsanitize=undefined) | ||||
| 			message("II enabled ASAN") | ||||
| 		else() | ||||
| 			message("!! can not enable ASAN on this platform (gcc/clang + win)") | ||||
| 		endif() | ||||
| 	elseif (MSVC) | ||||
| 		add_compile_options("/fsanitize=address") | ||||
| 		message("II enabled ASAN") | ||||
| 	else() | ||||
| 		message("!! can not enable ASAN on this platform") | ||||
| 	endif() | ||||
| endif() | ||||
|  | ||||
| # external libs | ||||
| add_subdirectory(./external) # before increasing warn levels, sad :( | ||||
|  | ||||
| set(CMAKE_CXX_EXTENSIONS OFF) | ||||
|  | ||||
| # bump up warning levels appropriately for clang, gcc & msvc | ||||
| if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") | ||||
| 	add_compile_options( | ||||
| 		-Wall -Wextra # Reasonable and standard | ||||
| 		-Wpedantic # Warn if non-standard C++ is used | ||||
| 		-Wunused # Warn on anything being unused | ||||
| 		#-Wconversion # Warn on type conversions that may lose data | ||||
| 		#-Wsign-conversion # Warn on sign conversions | ||||
| 		-Wshadow # Warn if a variable declaration shadows one from a parent context | ||||
| 	) | ||||
| elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") | ||||
| 	if (MSVC) | ||||
| 		string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") | ||||
| 	else() | ||||
| 		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") | ||||
| 	endif() | ||||
| endif() | ||||
|  | ||||
| # cmake setup end | ||||
|  | ||||
| add_subdirectory(./src) | ||||
|  | ||||
							
								
								
									
										8
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| # Tomato | ||||
|  | ||||
|  | ||||
|  | ||||
| ## Highly experimental solanaceae client with Tox built-in | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										7
									
								
								external/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								external/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @@ -12,3 +12,10 @@ add_subdirectory(./toxcore) | ||||
| add_subdirectory(./solanaceae_toxcore) | ||||
| add_subdirectory(./solanaceae_tox) | ||||
|  | ||||
| add_subdirectory(./sdl) | ||||
| add_subdirectory(./imgui) | ||||
|  | ||||
| add_subdirectory(./stb) | ||||
| add_subdirectory(./libwebp) | ||||
| add_subdirectory(./qoi) | ||||
|  | ||||
|   | ||||
							
								
								
									
										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 | ||||
							
								
								
									
										61
									
								
								external/entt/entt/.github/workflows/analyzer.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								external/entt/entt/.github/workflows/analyzer.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| name: analyzer | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|       - wip | ||||
|  | ||||
| jobs: | ||||
|  | ||||
|   iwyu: | ||||
|     timeout-minutes: 30 | ||||
|  | ||||
|     env: | ||||
|       IWYU: 0.19 | ||||
|       LLVM: 15 | ||||
|  | ||||
|     runs-on: ubuntu-latest | ||||
|     continue-on-error: true | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v3 | ||||
|     - 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 -DCMAKE_C_COMPILER=clang-$LLVM \ | ||||
|               -DCMAKE_CXX_COMPILER=clang++-$LLVM \ | ||||
|               -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 | ||||
							
								
								
									
										144
									
								
								external/entt/entt/.github/workflows/build.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								external/entt/entt/.github/workflows/build.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | ||||
| name: build | ||||
|  | ||||
| on: [push, pull_request] | ||||
|  | ||||
| jobs: | ||||
|  | ||||
|   linux: | ||||
|     timeout-minutes: 15 | ||||
|  | ||||
|     strategy: | ||||
|       matrix: | ||||
|         os: [ubuntu-latest, ubuntu-20.04] | ||||
|         compiler: | ||||
|           - { pkg: g++, exe: 'g++', version: 7 } | ||||
|           - { pkg: g++, exe: 'g++', version: 8 } | ||||
|           - { pkg: g++, exe: 'g++', version: 9 } | ||||
|           - { pkg: g++, exe: 'g++', version: 10 } | ||||
|           - { pkg: g++, exe: 'g++', version: 11 } | ||||
|           - { pkg: g++, exe: 'g++', version: 12 } | ||||
|           - { pkg: clang, exe: 'clang++', version: 8 } | ||||
|           - { pkg: clang, exe: 'clang++', version: 9 } | ||||
|           - { pkg: clang, exe: 'clang++', version: 10 } | ||||
|           - { pkg: clang, exe: 'clang++', version: 11 } | ||||
|           - { pkg: clang, exe: 'clang++', version: 12 } | ||||
|           - { pkg: clang, exe: 'clang++', version: 13 } | ||||
|           - { pkg: clang, exe: 'clang++', version: 14 } | ||||
|         exclude: | ||||
|           - os: ubuntu-latest | ||||
|             compiler: { pkg: g++, exe: 'g++', version: 7 } | ||||
|           - os: ubuntu-latest | ||||
|             compiler: { pkg: g++, exe: 'g++', version: 8 } | ||||
|           - os: ubuntu-latest | ||||
|             compiler: { pkg: g++, exe: 'g++', version: 9 } | ||||
|           - os: ubuntu-latest | ||||
|             compiler: { pkg: clang, exe: 'clang++', version: 8 } | ||||
|           - os: ubuntu-latest | ||||
|             compiler: { pkg: clang, exe: 'clang++', version: 9 } | ||||
|           - os: ubuntu-latest | ||||
|             compiler: { pkg: clang, exe: 'clang++', version: 10 } | ||||
|           - os: ubuntu-latest | ||||
|             compiler: { pkg: clang, exe: 'clang++', version: 11 } | ||||
|           - os: ubuntu-20.04 | ||||
|             compiler: { pkg: g++, exe: 'g++', version: 10 } | ||||
|           - os: ubuntu-20.04 | ||||
|             compiler: { pkg: g++, exe: 'g++', version: 11 } | ||||
|           - os: ubuntu-20.04 | ||||
|             compiler: { pkg: g++, exe: 'g++', version: 12 } | ||||
|           - os: ubuntu-20.04 | ||||
|             compiler: { pkg: clang, exe: 'clang++', version: 12 } | ||||
|           - os: ubuntu-20.04 | ||||
|             compiler: { pkg: clang, exe: 'clang++', version: 13 } | ||||
|           - os: ubuntu-20.04 | ||||
|             compiler: { pkg: clang, exe: 'clang++', version: 14 } | ||||
|  | ||||
|     runs-on: ${{ matrix.os }} | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v3 | ||||
|     - name: Install compiler | ||||
|       run: | | ||||
|         sudo apt update | ||||
|         sudo apt install -y ${{ matrix.compiler.pkg }}-${{ matrix.compiler.version }} | ||||
|     - name: Compile tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CXX: ${{ matrix.compiler.exe }}-${{ matrix.compiler.version }} | ||||
|       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 | ||||
|  | ||||
|   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@v3 | ||||
|     - 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 | ||||
|  | ||||
|   macos: | ||||
|     timeout-minutes: 15 | ||||
|     runs-on: macOS-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v3 | ||||
|     - 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 | ||||
|  | ||||
|   extra: | ||||
|     timeout-minutes: 15 | ||||
|  | ||||
|     strategy: | ||||
|       matrix: | ||||
|         os: [windows-latest, macOS-latest, ubuntu-latest] | ||||
|         id_type: ["std::uint32_t", "std::uint64_t"] | ||||
|         cxx_std: [cxx_std_17, cxx_std_20] | ||||
|  | ||||
|     runs-on: ${{ matrix.os }} | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v3 | ||||
|     - 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 | ||||
							
								
								
									
										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@v3 | ||||
|     - name: Compile tests | ||||
|       working-directory: build | ||||
|       env: | ||||
|         CXXFLAGS: "--coverage -fno-elide-constructors -fno-inline -fno-default-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@v3 | ||||
|       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@v3 | ||||
|     - 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@v3 | ||||
|     - 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.15.7) | ||||
|  | ||||
| # | ||||
| # 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-2023 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/mixin.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/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-2023 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. | ||||
							
								
								
									
										428
									
								
								external/entt/entt/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										428
									
								
								external/entt/entt/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,428 @@ | ||||
|  | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| [](https://github.com/skypjack/entt/actions) | ||||
| [](https://codecov.io/gh/skypjack/entt) | ||||
| [](https://godbolt.org/z/zxW73f) | ||||
| [](https://vcpkg.link/ports/entt) | ||||
| [](https://skypjack.github.io/entt/) | ||||
| [](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 is created in HTML format in the `build/docs/html` directory. | ||||
| 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.<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` downloads and compiles 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-2023 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/). | ||||
							
								
								
									
										26
									
								
								external/entt/entt/TODO
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								external/entt/entt/TODO
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| EXAMPLES | ||||
| * filter on runtime values/variables (not only types) | ||||
| * support to polymorphic types (see #859) | ||||
|  | ||||
| DOC: | ||||
| * custom storage/view | ||||
| * examples (and credits) from @alanjfs :) | ||||
| * update entity doc when the storage based model is in place | ||||
| * in-place O(1) release/destroy for non-orphaned entities, out-of-sync model | ||||
|  | ||||
| TODO (high prio): | ||||
| * check natvis files (periodically :) | ||||
| * resource cache: avoid using shared ptr with loader and the others | ||||
| * further optimize exclusion lists in multi type views (no existence check) | ||||
| * further improve the snapshot stuff, ie component functions | ||||
| * use fixture for storage tests to reduce loc number and duplication as much as possible | ||||
| * basic_view<...>::reach(...) | ||||
| * doc: bump entities | ||||
|  | ||||
| WIP: | ||||
| * get rid of observers, storage based views made them pointless - document alternatives | ||||
| * exploit the tombstone mechanism to allow enabling/disabling entities (see bump, compact and clear for further details) | ||||
| * process scheduler: reviews, use free lists internally | ||||
| * deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views | ||||
| * bring nested groups back in place (see bd34e7f) | ||||
| * work stealing job system (see #100) + mt scheduler based on const awareness for types | ||||
							
								
								
									
										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() | ||||
							
								
								
									
										54
									
								
								external/entt/entt/docs/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								external/entt/entt/docs/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| # | ||||
| # Doxygen configuration (documentation) | ||||
| # | ||||
|  | ||||
| FetchContent_Declare( | ||||
|     doxygen-awesome-css | ||||
|     GIT_REPOSITORY https://github.com/jothepro/doxygen-awesome-css | ||||
|     GIT_TAG main | ||||
|     GIT_SHALLOW 1 | ||||
| ) | ||||
|  | ||||
| FetchContent_GetProperties(doxygen-awesome-css) | ||||
|  | ||||
| if(NOT doxygen-awesome-css_POPULATED) | ||||
|     FetchContent_Populate(doxygen-awesome-css) | ||||
|     set(doxygen-awesome-css_INCLUDE_DIR ${doxygen-awesome-css_SOURCE_DIR}) | ||||
| endif() | ||||
|  | ||||
| set(DOXY_SOURCE_DIRECTORY ${EnTT_SOURCE_DIR}/src) | ||||
| set(DOXY_CSS_DIRECTORY ${doxygen-awesome-css_INCLUDE_DIR}) | ||||
| 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. | ||||
|  */ | ||||
							
								
								
									
										2726
									
								
								external/entt/entt/docs/doxy.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2726
									
								
								external/entt/entt/docs/doxy.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										120
									
								
								external/entt/entt/docs/md/config.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								external/entt/entt/docs/md/config.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| # 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. | ||||
							
								
								
									
										66
									
								
								external/entt/entt/docs/md/container.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								external/entt/entt/docs/md/container.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| # 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 functionalities 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, | ||||
| the `std::unordered_map` class.<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, the `std::unordered_set` class.<br/> | ||||
| Therefore, there is no need to go into the API description. | ||||
							
								
								
									
										986
									
								
								external/entt/entt/docs/md/core.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										986
									
								
								external/entt/entt/docs/md/core.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,986 @@ | ||||
| # Crash Course: core functionalities | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
| * [Any as in any type](#any-as-in-any-type) | ||||
|   * [Small buffer optimization](#small-buffer-optimization) | ||||
|   * [Alignment requirement](#alignment-requirement) | ||||
| * [Compressed pair](#compressed-pair) | ||||
| * [Enum as bitmask](#enum-as-bitmask) | ||||
| * [Hashed strings](#hashed-strings) | ||||
|   * [Wide characters](wide-characters) | ||||
|   * [Conflicts](#conflicts) | ||||
| * [Iterators](#iterators) | ||||
|   * [Input iterator pointer](#input-iterator-pointer) | ||||
|   * [Iota iterator](#iota-iterator) | ||||
|   * [Iterable adaptor](#iterable-adaptor) | ||||
| * [Memory](#memory) | ||||
|   * [Power of two and fast modulus](#power-of-two-and-fast-modulus) | ||||
|   * [Allocator aware unique pointers](#allocator-aware-unique-pointers) | ||||
| * [Monostate](#monostate) | ||||
| * [Type support](#type-support) | ||||
|   * [Built-in RTTI support](#built-in-rtti-support) | ||||
|     * [Type info](#type-info) | ||||
|     * [Almost unique identifiers](#almost-unique-identifiers) | ||||
|   * [Type traits](#type-traits) | ||||
|     * [Size of](#size-of) | ||||
|     * [Is applicable](#is-applicable) | ||||
|     * [Constness as](#constness-as) | ||||
|     * [Member class type](#member-class-type) | ||||
|     * [N-th argument](#n-th-argument) | ||||
|     * [Integral constant](#integral-constant) | ||||
|     * [Tag](#tag) | ||||
|     * [Type list and value list](#type-list-and-value-list) | ||||
| * [Unique sequential identifiers](#unique-sequential-identifiers) | ||||
|   * [Compile-time generator](#compile-time-generator) | ||||
|   * [Runtime generator](#runtime-generator) | ||||
| * [Utilities](#utilities) | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| `EnTT` comes with a bunch of core functionalities mostly used by the other parts | ||||
| of the library.<br/> | ||||
| Many of these tools are also useful in everyday work. Therefore, it's worth | ||||
| describing them so as not to reinvent the wheel in case of need. | ||||
|  | ||||
| # Any as in any type | ||||
|  | ||||
| `EnTT` offers its own `any` type. It may seem redundant considering that C++17 | ||||
| introduced `std::any`, but it is not (hopefully).<br/> | ||||
| First of all, the _type_ returned by an `std::any` is a const reference to an | ||||
| `std::type_info`, an implementation defined class that's not something everyone | ||||
| wants to see in a software. Furthermore, there is no way to bind it to the type | ||||
| system of the library and therefore with its integrated RTTI support. | ||||
|  | ||||
| The `any` API is very similar to that of its most famous counterpart, mainly | ||||
| because this class serves the same purpose of being an opaque container for any | ||||
| type of value.<br/> | ||||
| Instances also minimize the number of allocations by relying on a well known | ||||
| technique called _small buffer optimization_ and a fake vtable. | ||||
|  | ||||
| Creating an object of the `any` type, whether empty or not, is trivial: | ||||
|  | ||||
| ```cpp | ||||
| // an empty container | ||||
| entt::any empty{}; | ||||
|  | ||||
| // a container for an int | ||||
| entt::any any{0}; | ||||
|  | ||||
| // in place construction | ||||
| entt::any in_place{std::in_place_type<int>, 42}; | ||||
| ``` | ||||
|  | ||||
| Alternatively, the `make_any` function serves the same purpose but requires to | ||||
| always be explicit about the type: | ||||
|  | ||||
| ```cpp | ||||
| entt::any any = entt::make_any<int>(42); | ||||
| ``` | ||||
|  | ||||
| In both cases, the `any` class takes the burden of destroying the contained | ||||
| element when required, regardless of the storage strategy used for the specific | ||||
| object.<br/> | ||||
| Furthermore, an instance of `any` isn't tied to an actual type. Therefore, the | ||||
| wrapper is reconfigured when it's assigned a new object of a type other than | ||||
| the one it contains. | ||||
|  | ||||
| There is also a way to directly assign a value to the variable contained by an | ||||
| `entt::any`, without necessarily replacing it. This is especially useful when | ||||
| the object is used in _aliasing mode_, as described below: | ||||
|  | ||||
| ```cpp | ||||
| entt::any any{42}; | ||||
| entt::any value{3}; | ||||
|  | ||||
| // assigns by copy | ||||
| any.assign(value); | ||||
|  | ||||
| // assigns by move | ||||
| any.assign(std::move(value)); | ||||
| ``` | ||||
|  | ||||
| The `any` class performs a check on the type information and whether or not the | ||||
| original type was copy or move assignable, as appropriate.<br/> | ||||
| In all cases, the `assign` function returns a boolean value that is true in case | ||||
| of success and false otherwise. | ||||
|  | ||||
| When in doubt about the type of object contained, the `type` member function | ||||
| returns a const reference to the `type_info` associated with its element, or | ||||
| `type_id<void>()` if the container is empty.<br/> | ||||
| The type is also used internally when comparing two `any` objects: | ||||
|  | ||||
| ```cpp | ||||
| if(any == empty) { /* ... */ } | ||||
| ``` | ||||
|  | ||||
| In this case, before proceeding with a comparison, it's verified that the _type_ | ||||
| of the two objects is actually the same.<br/> | ||||
| Refer to the `EnTT` type system documentation for more details about how | ||||
| `type_info` works and the possible risks of a comparison. | ||||
|  | ||||
| A particularly interesting feature of this class is that it can also be used as | ||||
| an opaque container for const and non-const references: | ||||
|  | ||||
| ```cpp | ||||
| int value = 42; | ||||
|  | ||||
| entt::any any{std::in_place_type<int &>(value)}; | ||||
| entt::any cany = entt::make_any<const int &>(value); | ||||
| entt::any fwd = entt::forward_as_any(value); | ||||
|  | ||||
| any.emplace<const int &>(value); | ||||
| ``` | ||||
|  | ||||
| In other words, whenever `any` is explicitly told to construct an _alias_, it | ||||
| acts as a pointer to the original instance rather than making a copy of it or | ||||
| moving it internally. The contained object is never destroyed and users must | ||||
| ensure that its lifetime exceeds that of the container.<br/> | ||||
| Similarly, it's possible to create non-owning copies of `any` from an existing | ||||
| object: | ||||
|  | ||||
| ```cpp | ||||
| // aliasing constructor | ||||
| entt::any ref = other.as_ref(); | ||||
| ``` | ||||
|  | ||||
| In this case, it doesn't matter if the original container actually holds an | ||||
| object or is as a reference for unmanaged elements already. The new instance | ||||
| thus created doesn't create copies and only serves as a reference for the | ||||
| original item. | ||||
|  | ||||
| It's worth mentioning that, while everything works transparently when it comes | ||||
| to non-const references, there are some exceptions when it comes to const | ||||
| references.<br/> | ||||
| In particular, the `data` member function invoked on a non-const instance of | ||||
| `any` that wraps a const reference returns a null pointer in all cases. | ||||
|  | ||||
| To cast an instance of `any` to a type, the library offers a set of `any_cast` | ||||
| functions in all respects similar to their most famous counterparts.<br/> | ||||
| The only difference is that, in the case of `EnTT`, they won't raise exceptions | ||||
| but will only trigger an assert in debug mode, otherwise resulting in undefined | ||||
| behavior in case of misuse in release mode. | ||||
|  | ||||
| ## Small buffer optimization | ||||
|  | ||||
| The `any` class uses a technique called _small buffer optimization_ to reduce | ||||
| the number of allocations where possible.<br/> | ||||
| The default reserved size for an instance of `any` is `sizeof(double[2])`. | ||||
| However, this is also configurable if needed. In fact, `any` is defined as an | ||||
| alias for `basic_any<Len>`, where `Len` is the size above.<br/> | ||||
| Users can easily set a custom size or define their own aliases: | ||||
|  | ||||
| ```cpp | ||||
| using my_any = entt::basic_any<sizeof(double[4])>; | ||||
| ``` | ||||
|  | ||||
| This feature, in addition to allowing the choice of a size that best suits the | ||||
| needs of an application, also offers the possibility of forcing dynamic creation | ||||
| of objects during construction.<br/> | ||||
| In other terms, if the size is 0, `any` suppresses the small buffer optimization | ||||
| and always dynamically allocates objects (except for aliasing cases). | ||||
|  | ||||
| ## Alignment requirement | ||||
|  | ||||
| The alignment requirement is optional and by default the most stringent (the | ||||
| largest) for any object whose size is at most equal to the one provided.<br/> | ||||
| It's provided as an optional second parameter following the desired size for the | ||||
| internal storage: | ||||
|  | ||||
| ```cpp | ||||
| using my_any = entt::basic_any<sizeof(double[4]), alignof(double[4])>; | ||||
| ``` | ||||
|  | ||||
| The `basic_any` class template inspects the alignment requirements in each case, | ||||
| even when not provided and may decide not to use the small buffer optimization | ||||
| in order to meet them. | ||||
|  | ||||
| # Compressed pair | ||||
|  | ||||
| Primarily designed for internal use and far from being feature complete, the | ||||
| `compressed_pair` class does exactly what it promises: it tries to reduce the | ||||
| size of a pair by exploiting _Empty Base Class Optimization_ (or _EBCO_).<br/> | ||||
| This class **is not** a drop-in replacement for `std::pair`. However, it offers | ||||
| enough functionalities to be a good alternative for when reducing memory usage | ||||
| is more important than having some cool and probably useless feature. | ||||
|  | ||||
| Although the API is very close to that of `std::pair` (apart from the fact that | ||||
| the template parameters are inferred from the constructor and therefore there is | ||||
| no `entt::make_compressed_pair`), the major difference is that `first` and | ||||
| `second` are functions for implementation requirements: | ||||
|  | ||||
| ```cpp | ||||
| entt::compressed_pair pair{0, 3.}; | ||||
| pair.first() = 42; | ||||
| ``` | ||||
|  | ||||
| There isn't much to describe then. It's recommended to rely on documentation and | ||||
| intuition. At the end of the day, it's just a pair and nothing more. | ||||
|  | ||||
| # Enum as bitmask | ||||
|  | ||||
| Sometimes it's useful to be able to use enums as bitmasks. However, enum classes | ||||
| aren't really suitable for the purpose. Main problem is that they don't convert | ||||
| implicitly to their underlying type.<br/> | ||||
| The choice is then between using old-fashioned enums (with all their problems | ||||
| that I don't want to discuss here) or writing _ugly_ code. | ||||
|  | ||||
| Fortunately, there is also a third way: adding enough operators in the global | ||||
| scope to treat enum classes as bitmasks transparently.<br/> | ||||
| The ultimate goal is to write code like the following (or maybe something more | ||||
| meaningful, but this should give a grasp and remain simple at the same time): | ||||
|  | ||||
| ```cpp | ||||
| enum class my_flag { | ||||
|     unknown = 0x01, | ||||
|     enabled = 0x02, | ||||
|     disabled = 0x04 | ||||
| }; | ||||
|  | ||||
| const my_flag flags = my_flag::enabled; | ||||
| const bool is_enabled = !!(flags & my_flag::enabled); | ||||
| ``` | ||||
|  | ||||
| The problem with adding all operators to the global scope is that these come | ||||
| into play even when not required, with the risk of introducing errors that are | ||||
| difficult to deal with.<br/> | ||||
| However, C++ offers enough tools to get around this problem. In particular, the | ||||
| library requires users to register the enum classes for which bitmask support | ||||
| should be enabled: | ||||
|  | ||||
| ```cpp | ||||
| template<> | ||||
| struct entt::enum_as_bitmask<my_flag> | ||||
|     : std::true_type | ||||
| {}; | ||||
| ``` | ||||
|  | ||||
| This is handy when dealing with enum classes defined by third party libraries | ||||
| and over which the user has no control. However, it's also verbose and can be | ||||
| avoided by adding a specific value to the enum class itself: | ||||
|  | ||||
| ```cpp | ||||
| enum class my_flag { | ||||
|     unknown = 0x01, | ||||
|     enabled = 0x02, | ||||
|     disabled = 0x04, | ||||
|     _entt_enum_as_bitmask | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| In this case, there is no need to specialize the `enum_as_bitmask` traits, since | ||||
| `EnTT` automatically detects the flag and enables the bitmask support.<br/> | ||||
| Once the enum class is registered (in one way or the other), the most common | ||||
| operators such as `&`, `|` but also `&=` and `|=` are available for use. | ||||
|  | ||||
| Refer to the official documentation for the full list of operators. | ||||
|  | ||||
| # Hashed strings | ||||
|  | ||||
| Hashed strings are human-readable identifiers in the codebase that turn into | ||||
| numeric values at runtime, thus without affecting performance.<br/> | ||||
| The class has an implicit `constexpr` constructor that chews a bunch of | ||||
| characters. Once created, one can get the original string by means of the `data` | ||||
| member function or convert the instance into a number.<br/> | ||||
| A hashed string is well suited wherever a constant expression is required. No | ||||
| _string-to-number_ conversion will take place at runtime if used carefully. | ||||
|  | ||||
| Example of use: | ||||
|  | ||||
| ```cpp | ||||
| auto load(entt::hashed_string::hash_type resource) { | ||||
|     // uses the numeric representation of the resource to load and return it | ||||
| } | ||||
|  | ||||
| auto resource = load(entt::hashed_string{"gui/background"}); | ||||
| ``` | ||||
|  | ||||
| There is also a _user defined literal_ dedicated to hashed strings to make them | ||||
| more _user-friendly_: | ||||
|  | ||||
| ```cpp | ||||
| using namespace entt::literals; | ||||
| constexpr auto str = "text"_hs; | ||||
| ``` | ||||
|  | ||||
| User defined literals in `EnTT` are enclosed in the `entt::literals` namespace. | ||||
| Therefore, the entire namespace or selectively the literal of interest must be | ||||
| explicitly included before each use, a bit like `std::literals`.<br/> | ||||
| The class also offers the necessary functionalities to create hashed strings at | ||||
| runtime: | ||||
|  | ||||
| ```cpp | ||||
| std::string orig{"text"}; | ||||
|  | ||||
| // create a full-featured hashed string... | ||||
| entt::hashed_string str{orig.c_str()}; | ||||
|  | ||||
| // ... or compute only the unique identifier | ||||
| const auto hash = entt::hashed_string::value(orig.c_str()); | ||||
| ``` | ||||
|  | ||||
| This possibility shouldn't be exploited in tight loops, since the computation | ||||
| takes place at runtime and no longer at compile-time. It could therefore affect | ||||
| performance to some degrees. | ||||
|  | ||||
| ## Wide characters | ||||
|  | ||||
| The `hashed_string` class is an alias  for `basic_hashed_string<char>`. To use | ||||
| the C++ type for wide character representations, there exists also the alias | ||||
| `hashed_wstring` for `basic_hashed_string<wchar_t>`.<br/> | ||||
| In this case, the user defined literal to use to create hashed strings on the | ||||
| fly is `_hws`: | ||||
|  | ||||
| ```cpp | ||||
| constexpr auto str = L"text"_hws; | ||||
| ``` | ||||
|  | ||||
| The hash type of `hashed_wstring` is the same as its counterpart. | ||||
|  | ||||
| ## Conflicts | ||||
|  | ||||
| The hashed string class uses FNV-1a internally to hash strings. Because of the | ||||
| _pigeonhole principle_, conflicts are possible. This is a fact.<br/> | ||||
| There is no silver bullet to solve the problem of conflicts when dealing with | ||||
| hashing functions. In this case, the best solution is likely to give up. That's | ||||
| all.<br/> | ||||
| After all, human-readable unique identifiers aren't something strictly defined | ||||
| and over which users have not the control. Choosing a slightly different | ||||
| identifier is probably the best solution to make the conflict disappear in this | ||||
| case. | ||||
|  | ||||
| # Iterators | ||||
|  | ||||
| Writing and working with iterators isn't always easy. More often than not it | ||||
| also leads to duplicated code.<br/> | ||||
| `EnTT` tries to overcome this problem by offering some utilities designed to | ||||
| make this hard work easier. | ||||
|  | ||||
| ## Input iterator pointer | ||||
|  | ||||
| When writing an input iterator that returns in-place constructed values if | ||||
| dereferenced, it's not always straightforward to figure out what `value_type` is | ||||
| and how to make it behave like a full-fledged pointer.<br/> | ||||
| Conversely, it would be very useful to have an `operator->` available on the | ||||
| iterator itself that always works without too much complexity. | ||||
|  | ||||
| The input iterator pointer is meant for this. It's a small class that wraps the | ||||
| in-place constructed value and adds some functions on top of it to make it | ||||
| suitable for use with input iterators:  | ||||
|  | ||||
| ```cpp | ||||
| struct iterator_type { | ||||
|     using value_type = std::pair<first_type, second_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; | ||||
|  | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The library makes extensive use of this class internally. In many cases, the | ||||
| `value_type` of the returned iterators is just an input iterator pointer. | ||||
|  | ||||
| ## Iota iterator | ||||
|  | ||||
| Waiting for C++20, this iterator accepts an integral value and returns all | ||||
| elements in a certain range: | ||||
|  | ||||
| ```cpp | ||||
| entt::iota_iterator first{0}; | ||||
| entt::iota_iterator last{100}; | ||||
|  | ||||
| for(; first != last; ++first) { | ||||
|     int value = *first; | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| In the future, views will replace this class. Meanwhile, the library makes some | ||||
| interesting uses of it when a range of integral values is to be returned to the | ||||
| user. | ||||
|  | ||||
| ## Iterable adaptor | ||||
|  | ||||
| Typically, a container class provides `begin` and `end` member functions (with | ||||
| their const counterparts) for iteration.<br/> | ||||
| However, it can happen that a class offers multiple iteration methods or allows | ||||
| users to iterate different sets of _elements_. | ||||
|  | ||||
| The iterable adaptor is a utility class that makes it easier to use and access | ||||
| data in this case.<br/> | ||||
| It accepts a couple of iterators (or an iterator and a sentinel) and offers an | ||||
| _iterable_ object with all the expected methods like `begin`, `end` and whatnot. | ||||
|  | ||||
| The library uses this class extensively.<br/> | ||||
| Think for example of views, which can be iterated to access entities but also | ||||
| offer a method of obtaining an iterable object that returns tuples of entities | ||||
| and components at once.<br/> | ||||
| Another example is the registry class which allows users to iterate its storage | ||||
| by returning an iterable object for the purpose. | ||||
|  | ||||
| # Memory | ||||
|  | ||||
| There are a handful of tools within `EnTT` to interact with memory in one way or | ||||
| another.<br/> | ||||
| Some are geared towards simplifying the implementation of (internal or external) | ||||
| allocator aware containers. Others are designed to help the developer with | ||||
| everyday problems. | ||||
|  | ||||
| The former are very specific and for niche problems. These are tools designed to | ||||
| unwrap fancy or plain pointers (`to_address`) or to help forget the meaning of | ||||
| acronyms like _POCCA_, _POCMA_ or _POCS_.<br/> | ||||
| I won't describe them here in detail. Instead, I recommend reading the inline | ||||
| documentation to those interested in the subject. | ||||
|  | ||||
| ## Power of two and fast modulus | ||||
|  | ||||
| Finding out if a number is a power of two (`is_power_of_two`) or what the next | ||||
| power of two is given a random value (`next_power_of_two`) is very useful at | ||||
| times.<br/> | ||||
| For example, it helps to allocate memory in pages having a size suitable for the | ||||
| fast modulus: | ||||
|  | ||||
| ```cpp | ||||
| const std::size_t result = entt::fast_mod(value, modulus); | ||||
| ``` | ||||
|  | ||||
| Where `modulus` is necessarily a power of two. Perhaps not everyone knows that | ||||
| this type of operation is far superior in terms of performance to the basic | ||||
| modulus and for this reason preferred in many areas. | ||||
|  | ||||
| ## Allocator aware unique pointers | ||||
|  | ||||
| A nasty thing in C++ (at least up to C++20) is the fact that shared pointers | ||||
| support allocators while unique pointers don't.<br/> | ||||
| There is a proposal at the moment that also shows (among the other things) how | ||||
| this can be implemented without any compiler support. | ||||
|  | ||||
| The `allocate_unique` function follows this proposal, making a virtue out of | ||||
| necessity: | ||||
|  | ||||
| ```cpp | ||||
| std::unique_ptr<my_type, entt::allocation_deleter<my_type>> ptr = entt::allocate_unique<my_type>(allocator, arguments); | ||||
| ``` | ||||
|  | ||||
| Although the internal implementation is slightly different from what is proposed | ||||
| for the standard, this function offers an API that is a drop-in replacement for | ||||
| the same feature. | ||||
|  | ||||
| # Monostate | ||||
|  | ||||
| The monostate pattern is often presented as an alternative to a singleton based | ||||
| configuration system.<br/> | ||||
| This is exactly its purpose in `EnTT`. Moreover, this implementation is thread | ||||
| safe by design (hopefully). | ||||
|  | ||||
| Keys are integral values (easily obtained by hashed strings), values are basic | ||||
| types like `int`s or `bool`s. Values of different types can be associated with | ||||
| each key, even more than one at a time.<br/> | ||||
| Because of this, one should pay attention to use the same type both during an | ||||
| assignment and when trying to read back the data. Otherwise, there is the risk | ||||
| to incur in unexpected results. | ||||
|  | ||||
| Example of use: | ||||
|  | ||||
| ```cpp | ||||
| entt::monostate<entt::hashed_string{"mykey"}>{} = true; | ||||
| entt::monostate<"mykey"_hs>{} = 42; | ||||
|  | ||||
| // ... | ||||
|  | ||||
| const bool b = entt::monostate<"mykey"_hs>{}; | ||||
| const int i = entt::monostate<entt::hashed_string{"mykey"}>{}; | ||||
| ``` | ||||
|  | ||||
| # Type support | ||||
|  | ||||
| `EnTT` provides some basic information about types of all kinds.<br/> | ||||
| It also offers additional features that are not yet available in the standard | ||||
| library or that will never be. | ||||
|  | ||||
| ## Built-in RTTI support | ||||
|  | ||||
| Runtime type identification support (or RTTI) is one of the most frequently | ||||
| disabled features in the C++ world, especially in the gaming sector. Regardless | ||||
| of the reasons for this, it's often a shame not to be able to rely on opaque | ||||
| type information at runtime.<br/> | ||||
| The library tries to fill this gap by offering a built-in system that doesn't | ||||
| serve as a replacement but comes very close to being one and offers similar | ||||
| information to that provided by its counterpart. | ||||
|  | ||||
| Basically, the whole system relies on a handful of classes. In particular: | ||||
|  | ||||
| * The unique sequential identifier associated with a given type: | ||||
|  | ||||
|   ```cpp | ||||
|   auto index = entt::type_index<a_type>::value(); | ||||
|   ``` | ||||
|  | ||||
|   The returned value isn't guaranteed to be stable across different runs.<br/> | ||||
|   However, it can be very useful as index in associative and unordered | ||||
|   associative containers or for positional accesses in a vector or an array. | ||||
|    | ||||
|   An external generator can also be used if needed. In fact, `type_index` can be | ||||
|   specialized by type and is also _sfinae-friendly_ in order to allow more | ||||
|   refined specializations such as: | ||||
|    | ||||
|   ```cpp | ||||
|   template<typename Type> | ||||
|   struct entt::type_index<Type, std::void_d<decltype(Type::index())>> { | ||||
|       static entt::id_type value() noexcept { | ||||
|           return Type::index(); | ||||
|       } | ||||
|   }; | ||||
|   ``` | ||||
|    | ||||
|   Indexes **must** be sequentially generated in this case.<br/> | ||||
|   The tool is widely used within `EnTT`. Generating indices not sequentially | ||||
|   would break an assumption and would likely lead to undesired behaviors. | ||||
|  | ||||
| * The hash value associated with a given type: | ||||
|  | ||||
|   ```cpp | ||||
|   auto hash = entt::type_hash<a_type>::value(); | ||||
|   ``` | ||||
|  | ||||
|   In general, the `value` function exposed by `type_hash` is also `constexpr` | ||||
|   but this isn't guaranteed for all compilers and platforms (although it's valid | ||||
|   with the most well-known and popular ones). | ||||
|  | ||||
|   This function **can** use non-standard features of the language for its own | ||||
|   purposes. This makes it possible to provide compile-time identifiers that | ||||
|   remain stable across different runs.<br/> | ||||
|   Users can prevent the library from using these features by means of the | ||||
|   `ENTT_STANDARD_CPP` definition. In this case, there is no guarantee that | ||||
|   identifiers remain stable across executions. Moreover, they are generated | ||||
|   at runtime and are no longer a compile-time thing. | ||||
|  | ||||
|   As it happens with `type_index`, also `type_hash` is a _sfinae-friendly_ class | ||||
|   that can be specialized in order to customize its behavior globally or on a | ||||
|   per-type or per-traits basis. | ||||
|  | ||||
| * The name associated with a given type: | ||||
|  | ||||
|   ```cpp | ||||
|   auto name = entt::type_name<a_type>::value(); | ||||
|   ``` | ||||
|  | ||||
|   This value is extracted from some information generally made available by the | ||||
|   compiler in use. Therefore, it may differ depending on the compiler and may be | ||||
|   empty in the event that this information isn't available.<br/> | ||||
|   For example, given the following class: | ||||
|  | ||||
|   ```cpp | ||||
|   struct my_type { /* ... */ }; | ||||
|   ``` | ||||
|  | ||||
|   The name is `my_type` when compiled with GCC or CLang and `struct my_type` | ||||
|   when MSVC is in use.<br/> | ||||
|   Most of the time the name is also retrieved at compile-time and is therefore | ||||
|   always returned through an `std::string_view`. Users can easily access it and | ||||
|   modify it as needed, for example by removing the word `struct` to normalize | ||||
|   the result. `EnTT` doesn't do this for obvious reasons, since it would be | ||||
|   creating a new string at runtime otherwise. | ||||
|  | ||||
|   This function **can** use non-standard features of the language for its own | ||||
|   purposes. Users can prevent the library from using these features by means of | ||||
|   the `ENTT_STANDARD_CPP` definition. In this case, the name is just empty. | ||||
|  | ||||
|   As it happens with `type_index`, also `type_name` is a _sfinae-friendly_ class | ||||
|   that can be specialized in order to customize its behavior globally or on a | ||||
|   per-type or per-traits basis. | ||||
|  | ||||
| These are then combined into utilities that aim to offer an API that is somewhat | ||||
| similar to that made available by the standard library. | ||||
|  | ||||
| ### Type info | ||||
|  | ||||
| The `type_info` class isn't a drop-in replacement for `std::type_info` but can | ||||
| provide similar information which are not implementation defined and don't | ||||
| require to enable RTTI.<br/> | ||||
| Therefore, they can sometimes be even more reliable than those obtained | ||||
| otherwise. | ||||
|  | ||||
| Its type defines an opaque class that is also copyable and movable.<br/> | ||||
| Objects of this type are generally returned by the `type_id` functions: | ||||
|  | ||||
| ```cpp | ||||
| // by type | ||||
| auto info = entt::type_id<a_type>(); | ||||
|  | ||||
| // by value | ||||
| auto other = entt::type_id(42); | ||||
| ``` | ||||
|  | ||||
| All elements thus received are nothing more than const references to instances | ||||
| of `type_info` with static storage duration.<br/> | ||||
| This is convenient for saving the entire object aside for the cost of a pointer. | ||||
| However, nothing prevents from constructing `type_info` objects directly: | ||||
|  | ||||
| ```cpp | ||||
| entt::type_info info{std::in_place_type<int>}; | ||||
| ``` | ||||
|  | ||||
| These are the information made available by `type_info`: | ||||
|  | ||||
| * The index associated with a given type: | ||||
|  | ||||
|   ```cpp | ||||
|   auto idx = entt::type_id<a_type>().index(); | ||||
|   ``` | ||||
|  | ||||
|   This is also an alias for the following: | ||||
|  | ||||
|   ```cpp | ||||
|   auto idx = entt::type_index<std::remove_cv_t<std::remove_reference_t<a_type>>>::value(); | ||||
|   ``` | ||||
|  | ||||
| * The hash value associated with a given type: | ||||
|  | ||||
|   ```cpp | ||||
|   auto hash = entt::type_id<a_type>().hash(); | ||||
|   ``` | ||||
|  | ||||
|   This is also an alias for the following: | ||||
|  | ||||
|   ```cpp | ||||
|   auto hash = entt::type_hash<std::remove_cv_t<std::remove_reference_t<a_type>>>::value(); | ||||
|   ``` | ||||
|  | ||||
| * The name associated with a given type: | ||||
|  | ||||
|   ```cpp | ||||
|   auto name = entt::type_id<my_type>().name(); | ||||
|   ``` | ||||
|  | ||||
|   This is also an alias for the following: | ||||
|  | ||||
|   ```cpp | ||||
|   auto name = entt::type_name<std::remove_cv_t<std::remove_reference_t<a_type>>>::value(); | ||||
|   ``` | ||||
|  | ||||
| Where all accessed features are available at compile-time, the `type_info` class | ||||
| is also fully `constexpr`. However, this cannot be guaranteed in advance and | ||||
| depends mainly on the compiler in use and any specializations of the classes | ||||
| described above. | ||||
|  | ||||
| ### Almost unique identifiers | ||||
|  | ||||
| Since the default non-standard, compile-time implementation of `type_hash` makes | ||||
| use of hashed strings, it may happen that two types are assigned the same hash | ||||
| value.<br/> | ||||
| In fact, although this is quite rare, it's not entirely excluded. | ||||
|  | ||||
| Another case where two types are assigned the same identifier is when classes | ||||
| from different contexts (for example two or more libraries loaded at runtime) | ||||
| have the same fully qualified name. In this case, `type_name` returns the same | ||||
| value for the two types.<br/> | ||||
| Fortunately, there are several easy ways to deal with this: | ||||
|  | ||||
| * The most trivial one is to define the `ENTT_STANDARD_CPP` macro. Runtime | ||||
|   identifiers don't suffer from the same problem in fact. However, this solution | ||||
|   doesn't work well with a plugin system, where the libraries aren't linked. | ||||
|  | ||||
| * Another possibility is to specialize the `type_name` class for one of the | ||||
|   conflicting types, in order to assign it a custom identifier. This is probably | ||||
|   the easiest solution that also preserves the feature of the tool. | ||||
|  | ||||
| * A fully customized identifier generation policy (based for example on enum | ||||
|   classes or preprocessing steps) may represent yet another option. | ||||
|  | ||||
| These are just some examples of possible approaches to the problem but there are | ||||
| many others. As already mentioned above, since users have full control over | ||||
| their types, this problem is in any case easy to solve and should not worry too | ||||
| much.<br/> | ||||
| In all likelihood, it will never happen to run into a conflict anyway. | ||||
|  | ||||
| ## Type traits | ||||
|  | ||||
| A handful of utilities and traits not present in the standard template library | ||||
| but which can be useful in everyday life.<br/> | ||||
| This list **is not** exhaustive and contains only some of the most useful | ||||
| classes. Refer to the inline documentation for more information on the features | ||||
| offered by this module. | ||||
|  | ||||
| ### Size of | ||||
|  | ||||
| The standard operator `sizeof` complains if users provide it with functions or | ||||
| incomplete types. On the other hand, it's guaranteed that its result is always | ||||
| non-zero, even if applied to an empty class type.<br/> | ||||
| This small class combines the two and offers an alternative to `sizeof` that | ||||
| works under all circumstances, returning zero if the type isn't supported: | ||||
|  | ||||
| ```cpp | ||||
| const auto size = entt::size_of_v<void>; | ||||
| ``` | ||||
|  | ||||
| ### Is applicable | ||||
|  | ||||
| The standard library offers the great `std::is_invocable` trait in several | ||||
| forms. This takes a function type and a series of arguments and returns true if | ||||
| the condition is satisfied.<br/> | ||||
| Moreover, users are also provided with `std::apply`, a tool for combining | ||||
| invocable elements and tuples of arguments. | ||||
|  | ||||
| It would therefore be a good idea to have a variant of `std::is_invocable` that | ||||
| also accepts its arguments in the form of a tuple-like type, so as to complete | ||||
| the offer: | ||||
|  | ||||
| ```cpp | ||||
| constexpr bool result = entt::is_applicable<Func, std::tuple<a_type, another_type>>; | ||||
| ``` | ||||
|  | ||||
| This trait is built on top of `std::is_invocable` and does nothing but unpack a | ||||
| tuple-like type and simplify the code at the call site. | ||||
|  | ||||
| ### Constness as | ||||
|  | ||||
| A utility to easily transfer the constness of a type to another type: | ||||
|  | ||||
| ```cpp | ||||
| // type is const dst_type because of the constness of src_type | ||||
| using type = entt::constness_as_t<dst_type, const src_type>; | ||||
| ``` | ||||
|  | ||||
| The trait is subject to the rules of the language. For example, _transferring_ | ||||
| constness between references won't give the desired effect. | ||||
|  | ||||
| ### Member class type | ||||
|  | ||||
| The `auto` template parameter introduced with C++17 made it possible to simplify | ||||
| many class templates and template functions but also made the class type opaque | ||||
| when members are passed as template arguments.<br/> | ||||
| The purpose of this utility is to extract the class type in a few lines of code: | ||||
|  | ||||
| ```cpp | ||||
| template<typename Member> | ||||
| using clazz = entt::member_class_t<Member>; | ||||
| ``` | ||||
|  | ||||
| ### N-th argument | ||||
|  | ||||
| A utility to quickly find the n-th argument of a function, member function or | ||||
| data member (for blind operations on opaque types): | ||||
|  | ||||
| ```cpp | ||||
| using type = entt::nth_argument_t<1u, &clazz::member>; | ||||
| ``` | ||||
|  | ||||
| Disambiguation of overloaded functions is the responsibility of the user, should | ||||
| it be needed. | ||||
|  | ||||
| ### Integral constant | ||||
|  | ||||
| Since `std::integral_constant` may be annoying because of its form that requires | ||||
| to specify both a type and a value of that type, there is a more user-friendly | ||||
| shortcut for the creation of integral constants.<br/> | ||||
| This shortcut is the alias template `entt::integral_constant`: | ||||
|  | ||||
| ```cpp | ||||
| constexpr auto constant = entt::integral_constant<42>; | ||||
| ``` | ||||
|  | ||||
| Among the other uses, when combined with a hashed string it helps to define tags | ||||
| as human-readable _names_ where actual types would be required otherwise: | ||||
|  | ||||
| ```cpp | ||||
| constexpr auto enemy_tag = entt::integral_constant<"enemy"_hs>; | ||||
| registry.emplace<enemy_tag>(entity); | ||||
| ``` | ||||
|  | ||||
| ### Tag | ||||
|  | ||||
| Type `id_type` is very important and widely used in `EnTT`. Therefore, there is | ||||
| a more user-friendly shortcut for the creation of constants based on it.<br/> | ||||
| This shortcut is the alias template `entt::tag`. | ||||
|  | ||||
| If used in combination with hashed strings, it helps to use human-readable names | ||||
| where types would be required otherwise. As an example: | ||||
|  | ||||
| ```cpp | ||||
| registry.emplace<entt::tag<"enemy"_hs>>(entity); | ||||
| ``` | ||||
|  | ||||
| However, this isn't the only permitted use. Literally any value convertible to | ||||
| `id_type` is a good candidate, such as the named constants of an unscoped enum. | ||||
|  | ||||
| ### Type list and value list | ||||
|  | ||||
| There is no respectable library where the much desired _type list_ can be | ||||
| missing.<br/> | ||||
| `EnTT` is no exception and provides (making extensive use of it internally) the | ||||
| `type_list` type, in addition to its `value_list` counterpart dedicated to | ||||
| non-type template parameters. | ||||
|  | ||||
| Here is a (possibly incomplete) list of the functionalities that come with a | ||||
| type list: | ||||
|  | ||||
| * `type_list_element[_t]` to get the N-th element of a type list. | ||||
| * `type_list_index[_v]` to get the index of a given element of a type list. | ||||
| * `type_list_cat[_t]` and a handy `operator+` to concatenate type lists. | ||||
| * `type_list_unique[_t]` to remove duplicate types from a type list. | ||||
| * `type_list_contains[_v]` to know if a type list contains a given type. | ||||
| * `type_list_diff[_t]` to remove types from type lists. | ||||
| * `type_list_transform[_t]` to _transform_ a range and create another type list. | ||||
|  | ||||
| I'm also pretty sure that more and more utilities will be added over time as | ||||
| needs become apparent.<br/> | ||||
| Many of these functionalities also exist in their version dedicated to value | ||||
| lists. We therefore have `value_list_element[_v]` as well as | ||||
| `value_list_cat[_t]`and so on. | ||||
|  | ||||
| # Unique sequential identifiers | ||||
|  | ||||
| Sometimes it's useful to be able to give unique, sequential numeric identifiers | ||||
| to types either at compile-time or runtime.<br/> | ||||
| There are plenty of different solutions for this out there and I could have used | ||||
| one of them. However, I decided to spend my time to define a couple of tools | ||||
| that fully embraces what the modern C++ has to offer. | ||||
|  | ||||
| ## Compile-time generator | ||||
|  | ||||
| To generate sequential numeric identifiers at compile-time, `EnTT` offers the | ||||
| `ident` class template: | ||||
|  | ||||
| ```cpp | ||||
| // defines the identifiers for the given types | ||||
| using id = entt::ident<a_type, another_type>; | ||||
|  | ||||
| // ... | ||||
|  | ||||
| switch(a_type_identifier) { | ||||
| case id::value<a_type>: | ||||
|     // ... | ||||
|     break; | ||||
| case id::value<another_type>: | ||||
|     // ... | ||||
|     break; | ||||
| default: | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| This is what this class template has to offer: a `value` inline variable that | ||||
| contains a numeric identifier for the given type. It can be used in any context | ||||
| where constant expressions are required. | ||||
|  | ||||
| As long as the list remains unchanged, identifiers are also guaranteed to be | ||||
| stable across different runs. In case they have been used in a production | ||||
| environment and a type has to be removed, one can just use a placeholder to | ||||
| leave the other identifiers unchanged: | ||||
|  | ||||
| ```cpp | ||||
| template<typename> struct ignore_type {}; | ||||
|  | ||||
| using id = entt::ident< | ||||
|     a_type_still_valid, | ||||
|     ignore_type<no_longer_valid_type>, | ||||
|     another_type_still_valid | ||||
| >; | ||||
| ``` | ||||
|  | ||||
| Perhaps a bit ugly to see in a codebase but it gets the job done at least. | ||||
|  | ||||
| ## Runtime generator | ||||
|  | ||||
| The `family` class template helps to generate sequential numeric identifiers for | ||||
| types at runtime: | ||||
|  | ||||
| ```cpp | ||||
| // defines a custom generator | ||||
| using id = entt::family<struct my_tag>; | ||||
|  | ||||
| // ... | ||||
|  | ||||
| const auto a_type_id = id::value<a_type>; | ||||
| const auto another_type_id = id::value<another_type>; | ||||
| ``` | ||||
|  | ||||
| This is what a _family_ has to offer: a `value` inline variable that contains a | ||||
| numeric identifier for the given type.<br/> | ||||
| The generator is customizable, so as to get different _sequences_ for different | ||||
| purposes if needed. | ||||
|  | ||||
| Identifiers aren't guaranteed to be stable across different runs. Indeed it | ||||
| mostly depends on the flow of execution. | ||||
|  | ||||
| # Utilities | ||||
|  | ||||
| It's not possible to escape the temptation to add utilities of some kind to a | ||||
| library. In fact, `EnTT` also provides a handful of tools to simplify the | ||||
| life of developers: | ||||
|  | ||||
| * `entt::identity`: the identity function object that will be available with | ||||
|   C++20. It returns its argument unchanged and nothing more. It's useful as a | ||||
|   sort of _do nothing_ function in template programming. | ||||
|  | ||||
| * `entt::overload`: a tool to disambiguate different overloads from their | ||||
|   function type. It works with both free and member functions.<br/> | ||||
|   Consider the following definition: | ||||
|  | ||||
|   ```cpp | ||||
|   struct clazz { | ||||
|       void bar(int) {} | ||||
|       void bar() {} | ||||
|   }; | ||||
|   ``` | ||||
|  | ||||
|   This utility can be used to get the _right_ overload as: | ||||
|  | ||||
|   ```cpp | ||||
|   auto *member = entt::overload<void(int)>(&clazz::bar); | ||||
|   ``` | ||||
|  | ||||
|   The line above is literally equivalent to: | ||||
|  | ||||
|   ```cpp | ||||
|   auto *member = static_cast<void(clazz:: *)(int)>(&clazz::bar); | ||||
|   ``` | ||||
|  | ||||
|   Just easier to read and shorter to type. | ||||
|  | ||||
| * `entt::overloaded`: a small class template used to create a new type with an | ||||
|   overloaded `operator()` from a bunch of lambdas or functors.<br/> | ||||
|   As an example: | ||||
|  | ||||
|   ```cpp | ||||
|   entt::overloaded func{ | ||||
|       [](int value) { /* ... */ }, | ||||
|       [](char value) { /* ... */ } | ||||
|   }; | ||||
|  | ||||
|   func(42); | ||||
|   func('c'); | ||||
|   ``` | ||||
|  | ||||
|   Rather useful when doing metaprogramming and having to pass to a function a | ||||
|   callable object that supports multiple types at once. | ||||
|  | ||||
| * `entt::y_combinator`: this is a C++ implementation of **the** _y-combinator_. | ||||
|   If it's not clear what it is, there is probably no need for this utility.<br/> | ||||
|   Below is a small example to show its use: | ||||
|  | ||||
|   ```cpp | ||||
|   entt::y_combinator gauss([](const auto &self, auto value) -> unsigned int { | ||||
|       return value ? (value + self(value-1u)) : 0; | ||||
|   }); | ||||
|  | ||||
|   const auto result = gauss(3u); | ||||
|   ``` | ||||
|  | ||||
|   Maybe convoluted at a first glance but certainly effective. Unfortunately, | ||||
|   the language doesn't make it possible to do much better. | ||||
|  | ||||
| This is a rundown of the (actually few) utilities made available by `EnTT`. The | ||||
| list will probably grow over time but the size of each will remain rather small, | ||||
| as has been the case so far. | ||||
							
								
								
									
										2344
									
								
								external/entt/entt/docs/md/entity.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2344
									
								
								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 | ||||
|  | ||||
| Storage classes offer 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. | ||||
							
								
								
									
										372
									
								
								external/entt/entt/docs/md/graph.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										372
									
								
								external/entt/entt/docs/md/graph.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,372 @@ | ||||
| # 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 though. 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 takes 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 was newly inserted or not. The | ||||
| second one returns the number of deleted elements (0 or 1). | ||||
|  | ||||
| An adjacency matrix is 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()) { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The same result is obtained with the following snippet, since the vertices are | ||||
| plain 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 is used to get them as pairs of | ||||
| vertices: | ||||
|  | ||||
| ```cpp | ||||
| for(auto [lhs, rhs]: adjacency_matrix.edges()) { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| If the goal is to visit all the in- or out-edges of a given vertex instead, the | ||||
| `in_edges` and `out_edges` functions are meant for that: | ||||
|  | ||||
| ```cpp | ||||
| for(auto [lhs, rhs]: adjacency_matrix.out_edges(3u)) { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Both the 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 functionalities 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); | ||||
| ``` | ||||
|  | ||||
| It's also possible to provide a callback to which the vertices are passed and | ||||
| which can be used to add (`dot`) properties to the output as needed: | ||||
|  | ||||
| ```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 | ||||
| externally managed data 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 are 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 is 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`. | ||||
| In other terms, 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 is created (which requires no constructor arguments), the | ||||
| first thing to do is to bind a task. This tells to the builder _who_ intends to | ||||
| consume the resources that are specified immediately after: | ||||
|  | ||||
| ```cpp | ||||
| entt::flow builder{}; | ||||
| builder.bind("task_1"_hs); | ||||
| ``` | ||||
|  | ||||
| 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 isn't 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 necessary. | ||||
|  | ||||
| Once a task is associated with the flow builder, it's also 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, they 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. | ||||
|  | ||||
| ### Rebinding | ||||
|  | ||||
| The `flow` class is resource based rather than task based. This means that graph | ||||
| generation is driven by resources and not by the order of _appearance_ of tasks | ||||
| during flow definition.<br/> | ||||
| Although this concept is particularly important, it's almost irrelevant for the | ||||
| vast majority of cases. However, it becomes relevant when _rebinding_ resources | ||||
| or tasks. | ||||
|  | ||||
| In fact, nothing prevents rebinding elements to a flow.<br/> | ||||
| However, the behavior changes slightly from case to case and has some nuances | ||||
| that it's worth knowing about. | ||||
|  | ||||
| Directly rebinding a resource without the task being replaced trivially results | ||||
| in the task's access mode for that resource being updated: | ||||
|  | ||||
| ```cpp | ||||
| builder.bind("task"_hs).rw("resource"_hs).ro("resource"_hs) | ||||
| ``` | ||||
|  | ||||
| In this case, the resource is accessed in read-only mode, regardless of the | ||||
| first call to `rw`.<br/> | ||||
| Behind the scenes, the call doesn't actually _replace_ the previous one but is | ||||
| queued after it instead, overwriting it when generating the graph. Thus, a large | ||||
| number of resource rebindings may even impact processing times (very difficult | ||||
| to observe but theoretically possible). | ||||
|  | ||||
| Rebinding resources and also combining it with changes to tasks has far more | ||||
| implications instead.<br/> | ||||
| As mentioned, graph generation takes place starting from resources and not from | ||||
| tasks. Therefore, the result may not be as expected: | ||||
|  | ||||
| ```cpp | ||||
| builder | ||||
|     .bind("task_1"_hs) | ||||
|         .ro("resource"_hs) | ||||
|     .bind("task_2"_hs) | ||||
|         .ro("resource"_hs) | ||||
|     .bind("task_1"_hs) | ||||
|         .rw("resource"_hs); | ||||
| ``` | ||||
|  | ||||
| What happens here is that the resource first _sees_ a read-only access request | ||||
| from the first task, then a read-write request from the second task and finally | ||||
| a new read-only request from the first task.<br/> | ||||
| Although this definition would probably be counted as an error, the resulting | ||||
| graph may be unexpected. This in fact consists of a single edge outgoing from | ||||
| the second task and directed to the first task.<br/> | ||||
| To intuitively understand what happens, it's enough to think of the fact that a | ||||
| task never has an edge pointing to itself. | ||||
|  | ||||
| While not obvious, this approach has its pros and cons like any other solution. | ||||
| For example, creating loops is actually simple in the context of resource-based | ||||
| graph generations: | ||||
|  | ||||
| ```cpp | ||||
| builder | ||||
|     .bind("task_1"_hs) | ||||
|         .rw("resource"_hs) | ||||
|     .bind("task_2"_hs) | ||||
|         .rw("resource"_hs) | ||||
|     .bind("task_1"_hs) | ||||
|         .rw("resource"_hs); | ||||
| ``` | ||||
|  | ||||
| As expected, this definition leads to the creation of two edges that define a | ||||
| loop between the two tasks. | ||||
|  | ||||
| As a general rule, rebinding resources and tasks is highly discouraged because | ||||
| it could lead to subtle bugs if users don't know what they're doing.<br/> | ||||
| However, once the mechanisms of resource-based graph generation are understood, | ||||
| it can offer to the expert user a flexibility and a range of possibilities | ||||
| otherwise inaccessible. | ||||
|  | ||||
| ## 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 rule on | ||||
| the execution order: | ||||
|  | ||||
| ```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_1` **before** `task_2` and `task_3`. | ||||
| This is due to the fact that the former 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(); | ||||
| ``` | ||||
|  | ||||
| Searching 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()) { | ||||
|         // ... | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Then it's possible to instantiate an execution graph by means of other functions | ||||
| such as `out_edges` to retrieve the children of a given task or `edges` to get | ||||
| the identifiers. | ||||
							
								
								
									
										97
									
								
								external/entt/entt/docs/md/lib.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								external/entt/entt/docs/md/lib.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| # 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 `EnTT` works smoothly across boundaries. | ||||
|  | ||||
| ## Smooth until proven otherwise | ||||
|  | ||||
| Many classes in `EnTT` make extensive use of type erasure for their purposes. | ||||
| This raises the need to identify objects whose type has been erased.<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` are 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 those who need more details, the test suite contains many 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 _replacing_ the main context doesn't also propagate changes across | ||||
| boundaries. In other words, replacing 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. | ||||
							
								
								
									
										304
									
								
								external/entt/entt/docs/md/links.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								external/entt/entt/docs/md/links.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,304 @@ | ||||
| # EnTT in Action | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
| * [EnTT in Action](#entt-in-action) | ||||
|   * [Games](#games) | ||||
|   * [Engines and the like](#engines-and-the-like) | ||||
|   * [Articles, videos and blog posts](#articles-videos-and-blog-posts) | ||||
|   * [Any Other Business](#any-other-business) | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| `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.<br/> | ||||
| 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. | ||||
|  | ||||
| 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.<br/> | ||||
| I hope the following lists can grow much more in the future. | ||||
|  | ||||
| # EnTT in Action | ||||
|  | ||||
| ## 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. | ||||
|   * [The Worst Engine](https://github.com/Parasik72/TWE): a game engine based on | ||||
|     OpenGL. | ||||
|   * [Ecsact](https://ecsact.dev/): a language aimed at describing ECS, with a | ||||
|     [runtime implementation](https://github.com/ecsact-dev/ecsact_rt_entt) based | ||||
|     on `EnTT`. | ||||
|   * [AGE (Arc Game Engine)](https://github.com/MohitSethi99/ArcGameEngine): an | ||||
|     open-source engine for building 2D & 3D real-time rendering and interactive | ||||
|     contents. | ||||
|   * [Kengine](https://github.com/phisko/kengine): the _Koala engine_ is a game | ||||
|     engine entirely implemented as an entity-component-ystem. | ||||
|  | ||||
| ## 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. | ||||
|   * [Warmonger Dynasty devlog series](https://david-delassus.medium.com/list/warmonger-dynasty-devlogs-f64b71f556de) | ||||
|     by [linkdd](https://github.com/linkdd): an interesting walkthrough of | ||||
|     developing a game (also) with EnTT. | ||||
|   * [Use EnTT When You Need An ECS](https://www.codingwiththomas.com/blog/use-entt-when-you-need-an-ecs) | ||||
|     by [Thomas](https://www.codingwiththomas.com/): I couldn't have said it | ||||
|     better. | ||||
|   * [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. | ||||
							
								
								
									
										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. | ||||
							
								
								
									
										961
									
								
								external/entt/entt/docs/md/meta.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										961
									
								
								external/entt/entt/docs/md/meta.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,961 @@ | ||||
| # Crash Course: runtime reflection system | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
| * [Names and identifiers](#names-and-identifiers) | ||||
| * [Reflection in a nutshell](#reflection-in-a-nutshell) | ||||
|   * [Any to the rescue](#any-to-the-rescue) | ||||
|   * [Enjoy the runtime](#enjoy-the-runtime) | ||||
|   * [Container support](#container-support) | ||||
|   * [Pointer-like types](#pointer-like-types) | ||||
|   * [Template information](#template-information) | ||||
|   * [Automatic conversions](#automatic-conversions) | ||||
|   * [Implicitly generated default constructor](#implicitly-generated-default-constructor) | ||||
|   * [From void to any](#from-void-to-any) | ||||
|   * [Policies: the more, the less](#policies-the-more-the-less) | ||||
|   * [Named constants and enums](#named-constants-and-enums) | ||||
|   * [Properties and meta objects](#properties-and-meta-objects) | ||||
|   * [Unregister types](#unregister-types) | ||||
|   * [Meta context](#meta-context) | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| Reflection (or rather, its lack) is a trending topic in the C++ world and a tool | ||||
| that can unlock a lot of interesting features in the specific case of `EnTT`. I | ||||
| looked for a third-party library that met my needs on the subject, but I always | ||||
| came across some details that I didn't like: macros, being intrusive, too many | ||||
| allocations, and so on.<br/> | ||||
| I finally decided to write a built-in, non-intrusive and macro-free runtime | ||||
| reflection system for `EnTT`. Maybe I didn't do better than others or maybe yes, | ||||
| time will tell me, but at least I can model this tool around the library to | ||||
| which it belongs and not the opposite. | ||||
|  | ||||
| # Names and identifiers | ||||
|  | ||||
| The meta system doesn't force users to rely on the tools provided by the library | ||||
| when it comes to working with names and identifiers. It does this by offering an | ||||
| API that works with opaque identifiers that may or may not be generated by means | ||||
| of a hashed string.<br/> | ||||
| This means that users can assign any type of identifier to the meta objects, as | ||||
| long as they're numeric. It doesn't matter if they're generated at runtime, at | ||||
| compile-time or with custom functions. | ||||
|  | ||||
| That being said, the examples in the following sections are all based on the | ||||
| `hashed_string` class as provided by this library. Therefore, where an | ||||
| identifier is required, it's likely that a user defined literal is used as | ||||
| follows: | ||||
|  | ||||
| ```cpp | ||||
| auto factory = entt::meta<my_type>().type("reflected_type"_hs); | ||||
| ``` | ||||
|  | ||||
| For what it's worth, this is completely equivalent to: | ||||
|  | ||||
| ```cpp | ||||
| auto factory = entt::meta<my_type>().type(42u); | ||||
| ``` | ||||
|  | ||||
| Obviously, human-readable identifiers are more convenient to use and highly | ||||
| recommended. | ||||
|  | ||||
| # Reflection in a nutshell | ||||
|  | ||||
| Reflection always starts from actual C++ types. Users cannot reflect _imaginary_ | ||||
| types.<br/> | ||||
| The `meta` function is where it all starts: | ||||
|  | ||||
| ```cpp | ||||
| auto factory = entt::meta<my_type>(); | ||||
| ``` | ||||
|  | ||||
| The returned value is a _factory object_ to use to continue building the meta | ||||
| type. | ||||
|  | ||||
| By default, a meta type is associated with the identifier returned by the | ||||
| runtime type identification system built-in in `EnTT`.<br/> | ||||
| However, it's also possible to assign custom identifiers to meta types: | ||||
|  | ||||
| ```cpp | ||||
| auto factory = entt::meta<my_type>().type("reflected_type"_hs); | ||||
| ``` | ||||
|  | ||||
| Identifiers are used to _retrieve_ meta types at runtime by _name_ other than by | ||||
| type.<br/> | ||||
| However, users can be interested in adding features to a reflected type so that | ||||
| the reflection system can use it correctly under the hood, while they don't want | ||||
| to also make the type _searchable_. In this case, it's sufficient not to invoke | ||||
| `type`. | ||||
|  | ||||
| A factory is such that all its member functions return the factory itself. It's | ||||
| generally used to create the following: | ||||
|  | ||||
| * _Constructors_. A constructors is assigned to a reflected type by specifying | ||||
|   its _list of arguments_. Free functions are also accepted if the return type | ||||
|   is the expected one. From a client perspective, nothing changes between a free | ||||
|   function or an actual constructor: | ||||
|  | ||||
|   ```cpp | ||||
|   entt::meta<my_type>().ctor<int, char>().ctor<&factory>(); | ||||
|   ``` | ||||
|  | ||||
|   Meta default constructors are implicitly generated, if possible. | ||||
|  | ||||
| * _Destructors_. Both free functions and member functions are valid destructors: | ||||
|  | ||||
|   ```cpp | ||||
|   entt::meta<my_type>().dtor<&destroy>(); | ||||
|   ``` | ||||
|  | ||||
|   The purpose is to offer the possibility to free up resources that require | ||||
|   _special treatment_ before an object is actually destroyed.<br/> | ||||
|   A function should neither delete nor explicitly invoke the destructor of a | ||||
|   given instance. | ||||
|  | ||||
| * _Data members_. Meta data members are actual data members of the underlying | ||||
|   type but also static and global variables or constants of any kind. From the | ||||
|   point of view of the client, all the variables associated with the reflected | ||||
|   type appear as if they were part of the type itself: | ||||
|  | ||||
|   ```cpp | ||||
|   entt::meta<my_type>() | ||||
|       .data<&my_type::static_variable>("static"_hs) | ||||
|       .data<&my_type::data_member>("member"_hs) | ||||
|       .data<&global_variable>("global"_hs); | ||||
|   ``` | ||||
|  | ||||
|   The `data` function requires the identifier to use for the meta data member. | ||||
|   Users can then access it by _name_ at runtime.<br/> | ||||
|   Data members are also defined by means of a setter and getter pair. These are | ||||
|   either free functions, class members or a mix of them. This approach is also | ||||
|   convenient to create read-only properties from a non-const data member: | ||||
|  | ||||
|   ```cpp | ||||
|   entt::meta<my_type>().data<nullptr, &my_type::data_member>("member"_hs); | ||||
|   ``` | ||||
|  | ||||
|   Multiple setters are also supported by means of a `value_list` object: | ||||
|  | ||||
|   ```cpp | ||||
|   entt::meta<my_type>().data<entt::value_list<&from_int, &from_string>, &my_type::data_member>("member"_hs); | ||||
|   ``` | ||||
|  | ||||
| * _Member functions_. Meta member functions are actual member functions of the | ||||
|   underlying type but also plain free functions. From the point of view of the | ||||
|   client, all the functions associated with the reflected type appear as if they | ||||
|   were part of the type itself: | ||||
|  | ||||
|   ```cpp | ||||
|   entt::meta<my_type>() | ||||
|       .func<&my_type::static_function>("static"_hs) | ||||
|       .func<&my_type::member_function>("member"_hs) | ||||
|       .func<&free_function>("free"_hs); | ||||
|   ``` | ||||
|  | ||||
|   The `func` function requires the identifier to use for the meta data function. | ||||
|   Users can then access it by _name_ at runtime.<br/> | ||||
|   Overloading of meta functions is supported. Overloaded functions are resolved | ||||
|   at runtime by the reflection system according to the types of the arguments. | ||||
|  | ||||
| * _Base classes_. A base class is such that the underlying type is actually | ||||
|   derived from it: | ||||
|  | ||||
|   ```cpp | ||||
|   entt::meta<derived_type>().base<base_type>(); | ||||
|   ``` | ||||
|  | ||||
|   The reflection system tracks the relationship and allows for implicit casts at | ||||
|   runtime when required. In other terms, wherever a `base_type` is required, an | ||||
|   instance of `derived_type` is also accepted. | ||||
|  | ||||
| * _Conversion functions_. Conversion functions allow users to define conversions | ||||
|   that are implicitly performed by the reflection system when required: | ||||
|  | ||||
|   ```cpp | ||||
|   entt::meta<double>().conv<int>(); | ||||
|   ``` | ||||
|  | ||||
| This is everything users need to create meta types. Refer to the inline | ||||
| documentation for further details. | ||||
|  | ||||
| ## Any to the rescue | ||||
|  | ||||
| The reflection system offers a kind of _extended version_ of the `entt::any` | ||||
| class (see the core module for more details).<br/> | ||||
| The purpose is to add some feature on top of those already present, so as to | ||||
| integrate it with the meta type system without having to duplicate the code. | ||||
|  | ||||
| The API is very similar to that of the `any` type. The class `meta_any` _wraps_ | ||||
| many of the feature to infer a meta node, before forwarding some or all of the | ||||
| arguments to the underlying storage.<br/> | ||||
| Among the few relevant differences, `meta_any` adds support for containers and | ||||
| pointer-like types, while `any` doesn't.<br/> | ||||
| Similar to `any`, this class is also used to create _aliases_ for unmanaged | ||||
| objects either with `forward_as_meta` or using the `std::in_place_type<T &>` | ||||
| disambiguation tag, as well as from an existing object by means of the `as_ref` | ||||
| member function.<br/> | ||||
| Unlike `any` instead, `meta_any` treats an empty instance and one initialized | ||||
| with `void` differently: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta_any empty{}; | ||||
| entt::meta_any other{std::in_place_type<void>}; | ||||
| ``` | ||||
|  | ||||
| While `any` considers both as empty, `meta_any` treats objects initialized with | ||||
| `void` as if they were _valid_ ones. This allows to differentiate between failed | ||||
| function calls and function calls that are successful but return nothing. | ||||
|  | ||||
| Finally, the member functions `try_cast`, `cast` and `allow_cast` are used to | ||||
| cast the underlying object to a given type (either a reference or a value type) | ||||
| or to _convert_ a `meta_any` in such a way that a cast becomes viable for the | ||||
| resulting object.<br/> | ||||
| There is in fact no `any_cast` equivalent for `meta_any`. | ||||
|  | ||||
| ## Enjoy the runtime | ||||
|  | ||||
| Once the web of reflected types is constructed, it's a matter of using it at | ||||
| runtime where required.<br/> | ||||
| There are a few options to search for a reflected type: | ||||
|  | ||||
| ```cpp | ||||
| // direct access to a reflected type | ||||
| auto by_type = entt::resolve<my_type>(); | ||||
|  | ||||
| // look up a reflected type by identifier | ||||
| auto by_id = entt::resolve("reflected_type"_hs); | ||||
|  | ||||
| // look up a reflected type by type info | ||||
| auto by_type_id = entt::resolve(entt::type_id<my_type>()); | ||||
| ``` | ||||
|  | ||||
| There exists also an overload of the `resolve` function to use to iterate all | ||||
| reflected types at once. It returns an iterable object to be used in a range-for | ||||
| loop: | ||||
|  | ||||
| ```cpp | ||||
| for(auto &&[id, type]: entt::resolve()) { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| In all cases, the returned value is an instance of `meta_type` (possibly with | ||||
| its id). This kind of objects offer an API to know their _runtime identifiers_, | ||||
| to iterate all the meta objects associated with them and even to build instances | ||||
| of the underlying type.<br/> | ||||
| Meta data members and functions are accessed by name: | ||||
|  | ||||
| * Meta data members: | ||||
|  | ||||
|   ```cpp | ||||
|   auto data = entt::resolve<my_type>().data("member"_hs); | ||||
|   ``` | ||||
|  | ||||
|   The returned type is `meta_data` and may be invalid if there is no meta data | ||||
|   object associated with the given identifier.<br/> | ||||
|   A meta data object offers an API to query the underlying type (for example, to | ||||
|   know if it's a const or a static one), to get the meta type of the variable | ||||
|   and to set or get the contained value. | ||||
|  | ||||
| * Meta function members: | ||||
|  | ||||
|   ```cpp | ||||
|   auto func = entt::resolve<my_type>().func("member"_hs); | ||||
|   ``` | ||||
|  | ||||
|   The returned type is `meta_func` and may be invalid if there is no meta | ||||
|   function object associated with the given identifier.<br/> | ||||
|   A meta function object offers an API to query the underlying type (for | ||||
|   example, to know if it's a const or a static function), to know the number of | ||||
|   arguments, the meta return type and the meta types of the parameters. In | ||||
|   addition, a meta function object is used to invoke the underlying function and | ||||
|   then get the return value in the form of a `meta_any` object. | ||||
|  | ||||
| All the meta objects thus obtained as well as the meta types explicitly convert | ||||
| to a boolean value to check for validity: | ||||
|  | ||||
| ```cpp | ||||
| if(auto func = entt::resolve<my_type>().func("member"_hs); func) { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Furthermore, all them (and a few more, like meta basis) are returned by a bunch | ||||
| of overloads that provide the caller with iterable ranges of top-level elements. | ||||
| As an example: | ||||
|  | ||||
| ```cpp | ||||
| for(auto &&[id, type]: entt::resolve<my_type>().base()) { | ||||
|     // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Meta type are also used to `construct` actual instances of the underlying | ||||
| type.<br/> | ||||
| In particular, the `construct` member function accepts a variable number of | ||||
| arguments and searches for a match. It then returns a `meta_any` object that may | ||||
| or may not be initialized, depending on whether a suitable constructor was found | ||||
| or not. | ||||
|  | ||||
| There is no object that wraps the destructor of a meta type nor a `destroy` | ||||
| member function in its API. Destructors are invoked implicitly by `meta_any` | ||||
| behind the scenes and users have not to deal with them explicitly. Furthermore, | ||||
| they've no name, cannot be searched and wouldn't have member functions to expose | ||||
| anyway.<br/> | ||||
| Similarly, conversion functions aren't directly accessible. They're used | ||||
| internally by `meta_any` and the meta objects when needed. | ||||
|  | ||||
| Meta types and meta objects in general contain much more than what was said. | ||||
| Refer to the inline documentation for further details. | ||||
|  | ||||
| ## Container support | ||||
|  | ||||
| The runtime reflection system also supports containers of all types.<br/> | ||||
| Moreover, _containers_ doesn't necessarily mean those offered by the C++ | ||||
| standard library. In fact, user defined data structures can also work with the | ||||
| meta system in many cases. | ||||
|  | ||||
| To make a container be recognized as such by the meta system, users are required | ||||
| to provide specializations for either the `meta_sequence_container_traits` class | ||||
| or the `meta_associative_container_traits` class, according to the actual _type_ | ||||
| of the container.<br/> | ||||
| `EnTT` already exports the specializations for some common classes. In | ||||
| particular: | ||||
|  | ||||
| * `std::vector`, `std::array`, `std::deque` and `std::list` (but not | ||||
|   `std::forward_list`) are supported as _sequence containers_. | ||||
|  | ||||
| * `std::map`, `std::set` and their unordered counterparts are supported as | ||||
|   _associative containers_. | ||||
|  | ||||
| It's important to include the header file `container.hpp` to make these | ||||
| specializations available to the compiler when needed.<br/> | ||||
| The same file also contains many examples for the users that are interested in | ||||
| making their own containers available to the meta system. | ||||
|  | ||||
| When a specialization of the `meta_sequence_container_traits` class exists, the | ||||
| meta system treats the wrapped type as a sequence container. In a similar way, | ||||
| a type is treated as an associative container if a specialization of the | ||||
| `meta_associative_container_traits` class is found for it.<br/> | ||||
| Proxy objects are returned by dedicated members of the `meta_any` class. The | ||||
| following is a deliberately verbose example of how users can access a proxy | ||||
| object for a sequence container: | ||||
|  | ||||
| ```cpp | ||||
| std::vector<int> vec{1, 2, 3}; | ||||
| entt::meta_any any = entt::forward_as_meta(vec); | ||||
|  | ||||
| if(any.type().is_sequence_container()) { | ||||
|     if(auto view = any.as_sequence_container(); view) { | ||||
|         // ... | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The method to use to get a proxy object for associative containers is | ||||
| `as_associative_container` instead.<br/> | ||||
| It's not necessary to perform a double check actually. Instead, it's enough to | ||||
| query the meta type or verify that the proxy object is valid. In fact, proxies | ||||
| are contextually convertible to bool to check for validity. For example, invalid | ||||
| proxies are returned when the wrapped object isn't a container.<br/> | ||||
| In all cases, users aren't expected to _reflect_ containers explicitly. It's | ||||
| sufficient to assign a container for which a specialization of the traits | ||||
| classes exists to a `meta_any` object to be able to get its proxy object. | ||||
|  | ||||
| The interface of the `meta_sequence_container` proxy object is the same for all | ||||
| types of sequence containers, although the available features differ from case | ||||
| to case. In particular: | ||||
|  | ||||
| * The `value_type` member function returns the meta type of the elements. | ||||
|  | ||||
| * The `size` member function returns the number of elements in the container as | ||||
|   an unsigned integer value. | ||||
|  | ||||
| * The `resize` member function allows to resize the wrapped container and | ||||
|   returns true in case of success.<br/> | ||||
|   For example, it's not possible to resize fixed size containers. | ||||
|  | ||||
| * The `clear` member function allows to clear the wrapped container and returns | ||||
|   true in case of success.<br/> | ||||
|   For example, it's not possible to clear fixed size containers. | ||||
|  | ||||
| * The `begin` and `end` member functions return opaque iterators that is used to | ||||
|   iterate the container directly: | ||||
|  | ||||
|   ```cpp | ||||
|   for(entt::meta_any element: view) { | ||||
|       // ... | ||||
|   } | ||||
|   ``` | ||||
|  | ||||
|   In all cases, given an underlying container of type `C`, the returned element | ||||
|   contains an object of type `C::value_type` which therefore depends on the | ||||
|   actual container.<br/> | ||||
|   All meta iterators are input iterators and don't offer an indirection operator | ||||
|   on purpose. | ||||
|  | ||||
| * The `insert` member function is used to add elements to the container. It | ||||
|   accepts a meta iterator and the element to insert: | ||||
|  | ||||
|   ```cpp | ||||
|   auto last = view.end(); | ||||
|   // appends an integer to the container | ||||
|   view.insert(last, 42); | ||||
|   ``` | ||||
|  | ||||
|   This function returns a meta iterator pointing to the inserted element and a | ||||
|   boolean value to indicate whether the operation was successful or not. A call | ||||
|   to `insert` may silently fail in case of fixed size containers or whether the | ||||
|   arguments aren't at least convertible to the required types.<br/> | ||||
|   Since meta iterators are contextually convertible to bool, users can rely on | ||||
|   them to know if the operation failed on the actual container or upstream, for | ||||
|   example due to an argument conversion problem. | ||||
|  | ||||
| * The `erase` member function is used to remove elements from the container. It | ||||
|   accepts a meta iterator to the element to remove: | ||||
|  | ||||
|   ```cpp | ||||
|   auto first = view.begin(); | ||||
|   // removes the first element from the container | ||||
|   view.erase(first); | ||||
|   ``` | ||||
|  | ||||
|   This function returns a meta iterator following the last removed element and a | ||||
|   boolean value to indicate whether the operation was successful or not. A call | ||||
|   to `erase` may silently fail in case of fixed size containers. | ||||
|  | ||||
| * The `operator[]` is used to access container elements. It accepts a single | ||||
|   argument, the position of the element to return: | ||||
|  | ||||
|   ```cpp | ||||
|   for(std::size_t pos{}, last = view.size(); pos < last; ++pos) { | ||||
|       entt::meta_any value = view[pos]; | ||||
|       // ... | ||||
|   } | ||||
|   ``` | ||||
|  | ||||
|   The function returns instances of `meta_any` that directly refer to the actual | ||||
|   elements. Modifying the returned object directly modifies the element inside | ||||
|   the container.<br/> | ||||
|   Depending on the underlying sequence container, this operation may not be as | ||||
|   efficient. For example, in the case of an `std::list`, a positional access | ||||
|   translates to a linear visit of the list itself (probably not what the user | ||||
|   expects). | ||||
|  | ||||
| Similarly, also the interface of the `meta_associative_container` proxy object | ||||
| is the same for all types of associative containers. However, there are some | ||||
| differences in behavior in the case of key-only containers. In particular: | ||||
|  | ||||
| * The `key_only` member function returns true if the wrapped container is a | ||||
|   key-only one. | ||||
|  | ||||
| * The `key_type` member function returns the meta type of the keys. | ||||
|  | ||||
| * The `mapped_type` member function returns an invalid meta type for key-only | ||||
|   containers and the meta type of the mapped values for all other types of | ||||
|   containers. | ||||
|  | ||||
| * The `value_type` member function returns the meta type of the elements.<br/> | ||||
|   For example, it returns the meta type of `int` for `std::set<int>` while it | ||||
|   returns the meta type of `std::pair<const int, char>` for | ||||
|   `std::map<int, char>`. | ||||
|  | ||||
| * The `size` member function returns the number of elements in the container as | ||||
|   an unsigned integer value. | ||||
|  | ||||
| * The `clear` member function allows to clear the wrapped container and returns | ||||
|   true in case of success. | ||||
|  | ||||
| * The `begin` and `end` member functions return opaque iterators that are used | ||||
|   to iterate the container directly: | ||||
|  | ||||
|   ```cpp | ||||
|   for(std::pair<entt::meta_any, entt::meta_any> element: view) { | ||||
|       // ... | ||||
|   } | ||||
|   ``` | ||||
|  | ||||
|   In all cases, given an underlying container of type `C`, the returned element | ||||
|   is a key-value pair where the key has type `C::key_type` and the value has | ||||
|   type `C::mapped_type`. Since key-only containers don't have a mapped type, | ||||
|   their _value_ is nothing more than an invalid `meta_any` object.<br/> | ||||
|   All meta iterators are input iterators and don't offer an indirection operator | ||||
|   on purpose. | ||||
|  | ||||
|   While the accessed key is usually constant in the associative containers and | ||||
|   is therefore returned by copy, the value (if any) is wrapped by an instance of | ||||
|   `meta_any` that directly refers to the actual element. Modifying it directly | ||||
|   modifies the element inside the container. | ||||
|  | ||||
| * The `insert` member function is used to add elements to a container. It gets | ||||
|   two arguments, respectively the key and the value to insert: | ||||
|  | ||||
|   ```cpp | ||||
|   auto last = view.end(); | ||||
|   // appends an integer to the container | ||||
|   view.insert(last.handle(), 42, 'c'); | ||||
|   ``` | ||||
|  | ||||
|   This function returns a boolean value to indicate whether the operation was | ||||
|   successful or not. A call to `insert` may fail when the arguments aren't at | ||||
|   least convertible to the required types. | ||||
|  | ||||
| * The `erase` member function is used to remove elements from a container. It | ||||
|   gets a single argument, the key to remove: | ||||
|  | ||||
|   ```cpp | ||||
|   view.erase(42); | ||||
|   ``` | ||||
|  | ||||
|   This function returns a boolean value to indicate whether the operation was | ||||
|   successful or not. A call to `erase` may fail when the argument isn't at least | ||||
|   convertible to the required type. | ||||
|  | ||||
| * The `operator[]` is used to access elements in a container. It gets a single | ||||
|   argument, the key of the element to return: | ||||
|  | ||||
|   ```cpp | ||||
|   entt::meta_any value = view[42]; | ||||
|   ``` | ||||
|  | ||||
|   The function returns instances of `meta_any` that directly refer to the actual | ||||
|   elements. Modifying the returned object directly modifies the element inside | ||||
|   the container. | ||||
|  | ||||
| Container support is minimal but likely sufficient to satisfy all needs. | ||||
|  | ||||
| ## Pointer-like types | ||||
|  | ||||
| As with containers, it's also possible to _tell_ to the meta system which types | ||||
| are _pointers_. This makes it possible to dereference instances of `meta_any`, | ||||
| thus obtaining light _references_ to pointed objects that are also correctly | ||||
| associated with their meta types.<br/> | ||||
| To make the meta system recognize a type as _pointer-like_, users can specialize | ||||
| the `is_meta_pointer_like` class. `EnTT` already exports the specializations for | ||||
| some common classes. In particular: | ||||
|  | ||||
| * All types of raw pointers. | ||||
| * `std::unique_ptr` and `std::shared_ptr`. | ||||
|  | ||||
| It's important to include the header file `pointer.hpp` to make these | ||||
| specializations available to the compiler when needed.<br/> | ||||
| The same file also contains many examples for the users that are interested in | ||||
| making their own pointer-like types available to the meta system. | ||||
|  | ||||
| When a type is recognized as a pointer-like one by the meta system, it's | ||||
| possible to dereference the instances of `meta_any` that contain these objects. | ||||
| The following is a deliberately verbose example to show how to use this feature: | ||||
|  | ||||
| ```cpp | ||||
| int value = 42; | ||||
| // meta type equivalent to that of int * | ||||
| entt::meta_any any{&value}; | ||||
|  | ||||
| if(any.type().is_pointer_like()) { | ||||
|     // meta type equivalent to that of int | ||||
|     if(entt::meta_any ref = *any; ref) { | ||||
|         // ... | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| It's not necessary to perform a double check. Instead, it's enough to query the | ||||
| meta type or verify that the returned object is valid. For example, invalid | ||||
| instances are returned when the wrapped object isn't a pointer-like type.<br/> | ||||
| Dereferencing a pointer-like object returns an instance of `meta_any` which | ||||
| _refers_ to the pointed object. Modifying it means modifying the pointed object | ||||
| directly (unless the returned element is const). | ||||
|  | ||||
| In general, _dereferencing_ a pointer-like type boils down to a `*ptr`. However, | ||||
| `EnTT` also supports classes that don't offer an `operator*`. In particular: | ||||
|  | ||||
| * It's possible to exploit a solution based on ADL lookup by offering a function | ||||
|   (also a template one) named `dereference_meta_pointer_like`: | ||||
|  | ||||
|   ```cpp | ||||
|   template<typename Type> | ||||
|   Type & dereference_meta_pointer_like(const custom_pointer_type<Type> &ptr) { | ||||
|       return ptr.deref(); | ||||
|   } | ||||
|   ``` | ||||
|  | ||||
| * When not in control of the type's namespace, it's possible to inject into the | ||||
|   `entt` namespace a specialization of the `adl_meta_pointer_like` class | ||||
|   template to bypass the adl lookup as a whole: | ||||
|  | ||||
|   ```cpp | ||||
|   template<typename Type> | ||||
|   struct entt::adl_meta_pointer_like<custom_pointer_type<Type>> { | ||||
|       static decltype(auto) dereference(const custom_pointer_type<Type> &ptr) { | ||||
|           return ptr.deref(); | ||||
|       } | ||||
|   }; | ||||
|   ``` | ||||
|  | ||||
| In all other cases and when dereferencing a pointer works as expected regardless | ||||
| of the pointed type, no user intervention is required. | ||||
|  | ||||
| ## Template information | ||||
|  | ||||
| Meta types also provide a minimal set of information about the _nature_ of the | ||||
| original type in case it's a class template.<br/> | ||||
| By default, this works out of the box and requires no user action. However, it's | ||||
| important to include the header file `template.hpp` to make this information | ||||
| available to the compiler when needed. | ||||
|  | ||||
| Meta template information are easily found: | ||||
|  | ||||
| ```cpp | ||||
| // this method returns true if the type is recognized as a class template specialization | ||||
| if(auto type = entt::resolve<std::shared_ptr<my_type>>(); type.is_template_specialization()) { | ||||
|     // meta type of the class template conveniently wrapped by entt::meta_class_template_tag | ||||
|     auto class_type = type.template_type(); | ||||
|  | ||||
|     // number of template arguments | ||||
|     std::size_t arity = type.template_arity(); | ||||
|  | ||||
|     // meta type of the i-th argument | ||||
|     auto arg_type = type.template_arg(0u); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Typically, when template information for a type are required, what the library | ||||
| provides is sufficient. However, there are some cases where a user may want more | ||||
| details or a different set of information.<br/> | ||||
| Consider the case of a class template that is meant to wrap function types: | ||||
|  | ||||
| ```cpp | ||||
| template<typename> | ||||
| struct function_type; | ||||
|  | ||||
| template<typename Ret, typename... Args> | ||||
| struct function_type<Ret(Args...)> {}; | ||||
| ``` | ||||
|  | ||||
| In this case, rather than the function type, it might be useful to provide the | ||||
| return type and unpacked arguments as if they were different template parameters | ||||
| for the original class template.<br/> | ||||
| To achieve this, users must enter the library internals and provide their own | ||||
| specialization for the class template `entt::meta_template_traits`, such as: | ||||
|  | ||||
| ```cpp | ||||
| template<typename Ret, typename... Args> | ||||
| struct entt::meta_template_traits<function_type<Ret(Args...)>> { | ||||
|     using class_type = meta_class_template_tag<function_type>; | ||||
|     using args_type = type_list<Ret, Args...>; | ||||
| }; | ||||
| ``` | ||||
|  | ||||
| The reflection system doesn't verify the accuracy of the information nor infer a | ||||
| correspondence between real types and meta types.<br/> | ||||
| Therefore, the specialization is used as is and the information it contains is | ||||
| associated with the appropriate type when required. | ||||
|  | ||||
| ## Automatic conversions | ||||
|  | ||||
| In C++, there are a number of conversions allowed between arithmetic types that | ||||
| make it convenient to work with this kind of data.<br/> | ||||
| If this were to be translated into explicit registrations with the reflection | ||||
| system, it would result in a long series of instructions such as the following: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta<int>() | ||||
|     .conv<bool>() | ||||
|     .conv<char>() | ||||
|     // ... | ||||
|     .conv<double>(); | ||||
| ``` | ||||
|  | ||||
| Repeated for each type eligible to undergo this type of conversions. This is | ||||
| both error-prone and repetitive.<br/> | ||||
| Similarly, the language allows users to silently convert unscoped enums to their | ||||
| underlying types and offers what it takes to do the same for scoped enums. It | ||||
| would result in the following if it were to be done explicitly: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta<my_enum>() | ||||
|     .conv<std::underlying_type_t<my_enum>>(); | ||||
| ``` | ||||
|  | ||||
| Fortunately, all of this can also be avoided. `EnTT` offers implicit support for | ||||
| these types of conversions: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta_any any{42}; | ||||
| any.allow_cast<double>(); | ||||
| double value = any.cast<double>(); | ||||
| ``` | ||||
|  | ||||
| With no need for registration, the conversion takes place automatically under | ||||
| the hood. The same goes for a call to `allow_cast` involving a meta type: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta_type type = entt::resolve<int>(); | ||||
| entt::meta_any any{my_enum::a_value}; | ||||
| any.allow_cast(type); | ||||
| int value = any.cast<int>(); | ||||
| ``` | ||||
|  | ||||
| This makes working with arithmetic types and scoped or unscoped enums as easy as | ||||
| it is in C++.<br/> | ||||
| It's still possible to set up conversion functions manually and these are always | ||||
| preferred over the automatic ones. | ||||
|  | ||||
| ## Implicitly generated default constructor | ||||
|  | ||||
| Creating objects of default constructible types through the reflection system | ||||
| while not having to explicitly register the meta type or its default constructor | ||||
| is also possible.<br/> | ||||
| For example, in the case of primitive types like `int` or `char`, but not just | ||||
| them. | ||||
|  | ||||
| For default constructible types only, default constructors are automatically | ||||
| defined and associated with their meta types, whether they are explicitly or | ||||
| implicitly generated.<br/> | ||||
| Therefore, this is all is needed to construct an integer from its meta type: | ||||
|  | ||||
| ```cpp | ||||
| entt::resolve<int>().construct(); | ||||
| ``` | ||||
|  | ||||
| Where the meta type is for example the one returned from a meta container, | ||||
| useful for building keys without knowing or having to register the actual types. | ||||
|  | ||||
| In all cases, when users register default constructors, they are preferred both | ||||
| during searches and when the `construct` member function is invoked. | ||||
|  | ||||
| ## From void to any | ||||
|  | ||||
| Sometimes all a user has is an opaque pointer to an object of a known meta type. | ||||
| It would be handy in this case to be able to construct a `meta_any` element from | ||||
| it.<br/> | ||||
| For this purpose, the `meta_type` class offers a `from_void` member function | ||||
| designed to convert an opaque pointer into a `meta_any`: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta_any any = entt::resolve(id).from_void(element); | ||||
| ``` | ||||
|  | ||||
| Unfortunately, it's not possible to do a check on the actual type. Therefore, | ||||
| this call can be considered as a _static cast_ with all its _problems_.<br/> | ||||
| On the other hand, the ability to construct a `meta_any` from an opaque pointer | ||||
| opens the door to some pretty interesting uses that are worth exploring. | ||||
|  | ||||
| ## Policies: the more, the less | ||||
|  | ||||
| Policies are a kind of compile-time directives that can be used when registering | ||||
| reflection information.<br/> | ||||
| Their purpose is to require slightly different behavior than the default in some | ||||
| specific cases. For example, when reading a given data member, its value is | ||||
| returned wrapped in a `meta_any` object which, by default, makes a copy of it. | ||||
| For large objects or if the caller wants to access the original instance, this | ||||
| behavior isn't desirable. Policies are there to offer a solution to this and | ||||
| other problems. | ||||
|  | ||||
| There are a few alternatives available at the moment: | ||||
|  | ||||
| * The _as-is_ policy, associated with the type `entt::as_is_t`.<br/> | ||||
|   This is the default policy. In general, it should never be used explicitly, | ||||
|   since it's implicitly selected if no other policy is specified.<br/> | ||||
|   In this case, the return values of the functions as well as the properties | ||||
|   exposed as data members are always returned by copy in a dedicated wrapper and | ||||
|   therefore associated with their original meta types. | ||||
|  | ||||
| * The _as-void_ policy, associated with the type `entt::as_void_t`.<br/> | ||||
|   Its purpose is to discard the return value of a meta object, whatever it is, | ||||
|   thus making it appear as if its type were `void`: | ||||
|  | ||||
|   ```cpp | ||||
|   entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs); | ||||
|   ``` | ||||
|  | ||||
|   If the use with functions is obvious, perhaps less so is use with constructors | ||||
|   and data members. In the first case, the returned wrapper is always empty even | ||||
|   though the constructor is still invoked. In the second case, the property | ||||
|   isn't accessible for reading instead. | ||||
|  | ||||
| * The _as-ref_ and _as-cref_ policies, associated with the types | ||||
|   `entt::as_ref_t` and `entt::as_cref_t`.<br/> | ||||
|   They allow to build wrappers that act as references to unmanaged objects. | ||||
|   Accessing the object contained in the wrapper for which the _reference_ was | ||||
|   requested makes it possible to directly access the instance used to initialize | ||||
|   the wrapper itself: | ||||
|  | ||||
|   ```cpp | ||||
|   entt::meta<my_type>().data<&my_type::data_member, entt::as_ref_t>("member"_hs); | ||||
|   ``` | ||||
|  | ||||
|   These policies work with constructors (for example, when objects are taken | ||||
|   from an external container rather than created on demand), data members and | ||||
|   functions in general.<br/> | ||||
|   If on the one hand `as_cref_t` always forces the return type to be const, | ||||
|   `as_ref_t` _adapts_ to the constness of the passed object and to that of the | ||||
|   return type if any. | ||||
|  | ||||
| Some uses are rather trivial, but it's useful to note that there are some less | ||||
| obvious corner cases that can in turn be solved with the use of policies. | ||||
|  | ||||
| ## Named constants and enums | ||||
|  | ||||
| As mentioned, the `data` member function is used to reflect constants of any | ||||
| type.<br/> | ||||
| This allows users to create meta types for enums that work exactly like any | ||||
| other meta type built from a class. Similarly, arithmetic types are _enriched_ | ||||
| with constants of special meaning where required.<br/> | ||||
| All values thus exported appear to users as if they were constant data members | ||||
| of the reflected types. This avoids the need to _export_ what is the difference | ||||
| between enums and classes in C++ directly in the space of the reflected types. | ||||
|  | ||||
| Exposing constant values or elements from an enum is quite simple: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta<my_enum>() | ||||
|     .data<my_enum::a_value>("a_value"_hs) | ||||
|     .data<my_enum::another_value>("another_value"_hs); | ||||
|  | ||||
| entt::meta<int>().data<2048>("max_int"_hs); | ||||
| ``` | ||||
|  | ||||
| Accessing them is trivial as well. It's a matter of doing the following, as with | ||||
| any other data member of a meta type: | ||||
|  | ||||
| ```cpp | ||||
| auto value = entt::resolve<my_enum>().data("a_value"_hs).get({}).cast<my_enum>(); | ||||
| auto max = entt::resolve<int>().data("max_int"_hs).get({}).cast<int>(); | ||||
| ``` | ||||
|  | ||||
| All this happens behind the scenes without any allocation because of the small | ||||
| object optimization performed by the `meta_any` class. | ||||
|  | ||||
| ## Properties and meta objects | ||||
|  | ||||
| Sometimes (for example, when it comes to creating an editor) it might be useful | ||||
| to attach properties to the meta objects created. Fortunately, this is possible | ||||
| for most of them: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta<my_type>().type("reflected_type"_hs).prop("tooltip"_hs, "message"); | ||||
| ``` | ||||
|  | ||||
| Properties are always in the key/value form. The key is a numeric identifier, | ||||
| mostly similar to the identifier used to register meta objects. There are no | ||||
| restrictions on the type of the value instead, as long as it's movable.<br/> | ||||
| Key only properties are also supported out of the box: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta<my_type>().type("reflected_type"_hs).prop(my_enum::key_only); | ||||
| ``` | ||||
|  | ||||
| To attach multiple properties to a meta object, just invoke `prop` more than | ||||
| once.<br/> | ||||
| It's also possible to call `prop` at different times, as long as the factory is | ||||
| reset to the meta object of interest. | ||||
|  | ||||
| The meta objects for which properties are supported are currently meta types, | ||||
| meta data and meta functions.<br/> | ||||
| These types also offer a couple of member functions named `prop` to iterate all | ||||
| properties at once or to search a specific property by key: | ||||
|  | ||||
| ```cpp | ||||
| // iterate all properties of a meta type | ||||
| for(auto &&[id, prop]: entt::resolve<my_type>().prop()) { | ||||
|     // ... | ||||
| } | ||||
|  | ||||
| // search for a given property by name | ||||
| auto prop = entt::resolve<my_type>().prop("tooltip"_hs); | ||||
| ``` | ||||
|  | ||||
| Meta properties are objects having a fairly poor interface, all in all. They | ||||
| only provide the `value` member function to retrieve the contained value in the | ||||
| form of a `meta_any` object. | ||||
|  | ||||
| ## Unregister types | ||||
|  | ||||
| A type registered with the reflection system can also be _unregistered_. This | ||||
| means unregistering all its data members, member functions, conversion functions | ||||
| and so on. However, base classes aren't unregistered as well, since they don't | ||||
| necessarily depend on it.<br/> | ||||
| Roughly speaking, unregistering a type means disconnecting all associated meta | ||||
| objects from it and making its identifier no longer available: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta_reset<my_type>(); | ||||
| ``` | ||||
|  | ||||
| It's also possible to reset types by their unique identifiers: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta_reset("my_type"_hs); | ||||
| ``` | ||||
|  | ||||
| Finally, there exists a non-template overload of the `meta_reset` function that | ||||
| doesn't accept arguments and resets all meta types at once: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta_reset(); | ||||
| ``` | ||||
|  | ||||
| A type can be re-registered later with a completely different name and form. | ||||
|  | ||||
| ## Meta context | ||||
|  | ||||
| All meta types and their parts are created at runtime and stored in a default | ||||
| _context_. This is obtained via a service locator as: | ||||
|  | ||||
| ```cpp | ||||
| auto &&context = entt::locator<entt::meta_context>::value_or(); | ||||
| ``` | ||||
|  | ||||
| By itself, a context is an opaque object that the user cannot do much with. | ||||
| However, users can replace an existing context with another at any time: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta_context other{}; | ||||
| auto &&context = entt::locator<entt::meta_context>::value_or(); | ||||
| std::swap(context, other); | ||||
| ``` | ||||
|  | ||||
| This is useful for testing purposes or to define multiple context objects with | ||||
| different meta type to use as appropriate. | ||||
|  | ||||
| If _replacing_ the default context isn't enough, `EnTT` also offers the ability | ||||
| to use multiple and externally managed contexts with the runtime reflection | ||||
| system.<br/> | ||||
| For example, to create new meta types within a context other than the default | ||||
| one, simply pass it as an argument to the `meta` call: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta_ctx context{}; | ||||
| auto factory = entt::meta<my_type>(context).type("reflected_type"_hs); | ||||
| ``` | ||||
|  | ||||
| By doing so, the new meta type isn't available in the default context but is | ||||
| usable by passing around the new context when needed, such as when creating a | ||||
| new `meta_any` object: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta_any any{context, std::in_place_type<my_type>}; | ||||
| ``` | ||||
|  | ||||
| Similarly, to search for meta types in a context other than the default one, | ||||
| it's necessary to pass it to the `resolve` function: | ||||
|  | ||||
| ```cpp | ||||
| entt::meta_type type = entt::resolve(context, "reflected_type"_hs) | ||||
| ``` | ||||
|  | ||||
| More generally, when using externally managed contexts, it's always required to | ||||
| provide the system with the context to use, at least at the _entry point_.<br/> | ||||
| For example, once the `meta_type` instant is obtained, it's no longer necessary | ||||
| to pass the context around as the meta type takes the information with it and | ||||
| eventually propagates it to all its parts.<br/> | ||||
| On the other hand, it's necessary to instruct the library on where meta types | ||||
| are to be fetched when `meta_any`s and `meta_handle`s are constructed, a factory | ||||
| created or a meta type resolved. | ||||
							
								
								
									
										357
									
								
								external/entt/entt/docs/md/poly.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										357
									
								
								external/entt/entt/docs/md/poly.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,357 @@ | ||||
| # 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/> | ||||
| Among others, this is 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/> | ||||
| The result is an object to pass around as such and not through a reference or a | ||||
| pointer, as it 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. For example, 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/> | ||||
| The ones that I like more 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, it 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, a generic implementation is needed to fulfill the | ||||
| concept itself.<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 defined: | ||||
|  | ||||
| ```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 are 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 also exists 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> | ||||
| In fact, this is 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 is 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're part of 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 is 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`. Instead, it 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, the list of types is _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 is only 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 are defined, it's possible to use the | ||||
| `poly` class template to _wrap_ 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(); | ||||
| ``` | ||||
|  | ||||
| This class offers a wide range of constructors, from the default one (which | ||||
| returns 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 | ||||
| doesn'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()` invokes the `data` member function of the | ||||
| poly object, `instance->data()` maps 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 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. | ||||
							
								
								
									
										217
									
								
								external/entt/entt/docs/md/process.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								external/entt/entt/docs/md/process.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,217 @@ | ||||
| # 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 | ||||
|  | ||||
| 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 other component | ||||
| types.<br/> | ||||
| `EnTT` offers minimal support to this paradigm by introducing a few classes used | ||||
| to define and execute cooperative processes. | ||||
|  | ||||
| # The process | ||||
|  | ||||
| A typical task inherits from the `process` class template that stays true to the | ||||
| CRTP idiom. Moreover, derived classes specify what the intended type for elapsed | ||||
| times is. | ||||
|  | ||||
| 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 *);` | ||||
|  | ||||
|   This is invoked once per tick until a process is explicitly aborted or ends | ||||
|   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();` | ||||
|  | ||||
|   This is invoked when the process joins the running queue of a scheduler. It | ||||
|   happens usually as soon as the process is attached to the scheduler if it's a | ||||
|   top level one, otherwise when it replaces its parent if it's a _continuation_. | ||||
|  | ||||
| * `void succeeded();` | ||||
|  | ||||
|   This is invoked in case of success, immediately after an update and during the | ||||
|   same tick. | ||||
|  | ||||
| * `void failed();` | ||||
|  | ||||
|   This is invoked in case of errors, immediately after an update and during the | ||||
|   same tick. | ||||
|  | ||||
| * `void aborted();` | ||||
|  | ||||
|   This is invoked only if a process is explicitly aborted. There is no guarantee | ||||
|   that it executes in the same tick, it 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.<br/> | ||||
| All these are protected member functions made available 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 because they aren't | ||||
| 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 callbacks to | ||||
| invoke whenever a process terminates 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::basic_scheduler<std::uint64_t> scheduler; | ||||
| ``` | ||||
|  | ||||
| Otherwise, the `scheduler` alias is also available for the most common cases. It | ||||
| uses `std::uint32_t` as a default type: | ||||
|  | ||||
| ```cpp | ||||
| entt::scheduler scheduler; | ||||
| ``` | ||||
|  | ||||
| The class 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::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 used 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 is 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(); | ||||
| ``` | ||||
							
								
								
									
										91
									
								
								external/entt/entt/docs/md/reference.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								external/entt/entt/docs/md/reference.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| # Similar projects | ||||
|  | ||||
| <!-- | ||||
| @cond TURN_OFF_DOXYGEN | ||||
| --> | ||||
| # Table of Contents | ||||
|  | ||||
| * [Introduction](#introduction) | ||||
| * [Similar projects](#similar-projects) | ||||
| <!-- | ||||
| @endcond TURN_OFF_DOXYGEN | ||||
| --> | ||||
|  | ||||
| # Introduction | ||||
|  | ||||
| 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. | ||||
|  | ||||
| If you know of other similar projects out there, feel free to open an issue or a | ||||
| PR and I'll be glad to add them to this page.<br/> | ||||
| I hope the following lists can grow much more in the future. | ||||
|  | ||||
| # Similar projects | ||||
|  | ||||
| Below an incomplete list of similar projects 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. | ||||
|  | ||||
| * 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# | ||||
|   * [Arch](https://github.com/genaray/Arch): a simple, fast and _unity entities_ | ||||
|     inspired archetype ECS with optional multithreading.  | ||||
|   * [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`. | ||||
							
								
								
									
										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. | ||||
							
								
								
									
										565
									
								
								external/entt/entt/docs/md/signal.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										565
									
								
								external/entt/entt/docs/md/signal.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,565 @@ | ||||
| # 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) | ||||
|   * [Raw access](#raw-access) | ||||
| * [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, lambdas and members 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); | ||||
| ``` | ||||
|  | ||||
| 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. 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.<br/> | ||||
| In fact, this filtering works both ways. The class tries to pass its first | ||||
| _count_ arguments **first**, then the last _count_. Watch out for conversion | ||||
| rules if in doubt when connecting a listener!<br/> | ||||
| Arbitrary functions that pull random arguments from the delegate list aren't | ||||
| supported instead. Other feature were preferred, such as support for functions | ||||
| with compatible argument lists although not equal to those of the delegate. | ||||
|  | ||||
| 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)`. | ||||
|  | ||||
| ## Raw access | ||||
|  | ||||
| While not recommended, a delegate also allows direct access to the stored | ||||
| callable function target and underlying data, if any.<br/> | ||||
| This makes it possible to bypass the behavior of the delegate itself and force | ||||
| calls on different instances: | ||||
|  | ||||
| ```cpp | ||||
| my_struct other; | ||||
| delegate.target(&other, 42); | ||||
| ``` | ||||
|  | ||||
| It goes without saying that this type of approach is **very** risky, especially | ||||
| since there is no way of knowing whether the contained function was originally a | ||||
| member function of some class, a free function or a lambda.<br/> | ||||
| Another possible (and meaningful) use of this feature is that of identifying a | ||||
| particular delegate through its descriptive _traits_ instead. | ||||
|  | ||||
| # 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/> | ||||
| 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> | ||||
							
								
								
									
										123
									
								
								external/entt/entt/natvis/entt/entity.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								external/entt/entt/natvis/entt/entity.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||||
| 	<Type Name="entt::basic_registry<*>"> | ||||
| 		<Intrinsic Name="to_entity" Expression="*((traits_type::entity_type *)&entity) & traits_type::entity_mask"> | ||||
| 			<Parameter Name="entity" Type="traits_type::value_type &"/> | ||||
| 		</Intrinsic> | ||||
| 		<DisplayString>{{ pools={ pools.size() } }}</DisplayString> | ||||
| 		<Expand> | ||||
| 			<Item Name="[entities]">entities</Item> | ||||
| 			<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.ctx.size() }</DisplayString> | ||||
| 				<Expand> | ||||
| 					<IndexListItems> | ||||
| 						<Size>vars.ctx.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() * traits_type::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() * traits_type::page_size"/> | ||||
| 						<Loop> | ||||
| 							<Break Condition="pos == last"/> | ||||
| 							<Exec>page = pos / traits_type::page_size</Exec> | ||||
| 							<Exec>offset = pos & (traits_type::page_size - 1)</Exec> | ||||
| 							<If Condition="sparse[page] && (*((traits_type::entity_type *)&sparse[page][offset]) < ~traits_type::entity_mask)"> | ||||
| 								<Item Name="[{ pos }]">*((traits_type::entity_type *)&sparse[page][offset]) & traits_type::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="*((traits_type::entity_type *)&packed[pos]) < ~traits_type::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">payload.capacity() * traits_type::page_size</Item> | ||||
| 			<Item Name="[page size]" Optional="true" ExcludeView="simple">traits_type::page_size</Item> | ||||
| 			<Item Name="[length]" Optional="true" ExcludeView="simple">length</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="payload.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::traits_type::entity_type *)&base_type::packed[pos]) < ~base_type::traits_type::entity_mask"> | ||||
| 						<Item Name="[{ pos }:{ base_type::packed[pos] }]">payload[pos / traits_type::page_size][pos & (traits_type::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> | ||||
							
								
								
									
										55
									
								
								external/entt/entt/natvis/entt/signal.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								external/entt/entt/natvis/entt/signal.natvis
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| <?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.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> | ||||
| 		</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 .. | ||||
							
								
								
									
										88701
									
								
								external/entt/entt/single_include/entt/entt.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										88701
									
								
								external/entt/entt/single_include/entt/entt.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										83
									
								
								external/entt/entt/src/entt/config/config.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								external/entt/entt/src/entt/config/config.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| #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 | ||||
|  | ||||
| #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); | ||||
|  | ||||
| #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 12 | ||||
| #define ENTT_VERSION_PATCH 2 | ||||
|  | ||||
| #define ENTT_VERSION \ | ||||
|     ENTT_XSTR(ENTT_VERSION_MAJOR) \ | ||||
|     "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1054
									
								
								external/entt/entt/src/entt/container/dense_map.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1054
									
								
								external/entt/entt/src/entt/container/dense_map.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										889
									
								
								external/entt/entt/src/entt/container/dense_set.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										889
									
								
								external/entt/entt/src/entt/container/dense_set.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,889 @@ | ||||
| #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 Lhs, typename Rhs> | ||||
|     friend constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept; | ||||
|  | ||||
|     template<typename Lhs, typename Rhs> | ||||
|     friend constexpr bool operator==(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept; | ||||
|  | ||||
|     template<typename Lhs, typename Rhs> | ||||
|     friend constexpr bool operator<(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept; | ||||
|  | ||||
| private: | ||||
|     It it; | ||||
| }; | ||||
|  | ||||
| template<typename Lhs, typename Rhs> | ||||
| [[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept { | ||||
|     return lhs.it - rhs.it; | ||||
| } | ||||
|  | ||||
| template<typename Lhs, typename Rhs> | ||||
| [[nodiscard]] constexpr bool operator==(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept { | ||||
|     return lhs.it == rhs.it; | ||||
| } | ||||
|  | ||||
| template<typename Lhs, typename Rhs> | ||||
| [[nodiscard]] constexpr bool operator!=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept { | ||||
|     return !(lhs == rhs); | ||||
| } | ||||
|  | ||||
| template<typename Lhs, typename Rhs> | ||||
| [[nodiscard]] constexpr bool operator<(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept { | ||||
|     return lhs.it < rhs.it; | ||||
| } | ||||
|  | ||||
| template<typename Lhs, typename Rhs> | ||||
| [[nodiscard]] constexpr bool operator>(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept { | ||||
|     return rhs < lhs; | ||||
| } | ||||
|  | ||||
| template<typename Lhs, typename Rhs> | ||||
| [[nodiscard]] constexpr bool operator<=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept { | ||||
|     return !(lhs > rhs); | ||||
| } | ||||
|  | ||||
| template<typename Lhs, typename Rhs> | ||||
| [[nodiscard]] constexpr bool operator>=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &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 Lhs, typename Rhs> | ||||
| [[nodiscard]] constexpr bool operator==(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &rhs) noexcept { | ||||
|     return lhs.index() == rhs.index(); | ||||
| } | ||||
|  | ||||
| template<typename Lhs, typename Rhs> | ||||
| [[nodiscard]] constexpr bool operator!=(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &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. | ||||
|      * | ||||
|      * 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. | ||||
|      * @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<typename 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 | ||||
							
								
								
									
										138
									
								
								external/entt/entt/src/entt/core/algorithm.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								external/entt/entt/src/entt/core/algorithm.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | ||||
| #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) { | ||||
|             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) { | ||||
|                 constexpr auto mask = (1 << Bit) - 1; | ||||
|                 constexpr auto buckets = 1 << Bit; | ||||
|  | ||||
|                 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((std::is_lvalue_reference_v<Args> && ...) && (sizeof...(Args) == 1u), "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(std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>> && (sizeof...(Args) != 0u || !std::is_default_constructible_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(std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>> && (sizeof...(Args) != 0u || !std::is_default_constructible_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> | ||||
| [[nodiscard]] 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> | ||||
| [[nodiscard]] 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> | ||||
| [[nodiscard]] 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> | ||||
| [[nodiscard]] 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> | ||||
| [[nodiscard]] 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> | ||||
| [[nodiscard]] 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> | ||||
| [[nodiscard]] 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 traits_type = 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, traits_type::offset}; | ||||
|  | ||||
|         for(; str[base.length]; ++base.length) { | ||||
|             base.hash = (base.hash ^ static_cast<traits_type::type>(str[base.length])) * traits_type::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, traits_type::offset}; | ||||
|  | ||||
|         for(size_type pos{}; pos < len; ++pos) { | ||||
|             base.hash = (base.hash ^ static_cast<traits_type::type>(str[pos])) * traits_type::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 Allocator Type of allocator used to manage memory and elements. | ||||
|  */ | ||||
| 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 = 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<typename... 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<typename 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<typename 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 | ||||
							
								
								
									
										920
									
								
								external/entt/entt/src/entt/core/type_traits.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										920
									
								
								external/entt/entt/src/entt/core/type_traits.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,920 @@ | ||||
| #ifndef ENTT_CORE_TYPE_TRAITS_HPP | ||||
| #define ENTT_CORE_TYPE_TRAITS_HPP | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <iterator> | ||||
| #include <tuple> | ||||
| #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. | ||||
|  */ | ||||
| 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::bool_constant<(std::is_same_v<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 type. */ | ||||
|     using type = decltype(Value); | ||||
|     /*! @brief Searched value. */ | ||||
|     static constexpr auto value = Value; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam Index Index of the type to return. | ||||
|  * @tparam List Value list to search into. | ||||
|  */ | ||||
| template<std::size_t Index, typename List> | ||||
| using value_list_element_t = typename value_list_element<Index, List>::type; | ||||
|  | ||||
| /** | ||||
|  * @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 Primary template isn't defined on purpose. */ | ||||
| template<auto, typename> | ||||
| struct value_list_index; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides compile-time type access to the values of a value list. | ||||
|  * @tparam Value Value to look for and for which to return the index. | ||||
|  * @tparam First First value provided by the value list. | ||||
|  * @tparam Other Other values provided by the value list. | ||||
|  */ | ||||
| template<auto Value, auto First, auto... Other> | ||||
| struct value_list_index<Value, value_list<First, Other...>> { | ||||
|     /*! @brief Unsigned integer type. */ | ||||
|     using value_type = std::size_t; | ||||
|     /*! @brief Compile-time position of the given value in the sublist. */ | ||||
|     static constexpr value_type value = 1u + value_list_index<Value, value_list<Other...>>::value; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides compile-time type access to the values of a value list. | ||||
|  * @tparam Value Value to look for and for which to return the index. | ||||
|  * @tparam Other Other values provided by the value list. | ||||
|  */ | ||||
| template<auto Value, auto... Other> | ||||
| struct value_list_index<Value, value_list<Value, Other...>> { | ||||
|     static_assert(value_list_index<Value, value_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 value in the sublist. */ | ||||
|     static constexpr value_type value = 0u; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides compile-time type access to the values of a value list. | ||||
|  * @tparam Value Value to look for and for which to return the index. | ||||
|  */ | ||||
| template<auto Value> | ||||
| struct value_list_index<Value, value_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 Value list. | ||||
|  * @tparam Value Value to look for and for which to return the index. | ||||
|  */ | ||||
| template<auto Value, typename List> | ||||
| inline constexpr std::size_t value_list_index_v = value_list_index<Value, 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 Primary template isn't defined on purpose. */ | ||||
| template<typename> | ||||
| struct value_list_unique; | ||||
|  | ||||
| /** | ||||
|  * @brief Removes duplicates values from a value list. | ||||
|  * @tparam Value One of the values provided by the given value list. | ||||
|  * @tparam Other The other values provided by the given value list. | ||||
|  */ | ||||
| template<auto Value, auto... Other> | ||||
| struct value_list_unique<value_list<Value, Other...>> { | ||||
|     /*! @brief A value list without duplicate types. */ | ||||
|     using type = std::conditional_t< | ||||
|         ((Value == Other) || ...), | ||||
|         typename value_list_unique<value_list<Other...>>::type, | ||||
|         value_list_cat_t<value_list<Value>, typename value_list_unique<value_list<Other...>>::type>>; | ||||
| }; | ||||
|  | ||||
| /*! @brief Removes duplicates values from a value list. */ | ||||
| template<> | ||||
| struct value_list_unique<value_list<>> { | ||||
|     /*! @brief A value list without duplicate types. */ | ||||
|     using type = value_list<>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam Type A value list. | ||||
|  */ | ||||
| template<typename Type> | ||||
| using value_list_unique_t = typename value_list_unique<Type>::type; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides the member constant `value` to true if a value list contains | ||||
|  * a given value, false otherwise. | ||||
|  * @tparam List Value list. | ||||
|  * @tparam Value Value to look for. | ||||
|  */ | ||||
| template<typename List, auto Value> | ||||
| struct value_list_contains; | ||||
|  | ||||
| /** | ||||
|  * @copybrief value_list_contains | ||||
|  * @tparam Value Values provided by the value list. | ||||
|  * @tparam Other Value to look for. | ||||
|  */ | ||||
| template<auto... Value, auto Other> | ||||
| struct value_list_contains<value_list<Value...>, Other> | ||||
|     : std::bool_constant<((Value == Other) || ...)> {}; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper variable template. | ||||
|  * @tparam List Value list. | ||||
|  * @tparam Value Value to look for. | ||||
|  */ | ||||
| template<typename List, auto Value> | ||||
| inline constexpr bool value_list_contains_v = value_list_contains<List, Value>::value; | ||||
|  | ||||
| /*! @brief Primary template isn't defined on purpose. */ | ||||
| template<typename...> | ||||
| class value_list_diff; | ||||
|  | ||||
| /** | ||||
|  * @brief Computes the difference between two value lists. | ||||
|  * @tparam Value Values provided by the first value list. | ||||
|  * @tparam Other Values provided by the second value list. | ||||
|  */ | ||||
| template<auto... Value, auto... Other> | ||||
| class value_list_diff<value_list<Value...>, value_list<Other...>> { | ||||
|     using v141_toolset_workaround = value_list<Other...>; | ||||
|  | ||||
| public: | ||||
|     /*! @brief A value list that is the difference between the two value lists. */ | ||||
|     using type = value_list_cat_t<std::conditional_t<value_list_contains_v<v141_toolset_workaround, Value>, value_list<>, value_list<Value>>...>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Helper type. | ||||
|  * @tparam List Value lists between which to compute the difference. | ||||
|  */ | ||||
| template<typename... List> | ||||
| using value_list_diff_t = typename value_list_diff<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::bool_constant<std::is_empty_v<Type> && !std::is_final_v<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>)> {}; | ||||
|  | ||||
| /*! @copydoc is_equality_comparable */ | ||||
| template<typename Type, auto N> | ||||
| struct is_equality_comparable<Type[N]>: std::false_type {}; | ||||
|  | ||||
| /** | ||||
|  * @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 | ||||
|  | ||||
| template<typename... Type> | ||||
| struct std::tuple_size<entt::type_list<Type...>>: std::integral_constant<std::size_t, entt::type_list<Type...>::size> {}; | ||||
|  | ||||
| template<std::size_t Index, typename... Type> | ||||
| struct std::tuple_element<Index, entt::type_list<Type...>>: entt::type_list_element<Index, entt::type_list<Type...>> {}; | ||||
|  | ||||
| template<auto... Value> | ||||
| struct std::tuple_size<entt::value_list<Value...>>: std::integral_constant<std::size_t, entt::value_list<Value...>::size> {}; | ||||
|  | ||||
| template<std::size_t Index, auto... Value> | ||||
| struct std::tuple_element<Index, entt::value_list<Value...>>: entt::value_list_element<Index, entt::value_list<Value...>> {}; | ||||
|  | ||||
| #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<typename 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<typename... Func> | ||||
| struct overloaded: Func... { | ||||
|     using Func::operator()...; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Deduction guide. | ||||
|  * @tparam Func Types of function objects. | ||||
|  */ | ||||
| template<typename... Func> | ||||
| overloaded(Func...) -> overloaded<Func...>; | ||||
|  | ||||
| /** | ||||
|  * @brief Basic implementation of a y-combinator. | ||||
|  * @tparam Func Type of a potentially recursive function. | ||||
|  */ | ||||
| template<typename 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<typename... 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<typename... 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" | ||||
| #include "fwd.hpp" | ||||
|  | ||||
| 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<> | ||||
| struct in_place_delete<void>: std::false_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<> | ||||
| struct page_size<void>: std::integral_constant<std::size_t, 0u> {}; | ||||
|  | ||||
| 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; | ||||
| }; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										379
									
								
								external/entt/entt/src/entt/entity/entity.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										379
									
								
								external/entt/entt/src/entt/entity/entity.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,379 @@ | ||||
| #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 { | ||||
|  | ||||
| // waiting for C++20 (and std::popcount) | ||||
| template<typename Type> | ||||
| static constexpr int popcount(Type value) noexcept { | ||||
|     return value ? (int(value & 1) + popcount(value >> 1)) : 0; | ||||
| } | ||||
|  | ||||
| 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>> { | ||||
|     using value_type = Type; | ||||
| }; | ||||
|  | ||||
| template<typename Type> | ||||
| struct entt_traits<Type, std::enable_if_t<std::is_class_v<Type>>> | ||||
|     : entt_traits<typename Type::entity_type> { | ||||
|     using value_type = Type; | ||||
| }; | ||||
|  | ||||
| template<> | ||||
| struct entt_traits<std::uint32_t> { | ||||
|     using value_type = 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; | ||||
| }; | ||||
|  | ||||
| template<> | ||||
| struct entt_traits<std::uint64_t> { | ||||
|     using value_type = 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; | ||||
| }; | ||||
|  | ||||
| } // namespace internal | ||||
|  | ||||
| /** | ||||
|  * Internal details not to be documented. | ||||
|  * @endcond | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @brief Common basic entity traits implementation. | ||||
|  * @tparam Traits Actual entity traits to use. | ||||
|  */ | ||||
| template<typename Traits> | ||||
| class basic_entt_traits { | ||||
|     static constexpr auto length = internal::popcount(Traits::entity_mask); | ||||
|  | ||||
|     static_assert(Traits::entity_mask && ((typename Traits::entity_type{1} << length) == (Traits::entity_mask + 1)), "Invalid entity mask"); | ||||
|     static_assert((typename Traits::entity_type{1} << internal::popcount(Traits::version_mask)) == (Traits::version_mask + 1), "Invalid version mask"); | ||||
|  | ||||
| public: | ||||
|     /*! @brief Value type. */ | ||||
|     using value_type = typename Traits::value_type; | ||||
|     /*! @brief Underlying entity type. */ | ||||
|     using entity_type = typename Traits::entity_type; | ||||
|     /*! @brief Underlying version type. */ | ||||
|     using version_type = typename Traits::version_type; | ||||
|  | ||||
|     /*! @brief Entity mask size. */ | ||||
|     static constexpr entity_type entity_mask = Traits::entity_mask; | ||||
|     /*! @brief Version mask size */ | ||||
|     static constexpr entity_type version_mask = Traits::version_mask; | ||||
|  | ||||
|     /** | ||||
|      * @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) & 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 static_cast<version_type>(to_integral(value) >> length); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns the successor of a given identifier. | ||||
|      * @param value The identifier of which to return the successor. | ||||
|      * @return The successor of the given identifier. | ||||
|      */ | ||||
|     [[nodiscard]] static constexpr value_type next(const value_type value) noexcept { | ||||
|         const auto vers = to_version(value) + 1; | ||||
|         return construct(to_entity(value), static_cast<version_type>(vers + (vers == version_mask))); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @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 & entity_mask) | (static_cast<entity_type>(version) << length)}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @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 = (version_mask << length); | ||||
|         return value_type{(lhs & entity_mask) | (rhs & mask)}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Entity traits. | ||||
|  * @tparam Type Type of identifier. | ||||
|  */ | ||||
| template<typename Type> | ||||
| struct entt_traits: basic_entt_traits<internal::entt_traits<Type>> { | ||||
|     /*! @brief Base type. */ | ||||
|     using base_type = basic_entt_traits<internal::entt_traits<Type>>; | ||||
|     /*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */ | ||||
|     static constexpr std::size_t page_size = ENTT_SPARSE_PAGE; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @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 traits_type = entt_traits<Entity>; | ||||
|         constexpr auto value = traits_type::construct(traits_type::entity_mask, traits_type::version_mask); | ||||
|         return value; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @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 traits_type = entt_traits<Entity>; | ||||
|         return traits_type::to_entity(entity) == traits_type::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 traits_type = entt_traits<Entity>; | ||||
|         constexpr auto value = traits_type::construct(traits_type::entity_mask, traits_type::version_mask); | ||||
|         return value; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @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 traits_type = entt_traits<Entity>; | ||||
|         return traits_type::to_version(entity) == traits_type::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 | ||||
							
								
								
									
										257
									
								
								external/entt/entt/src/entt/entity/fwd.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								external/entt/entt/src/entt/entity/fwd.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,257 @@ | ||||
| #ifndef ENTT_ENTITY_FWD_HPP | ||||
| #define ENTT_ENTITY_FWD_HPP | ||||
|  | ||||
| #include <cstdint> | ||||
| #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 {}; | ||||
|  | ||||
| /*! @brief Storage 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 | ||||
| }; | ||||
|  | ||||
| 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_mixin; | ||||
|  | ||||
| /** | ||||
|  * @brief Provides a common way to define storage types. | ||||
|  * @tparam Type Storage value type. | ||||
|  * @tparam Entity A valid entity type. | ||||
|  * @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_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. | ||||
|  * @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, typename Mask = std::uint32_t, typename = std::allocator<Mask>> | ||||
| 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> | ||||
| struct exclude_t final: type_list<Type...> { | ||||
|     /*! @brief Default constructor. */ | ||||
|     explicit constexpr exclude_t() {} | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @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> | ||||
| struct get_t final: type_list<Type...> { | ||||
|     /*! @brief Default constructor. */ | ||||
|     explicit constexpr get_t() {} | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @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> | ||||
| struct owned_t final: type_list<Type...> { | ||||
|     /*! @brief Default constructor. */ | ||||
|     explicit constexpr owned_t() {} | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Variable template for lists of owned components. | ||||
|  * @tparam Type List of types. | ||||
|  */ | ||||
| template<typename... Type> | ||||
| inline constexpr owned_t<Type...> owned{}; | ||||
|  | ||||
| /** | ||||
|  * @brief Applies a given _function_ to a get list and generate a new list. | ||||
|  * @tparam Type Types provided by the get 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<get_t<Type...>, Op> { | ||||
|     /*! @brief Resulting get list after applying the transform function. */ | ||||
|     using type = get_t<typename Op<Type>::type...>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Applies a given _function_ to an exclude list and generate a new list. | ||||
|  * @tparam Type Types provided by the exclude 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<exclude_t<Type...>, Op> { | ||||
|     /*! @brief Resulting exclude list after applying the transform function. */ | ||||
|     using type = exclude_t<typename Op<Type>::type...>; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Applies a given _function_ to an owned list and generate a new list. | ||||
|  * @tparam Type Types provided by the owned 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<owned_t<Type...>, Op> { | ||||
|     /*! @brief Resulting owned list after applying the transform function. */ | ||||
|     using type = owned_t<typename Op<Type>::type...>; | ||||
| }; | ||||
|  | ||||
| /*! @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 | ||||
							
								
								
									
										1084
									
								
								external/entt/entt/src/entt/entity/group.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1084
									
								
								external/entt/entt/src/entt/entity/group.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										384
									
								
								external/entt/entt/src/entt/entity/handle.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								external/entt/entt/src/entt/entity/handle.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,384 @@ | ||||
| #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. | ||||
|      * @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(std::exchange(entt, null)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Destroys the entity associated with a handle. | ||||
|      * @param version A desired version upon destruction. | ||||
|      */ | ||||
|     void destroy(const version_type version) { | ||||
|         reg->destroy(std::exchange(entt, null), 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 | ||||
							
								
								
									
										258
									
								
								external/entt/entt/src/entt/entity/helper.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								external/entt/entt/src/entt/entity/helper.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,258 @@ | ||||
| #ifndef ENTT_ENTITY_HELPER_HPP | ||||
| #define ENTT_ENTITY_HELPER_HPP | ||||
|  | ||||
| #include <memory> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include "../core/fwd.hpp" | ||||
| #include "../core/type_traits.hpp" | ||||
| #include "../signal/delegate.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 = 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 = 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) { | ||||
|     if(const auto *storage = reg.template storage<Component>(); storage) { | ||||
|         constexpr auto page_size = std::remove_const_t<std::remove_pointer_t<decltype(storage)>>::traits_type::page_size; | ||||
|         const typename Registry::common_type &base = *storage; | ||||
|         const auto *addr = std::addressof(instance); | ||||
|  | ||||
|         for(auto it = base.rbegin(), last = base.rend(); it < last; it += page_size) { | ||||
|             if(const auto dist = (addr - std::addressof(storage->get(*it))); dist >= 0 && dist < static_cast<decltype(dist)>(page_size)) { | ||||
|                 return *(it + dist); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return null; | ||||
| } | ||||
|  | ||||
| /*! @brief Primary template isn't defined on purpose. */ | ||||
| template<typename...> | ||||
| struct sigh_helper; | ||||
|  | ||||
| /** | ||||
|  * @brief Signal connection helper for registries. | ||||
|  * @tparam Registry Basic registry type. | ||||
|  */ | ||||
| template<typename Registry> | ||||
| struct sigh_helper<Registry> { | ||||
|     /*! @brief Registry type. */ | ||||
|     using registry_type = Registry; | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a helper for a given registry. | ||||
|      * @param ref A valid reference to a registry. | ||||
|      */ | ||||
|     sigh_helper(registry_type &ref) | ||||
|         : bucket{&ref} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Binds a properly initialized helper to a given signal type. | ||||
|      * @tparam Type Type of signal to bind the helper to. | ||||
|      * @param id Optional name for the underlying storage to use. | ||||
|      * @return A helper for a given registry and signal type. | ||||
|      */ | ||||
|     template<typename Type> | ||||
|     auto with(const id_type id = type_hash<Type>::value()) noexcept { | ||||
|         return sigh_helper<registry_type, Type>{*bucket, id}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Returns a reference to the underlying registry. | ||||
|      * @return A reference to the underlying registry. | ||||
|      */ | ||||
|     [[nodiscard]] registry_type ®istry() noexcept { | ||||
|         return *bucket; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     registry_type *bucket; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Signal connection helper for registries. | ||||
|  * @tparam Registry Basic registry type. | ||||
|  * @tparam Type Type of signal to connect listeners to. | ||||
|  */ | ||||
| template<typename Registry, typename Type> | ||||
| struct sigh_helper<Registry, Type> final: sigh_helper<Registry> { | ||||
|     /*! @brief Registry type. */ | ||||
|     using registry_type = Registry; | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs a helper for a given registry. | ||||
|      * @param ref A valid reference to a registry. | ||||
|      * @param id Optional name for the underlying storage to use. | ||||
|      */ | ||||
|     sigh_helper(registry_type &ref, const id_type id = type_hash<Type>::value()) | ||||
|         : sigh_helper<Registry>{ref}, | ||||
|           name{id} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Forwards the call to `on_construct` on the underlying storage. | ||||
|      * @tparam Candidate Function or member to connect. | ||||
|      * @tparam Args Type of class or type of payload, if any. | ||||
|      * @param args A valid object that fits the purpose, if any. | ||||
|      * @return This helper. | ||||
|      */ | ||||
|     template<auto Candidate, typename... Args> | ||||
|     auto on_construct(Args &&...args) { | ||||
|         this->registry().template on_construct<Type>(name).template connect<Candidate>(std::forward<Args>(args)...); | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Forwards the call to `on_update` on the underlying storage. | ||||
|      * @tparam Candidate Function or member to connect. | ||||
|      * @tparam Args Type of class or type of payload, if any. | ||||
|      * @param args A valid object that fits the purpose, if any. | ||||
|      * @return This helper. | ||||
|      */ | ||||
|     template<auto Candidate, typename... Args> | ||||
|     auto on_update(Args &&...args) { | ||||
|         this->registry().template on_update<Type>(name).template connect<Candidate>(std::forward<Args>(args)...); | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Forwards the call to `on_destroy` on the underlying storage. | ||||
|      * @tparam Candidate Function or member to connect. | ||||
|      * @tparam Args Type of class or type of payload, if any. | ||||
|      * @param args A valid object that fits the purpose, if any. | ||||
|      * @return This helper. | ||||
|      */ | ||||
|     template<auto Candidate, typename... Args> | ||||
|     auto on_destroy(Args &&...args) { | ||||
|         this->registry().template on_destroy<Type>(name).template connect<Candidate>(std::forward<Args>(args)...); | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     id_type name; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Deduction guide. | ||||
|  * @tparam Registry Basic registry type. | ||||
|  */ | ||||
| template<typename Registry> | ||||
| sigh_helper(Registry &) -> sigh_helper<Registry>; | ||||
|  | ||||
| } // namespace entt | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										293
									
								
								external/entt/entt/src/entt/entity/mixin.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								external/entt/entt/src/entt/entity/mixin.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,293 @@ | ||||
| #ifndef ENTT_ENTITY_MIXIN_HPP | ||||
| #define ENTT_ENTITY_MIXIN_HPP | ||||
|  | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include "../config/config.h" | ||||
| #include "../core/any.hpp" | ||||
| #include "../signal/sigh.hpp" | ||||
| #include "entity.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_mixin final: public Type { | ||||
|     using underlying_type = Type; | ||||
|     using basic_registry_type = basic_registry<typename underlying_type::entity_type, typename underlying_type::base_type::allocator_type>; | ||||
|     using sigh_type = sigh<void(basic_registry_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>; | ||||
|     using underlying_iterator = typename underlying_type::base_type::basic_iterator; | ||||
|  | ||||
|     basic_registry_type &owner_or_assert() const noexcept { | ||||
|         ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); | ||||
|         return *owner; | ||||
|     } | ||||
|  | ||||
|     void pop(underlying_iterator first, underlying_iterator last) final { | ||||
|         if(auto ® = owner_or_assert(); destruction.empty()) { | ||||
|             underlying_type::pop(first, last); | ||||
|         } else { | ||||
|             for(; first != last; ++first) { | ||||
|                 const auto entt = *first; | ||||
|                 destruction.publish(reg, entt); | ||||
|                 const auto it = underlying_type::find(entt); | ||||
|                 underlying_type::pop(it, it + 1u); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void pop_all() final { | ||||
|         if(auto ® = owner_or_assert(); !destruction.empty()) { | ||||
|             for(auto pos = underlying_type::each().begin().base().index(); !(pos < 0); --pos) { | ||||
|                 if constexpr(underlying_type::traits_type::in_place_delete) { | ||||
|                     if(const auto entt = underlying_type::operator[](static_cast<typename underlying_type::size_type>(pos)); entt != tombstone) { | ||||
|                         destruction.publish(reg, entt); | ||||
|                     } | ||||
|                 } else { | ||||
|                     destruction.publish(reg, underlying_type::operator[](static_cast<typename underlying_type::size_type>(pos))); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         underlying_type::pop_all(); | ||||
|     } | ||||
|  | ||||
|     underlying_iterator try_emplace(const typename underlying_type::entity_type entt, const bool force_back, const void *value) final { | ||||
|         const auto it = underlying_type::try_emplace(entt, force_back, value); | ||||
|  | ||||
|         if(auto ® = owner_or_assert(); it != underlying_type::base_type::end()) { | ||||
|             construction.publish(reg, *it); | ||||
|         } | ||||
|  | ||||
|         return it; | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     /*! @brief Allocator type. */ | ||||
|     using allocator_type = typename underlying_type::allocator_type; | ||||
|     /*! @brief Underlying entity identifier. */ | ||||
|     using entity_type = typename underlying_type::entity_type; | ||||
|     /*! @brief Expected registry type. */ | ||||
|     using registry_type = basic_registry_type; | ||||
|  | ||||
|     /*! @brief Default constructor. */ | ||||
|     sigh_mixin() | ||||
|         : sigh_mixin{allocator_type{}} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Constructs an empty storage with a given allocator. | ||||
|      * @param allocator The allocator to use. | ||||
|      */ | ||||
|     explicit sigh_mixin(const allocator_type &allocator) | ||||
|         : underlying_type{allocator}, | ||||
|           owner{}, | ||||
|           construction{allocator}, | ||||
|           destruction{allocator}, | ||||
|           update{allocator} {} | ||||
|  | ||||
|     /** | ||||
|      * @brief Move constructor. | ||||
|      * @param other The instance to move from. | ||||
|      */ | ||||
|     sigh_mixin(sigh_mixin &&other) noexcept | ||||
|         : underlying_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_mixin(sigh_mixin &&other, const allocator_type &allocator) noexcept | ||||
|         : underlying_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_mixin &operator=(sigh_mixin &&other) noexcept { | ||||
|         underlying_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_mixin &other) { | ||||
|         using std::swap; | ||||
|         underlying_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 Emplace elements into a storage. | ||||
|      * | ||||
|      * The behavior of this operation depends on the underlying storage type | ||||
|      * (for example, components vs entities).<br/> | ||||
|      * Refer to the specific documentation for more details. | ||||
|      * | ||||
|      * @return A return value as returned by the underlying storage. | ||||
|      */ | ||||
|     auto emplace() { | ||||
|         const auto entt = underlying_type::emplace(); | ||||
|         construction.publish(owner_or_assert(), entt); | ||||
|         return entt; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Emplace elements into a storage. | ||||
|      * | ||||
|      * The behavior of this operation depends on the underlying storage type | ||||
|      * (for example, components vs entities).<br/> | ||||
|      * Refer to the specific documentation for more details. | ||||
|      * | ||||
|      * @tparam Args Types of arguments to forward to the underlying storage. | ||||
|      * @param hint A valid identifier. | ||||
|      * @param args Parameters to forward to the underlying storage. | ||||
|      * @return A return value as returned by the underlying storage. | ||||
|      */ | ||||
|     template<typename... Args> | ||||
|     decltype(auto) emplace(const entity_type hint, Args &&...args) { | ||||
|         if constexpr(std::is_same_v<typename underlying_type::value_type, typename underlying_type::entity_type>) { | ||||
|             const auto entt = underlying_type::emplace(hint, std::forward<Args>(args)...); | ||||
|             construction.publish(owner_or_assert(), entt); | ||||
|             return entt; | ||||
|         } else { | ||||
|             underlying_type::emplace(hint, std::forward<Args>(args)...); | ||||
|             construction.publish(owner_or_assert(), hint); | ||||
|             return this->get(hint); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @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) { | ||||
|         underlying_type::patch(entt, std::forward<Func>(func)...); | ||||
|         update.publish(owner_or_assert(), entt); | ||||
|         return this->get(entt); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @brief Emplace elements into a storage. | ||||
|      * | ||||
|      * The behavior of this operation depends on the underlying storage type | ||||
|      * (for example, components vs entities).<br/> | ||||
|      * Refer to the specific documentation for more details. | ||||
|      * | ||||
|      * @tparam It Iterator type (as required by the underlying storage type). | ||||
|      * @tparam Args Types of arguments to forward to the underlying storage. | ||||
|      * @param first An iterator to the first element of the range. | ||||
|      * @param last An iterator past the last element of the range. | ||||
|      * @param args Parameters to use to forward to the underlying storage. | ||||
|      */ | ||||
|     template<typename It, typename... Args> | ||||
|     void insert(It first, It last, Args &&...args) { | ||||
|         underlying_type::insert(first, last, std::forward<Args>(args)...); | ||||
|  | ||||
|         if(auto ® = owner_or_assert(); !construction.empty()) { | ||||
|             for(; first != last; ++first) { | ||||
|                 construction.publish(reg, *first); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @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; | ||||
|         underlying_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