Compare commits
	
		
			361 Commits
		
	
	
		
			f077a29cf0
			...
			dev-4b0d95
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 4b0d9595ac | |||
| 5ac318d1bf | |||
| eaa8f1dd16 | |||
| b88fffd959 | |||
| 858b9dfcfa | |||
| bc8b631b84 | |||
| 52278f6726 | |||
| 29fd1bfb62 | |||
| 998000aa3a | |||
| e66f4651d0 | |||
| 854d09f05c | |||
| 2d6a9acbb6 | |||
| b7f0ad6c9a | |||
| 43f8c22570 | |||
| 3c7bd2e2cb | |||
| dadc72c8e0 | |||
| 5dd9834009 | |||
| 7ee4ed0020 | |||
| 3d557f91d8 | |||
| 85edd0eab6 | |||
| cedb63b87a | |||
| 14f1d1d37f | |||
|  | 8c24234126 | ||
| e0d873d41c | |||
| 5728432b76 | |||
| 0030487613 | |||
| f932f5ffb4 | |||
| da83065024 | |||
| a6614e76ce | |||
| cdd67f4779 | |||
| a845609660 | |||
| de3b8f059e | |||
| 7b4af58544 | |||
| f287348550 | |||
| 498b4435c7 | |||
| a5e67d0ee8 | |||
| 9e30983b22 | |||
| 195a87b8ab | |||
| dfbb1dea68 | |||
| 2597edd579 | |||
| 85a29372f4 | |||
| a9f6a5d763 | |||
| 73180195fe | |||
| 10b689ca95 | |||
| 3796841961 | |||
| 854ed851b4 | |||
| 5c3b797a99 | |||
| 8a580e2fbb | |||
| 3cede91aa0 | |||
| 0610a6a64a | |||
| 26d07b06db | |||
| fd0b210bbb | |||
| 268cbe137e | |||
| 31bb0d3e61 | |||
| 248f68f6a2 | |||
| 3b010bd16f | |||
| 7e285290fe | |||
| 5767834f71 | |||
| 53ce292e82 | |||
| 84bd24807d | |||
| 8d0518c2e3 | |||
| 6d150ba441 | |||
| c737715c66 | |||
| b640b5a06b | |||
| 1b9363e7b5 | |||
| 16d2238f35 | |||
| 19844a9423 | |||
| 19fd99f713 | |||
| f22f523774 | |||
| 8b17ed195f | |||
| def7fc1959 | |||
| 318be9cd62 | |||
| 2772c8ee69 | |||
| eac2927379 | |||
| 77a0ae6acd | |||
| 7879a0927b | |||
| 88ea3e177d | |||
| bc22451524 | |||
| 7b8e93eec3 | |||
| 71be5c3c6e | |||
| 2b8cee6a29 | |||
| 5bf4640d61 | |||
| 0e0e81720b | |||
| 592a4cb9cf | |||
| 93f60bd073 | |||
| 6a6de77ae9 | |||
| 89f065a610 | |||
| 52e95ca654 | |||
| eaa316a2aa | |||
| bdf4e60f2f | |||
| 2e3c779bec | |||
| 461a4f1aa7 | |||
| 78488daa9b | |||
| 22f2c8f514 | |||
| e442191aad | |||
| 795ab2d4e1 | |||
| 0896038dd6 | |||
| 67c6f9adb0 | |||
| 6aac44cda9 | |||
| 4fb2b51b7d | |||
| 182d844e32 | |||
| 6f511016bc | |||
| fb885b5c21 | |||
| 527a7c63f6 | |||
| d21dbb43e2 | |||
| 7ac62274f4 | |||
| 4ec87337c8 | |||
| 20f7c6d011 | |||
| 24dc5a03f3 | |||
| 3d0863ff9a | |||
| 97aedca844 | |||
| 2e7d5538d1 | |||
| 1bfd04680e | |||
| 73d1d65142 | |||
| f6e55851cc | |||
| 0b0245d844 | |||
| d278391528 | |||
| aa7a5d6013 | |||
| 84987216cb | |||
| 58e9fd5514 | |||
| 3d41eedf48 | |||
| 2bc30ffcdc | |||
| e67d7d37b5 | |||
| 98ab974515 | |||
| 267f8dffc1 | |||
| b38a1a2507 | |||
| ee87dbc532 | |||
| 78c7ef5b46 | |||
| 95ec596cfd | |||
| 47ad96e2b6 | |||
| 396477f66b | |||
| 01edf9e76e | |||
| bde0f2c7c3 | |||
| 83bbac2cd1 | |||
| d5dede5a61 | |||
| 719400068a | |||
| aaf8c6adc1 | |||
| dc081ae2aa | |||
| 3cf3097094 | |||
| a5093c4aa3 | |||
| e801626232 | |||
| 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 | ||||||
							
								
								
									
										225
									
								
								.github/workflows/cd.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								.github/workflows/cd.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,225 @@ | |||||||
|  | name: ContinuousDelivery | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     branches: [ master ] | ||||||
|  |   pull_request: | ||||||
|  |     branches: [ master ] | ||||||
|  |  | ||||||
|  | env: | ||||||
|  |   BUILD_TYPE: RelWithDebInfo | ||||||
|  |   BRANCH_NAME: ${{ github.head_ref || github.ref_name }} | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   linux-ubuntu: | ||||||
|  |     timeout-minutes: 10 | ||||||
|  |  | ||||||
|  |     runs-on: ubuntu-20.04 | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |     - uses: actions/checkout@v4 | ||||||
|  |       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=dev-${SHORT_HASH}" >> $GITHUB_OUTPUT | ||||||
|  |         else | ||||||
|  |           SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-') | ||||||
|  |           echo "name=dev-${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@v4 | ||||||
|  |       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 | ||||||
|  |  | ||||||
|  |     ## sdl_image vendored needs nasm for dav1d | ||||||
|  |     #- uses: ilammy/setup-nasm@v1 | ||||||
|  |  | ||||||
|  |     - 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 -DSDL3IMAGE_VENDORED=ON -DSDL3IMAGE_DEPS_SHARED=ON -DSDL3IMAGE_JXL=OFF -DSDL3IMAGE_AVIF=OFF | ||||||
|  |  | ||||||
|  |     - 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=dev-${SHORT_HASH}" >> $GITHUB_OUTPUT | ||||||
|  |         else | ||||||
|  |           SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-') | ||||||
|  |           echo "name=dev-${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@v4 | ||||||
|  |       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 | ||||||
|  |  | ||||||
|  |     ## sdl_image vendored needs nasm for dav1d | ||||||
|  |     #- uses: ilammy/setup-nasm@v1 | ||||||
|  |  | ||||||
|  |     - 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 -DSDL3IMAGE_VENDORED=ON -DSDL3IMAGE_DEPS_SHARED=ON -DSDL3IMAGE_JXL=OFF -DSDL3IMAGE_AVIF=OFF | ||||||
|  |  | ||||||
|  |     - 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=dev-${SHORT_HASH}" >> $GITHUB_OUTPUT | ||||||
|  |         else | ||||||
|  |           SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-') | ||||||
|  |           echo "name=dev-${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@v4 | ||||||
|  |       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=dev-${SHORT_HASH}" >> $GITHUB_OUTPUT | ||||||
|  |         else | ||||||
|  |           SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-') | ||||||
|  |           echo "name=dev-${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="${tag#v}" \ | ||||||
|  |             --notes="preview build of the latest commit" \ | ||||||
|  |             --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" | ||||||
|  |  | ||||||
							
								
								
									
										77
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | |||||||
|  | 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@v4 | ||||||
|  |       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@v4 | ||||||
|  |       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: 15 | ||||||
|  |  | ||||||
|  |     runs-on: windows-latest | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |     - uses: actions/checkout@v4 | ||||||
|  |       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 | ||||||
|  |  | ||||||
|  |     ## sdl_image vendored needs nasm for dav1d | ||||||
|  |     #- uses: ilammy/setup-nasm@v1 | ||||||
|  |  | ||||||
|  |     - 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 -DSDL3IMAGE_VENDORED=ON -DSDL3IMAGE_DEPS_SHARED=ON -DSDL3IMAGE_JXL=OFF -DSDL3IMAGE_AVIF=OFF | ||||||
|  |  | ||||||
|  |     - 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 | ||||||
							
								
								
									
										10
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.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"] | [submodule "external/solanaceae_toxcore"] | ||||||
| 	path = external/solanaceae_toxcore | 	path = external/solanaceae_toxcore | ||||||
| 	url = https://github.com/Green-Sky/solanaceae_toxcore.git | 	url = https://github.com/Green-Sky/solanaceae_toxcore.git | ||||||
| @@ -16,3 +20,9 @@ | |||||||
| [submodule "external/solanaceae_plugin"] | [submodule "external/solanaceae_plugin"] | ||||||
| 	path = external/solanaceae_plugin | 	path = external/solanaceae_plugin | ||||||
| 	url = https://github.com/Green-Sky/solanaceae_plugin.git | 	url = https://github.com/Green-Sky/solanaceae_plugin.git | ||||||
|  | [submodule "external/solanaceae_object_store"] | ||||||
|  | 	path = external/solanaceae_object_store | ||||||
|  | 	url = https://github.com/Green-Sky/solanaceae_object_store.git | ||||||
|  | [submodule "external/solanaceae_message_serializer"] | ||||||
|  | 	path = external/solanaceae_message_serializer | ||||||
|  | 	url = https://github.com/Green-Sky/solanaceae_message_serializer.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 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								external/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								external/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,10 +1,11 @@ | |||||||
| cmake_minimum_required(VERSION 3.9 FATAL_ERROR) | cmake_minimum_required(VERSION 3.14...3.24 FATAL_ERROR) | ||||||
|  |  | ||||||
| add_subdirectory(./entt) | add_subdirectory(./entt) | ||||||
|  |  | ||||||
| add_subdirectory(./solanaceae_util) | add_subdirectory(./solanaceae_util) | ||||||
| add_subdirectory(./solanaceae_contact) | add_subdirectory(./solanaceae_contact) | ||||||
| add_subdirectory(./solanaceae_message3) | add_subdirectory(./solanaceae_message3) | ||||||
|  | add_subdirectory(./solanaceae_message_serializer) | ||||||
|  |  | ||||||
| add_subdirectory(./solanaceae_plugin) | add_subdirectory(./solanaceae_plugin) | ||||||
|  |  | ||||||
| @@ -12,3 +13,13 @@ add_subdirectory(./toxcore) | |||||||
| add_subdirectory(./solanaceae_toxcore) | add_subdirectory(./solanaceae_toxcore) | ||||||
| add_subdirectory(./solanaceae_tox) | add_subdirectory(./solanaceae_tox) | ||||||
|  |  | ||||||
|  | add_subdirectory(./solanaceae_object_store) | ||||||
|  |  | ||||||
|  | add_subdirectory(./sdl) | ||||||
|  | add_subdirectory(./imgui) | ||||||
|  |  | ||||||
|  | add_subdirectory(./stb) | ||||||
|  | add_subdirectory(./libwebp) | ||||||
|  | add_subdirectory(./qoi) | ||||||
|  | add_subdirectory(./sdl_image) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										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