根据LL重构文件结构

This commit is contained in:
Qiuzhizhe 2023-03-03 10:16:38 -08:00
parent 125df0725f
commit 690132ce0f
4221 changed files with 26691 additions and 24996 deletions

View File

@ -1,55 +1,53 @@
# Documents: https://clang.llvm.org/docs/ClangFormatStyleOptions.html
Language: Cpp
# BasedOnStyle: LLVM
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: true
AlignConsecutiveAssignments: None
AlignConsecutiveDeclarations: None
AlignOperands: Align
AlwaysBreakTemplateDeclarations : true
AlwaysBreakTemplateDeclarations: Yes
AlignTrailingComments: true
AllowAllArgumentsOnNextLine : true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine : true
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AllowShortLambdasOnASingleLine: true
AllowShortFunctionsOnASingleLine: Empty
AllowShortLambdasOnASingleLine: All
AllowShortEnumsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
BinPackArguments: true
BinPackParameters: true
ConstructorInitializerIndentWidth: 0
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ColumnLimit: 0
BreakBeforeConceptDeclarations: Always
RequiresClausePosition: OwnLine
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
PointerAlignment: Left
IndentWidth: 4
SortIncludes: false
SortIncludes: Never
MaxEmptyLinesToKeep: 2
SpacesInSquareBrackets: false
SpacesInParentheses : false
SpacesInParentheses: false
SpaceBeforeAssignmentOperators: true
SpacesInContainerLiterals: true
IndentWrappedFunctionNames: true
KeepEmptyLinesAtTheStartOfBlocks: true
SeparateDefinitionBlocks: Always
BreakConstructorInitializersBeforeComma: true
SpaceAfterCStyleCast: false
IndentCaseLabels: true
TabWidth: 4
UseTab: Never
BreakBeforeBraces: Custom
BraceWrapping:
# case 语句后面
AfterCaseLabel: false
# class定义后面
AfterClass: false
# 控制语句后面
AfterControlStatement: false
# enum定义后面
AfterEnum: false
# 函数定义后面

4
.clangd Normal file
View File

@ -0,0 +1,4 @@
Diagnostics:
Suppress: ["-Wmicrosoft-enum-forward-reference", "-Wc++11-narrowing"]
CompileFlags:
Add: ["-ferror-limit=0", "-D__FUNCTION__=\"dummy\"", "-D_CRT_USE_BUILTIN_OFFSETOF"]

194
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,194 @@
name: Build
on:
workflow_dispatch:
pull_request:
push:
env:
BUILD_TYPE: Release
jobs:
build:
name: Build
# runs-on: self-hosted
runs-on: windows-2022
steps:
- name: Checkout repository
uses: actions/checkout@v3.2.0
with:
fetch-depth: 1
submodules: 'true'
- name: Cache BDS libraries
id: cache-bds-lib
uses: actions/cache@v3
env:
cache-name: cache-bds-lib
with:
path: |
${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_api.lib
${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_var.lib
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('scripts/LINK.txt') }}
- name: Download BDS if not cached
if: steps.cache-bds-lib.outputs.cache-hit != 'true'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
mkdir Tools/Server
ServerLink=$(cat 'scripts/LINK.txt')
curl -L -o Tools/Server/server.zip "$ServerLink"
unzip Tools/Server/server.zip -d Tools/Server/ > /dev/null
shell: bash
- name: Build libraries if not cached
if: steps.cache-bds-lib.outputs.cache-hit != 'true'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
cd Tools
LibraryBuilder.exe Server
mkdir ..\LiteLoader\lib
move bedrock_server_api.lib ..\LiteLoader\lib
move bedrock_server_var.lib ..\LiteLoader\lib
shell: cmd
- name: Get short SHA
id: sha_short
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Set LITELOADER_VERSION_COMMIT_SHA
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
sed -r -i 's/#define\s+LITELOADER_VERSION_COMMIT_SHA\s+.*/#define LITELOADER_VERSION_COMMIT_SHA ${{ steps.sha_short.outputs.sha_short }}\r/' LiteLoader/include/liteloader/Version.h
shell: bash
- name: Configure CMake (MSVC)
run: |
cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
shell: cmd
- name: Build all
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
shell: cmd
- name: Pack output
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target PackOutput
shell: cmd
- name: Pack SDK on push event
if: github.event_name == 'push'
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target PackSDK
shell: cmd
- name: Configure CMake (ClangCL)
run: |
cmake -B ${{github.workspace}}/build_clang -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -T clangcl
shell: cmd
- name: Build SymDBHelper
run: cmake --build ${{github.workspace}}/build_clang --config ${{env.BUILD_TYPE}} --target SymDBHelper
- name: Compress resource packs for LiteLoaderBDS CUI on push event
if: github.event_name == 'push'
run: |
cd build/output/plugins/LiteLoader/ResourcePacks
7z a LiteLoaderBDS-CUI.tar LiteLoaderBDS-CUI
rm -r LiteLoaderBDS-CUI
shell: bash
- name: Update C++ SDK on push event
if: github.event_name == 'push'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
cd scripts
./UploadSDK.cmd action
env:
REPO_KEY: ${{secrets.PUSH_TOKEN}}
USERNAME: github-actions[bot]
shell: cmd
# - name: Download LLMoney
# working-directory: ${{ env.GITHUB_WORKSPACE }}
# run: |
# git clone https://github.com/Tooth-Hub/LLMoney.git LLMoney-bin
# cp LLMoney-bin/LLMoney.dll build/output/plugins/
# shell: bash
- name: Upload LiteLoaderBDS
uses: actions/upload-artifact@v3.1.0
with:
name: LiteLoaderBDS
path: |
${{ github.workspace }}\build\output\LLPeEditor.exe
${{ github.workspace }}\build\output\LLPreLoader.dll
${{ github.workspace }}\build\output\LiteLoader.dll
${{ github.workspace }}\build\output\plugins\lib\
${{ github.workspace }}\build\output\plugins\LiteLoader\LangPack\
${{ github.workspace }}\build\output\plugins\LiteLoader\CrashLogger_Daemon.exe
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Js.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Lua.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.NodeJs.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\7z\
${{ github.workspace }}\build\output\plugins\LiteLoader\ParticleAPI.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\ResourcePacks\LiteLoaderBDS-CUI.tar
${{ github.workspace }}\build\output\plugins\LiteLoader\PermissionAPI.dll
# ${{ github.workspace }}\build\output\plugins\LLMoney.dll
- name: Upload PeEditor
uses: actions/upload-artifact@v3.1.0
with:
name: PeEditor
path: ${{ github.workspace }}\build\output\LLPeEditor.exe
- name: Upload PreLoader
uses: actions/upload-artifact@v3.1.0
with:
name: PreLoader
path: ${{ github.workspace }}\build\output\LLPreLoader.dll
- name: Upload LiteLoader
uses: actions/upload-artifact@v3.1.0
with:
name: LiteLoader
path: |
${{ github.workspace }}\build\output\LiteLoader.dll
${{ github.workspace }}\build\output\plugins\lib\*.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LangPack\
${{ github.workspace }}\build\output\plugins\LiteLoader\7z\
${{ github.workspace }}\build\output\plugins\LiteLoader\CrashLogger_Daemon.exe
- name: Upload ScriptEngine
uses: actions/upload-artifact@v3.1.0
with:
name: ScriptEngine
path: |
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Js.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Lua.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.NodeJs.dll
${{ github.workspace }}\build\output\plugins\lib\node_modules.tar
${{ github.workspace }}\build\output\plugins\lib\package.json
- name: Upload LLParticle
uses: actions/upload-artifact@v3.1.0
with:
name: LLParticle
path: |
${{ github.workspace }}\build\output\plugins\LiteLoader\ParticleAPI.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\ResourcePacks\LiteLoaderBDS-CUI.tar
- name: Upload LLPermission
uses: actions/upload-artifact@v3.1.0
with:
name: LLPermission
path: ${{ github.workspace }}\build\output\plugins\LiteLoader\PermissionAPI.dll
- name: Upload PDB files
uses: actions/upload-artifact@v3.1.0
with:
name: PDB
path: ${{ github.workspace }}\build\pdb\

View File

@ -1,143 +0,0 @@
name: CMake
on:
push:
paths:
- '**.cpp'
- '**.cc'
- '**.cxx'
- '**.c'
- '**.hpp'
- '**.hh'
- '**.hxx'
- '**.h'
- '.github/workflows/cmake.yml'
- '**/CMakeLists.txt'
env:
BUILD_TYPE: Release
jobs:
build:
runs-on: windows-2022
steps:
- uses: actions/checkout@v3.0.2
with:
fetch-depth: 1
#submodules: 'true'
- name: Cache Bedrock Dedicated Server Library
id: cache-bds-lib
uses: actions/cache@v3
env:
cache-name: cache-bds-lib
with:
path: |
${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_api.lib
${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_var.lib
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('Scripts/LINK.txt') }}
- name: Download Server
if: steps.cache-bds-lib.outputs.cache-hit != 'true'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
mkdir Tools/Server
ServerLink=$(cat 'Scripts/LINK.txt')
curl -L -o Tools/Server/server.zip "$ServerLink"
unzip Tools/Server/server.zip -d Tools/Server/ > /dev/null
shell: bash
- name: Build Library
if: steps.cache-bds-lib.outputs.cache-hit != 'true'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
cd Tools
LibraryBuilder.exe Server
shell: cmd
- name: Change LITELOADER_VERSION_STATUS_BETA
working-directory: ${{ env.GITHUB_WORKSPACE }}
if: false == startsWith(github.ref, 'refs/tags/')
run: |
sed -r -i 's/#define\s+LITELOADER_VERSION_STATUS\s+LITELOADER_VERSION_\w+/#define LITELOADER_VERSION_STATUS LITELOADER_VERSION_BETA/' LiteLoader/Main/Version.h
sed -r -i 's/#define\s+LITELOADER_VERSION_ACTIONS\s+.*/#define LITELOADER_VERSION_ACTIONS ${{ github.run_number }}\r/' LiteLoader/Main/Version.h
cat LiteLoader/Main/Version.h
shell: bash
- name: Change LITELOADER_VERSION_STATUS_RELEASE
working-directory: ${{ env.GITHUB_WORKSPACE }}
if: startsWith(github.ref, 'refs/tags/')
run: |
sed -r -i 's/#define\s+LITELOADER_VERSION_STATUS\s+LITELOADER_VERSION_\w+/#define LITELOADER_VERSION_STATUS LITELOADER_VERSION_RELEASE/' LiteLoader/Main/Version.h
sed -r -i 's/#define\s+LITELOADER_VERSION_ACTIONS\s+.*/#define LITELOADER_VERSION_ACTIONS ${{ github.run_number }}\r/' LiteLoader/Main/Version.h
shell: bash
- name: Get MSVC Path
working-directory: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\
run: echo "MSVC_VER=$(ls | tail -n 1)" >> $GITHUB_ENV
shell: bash
- name: Configure CMake(MSVC)
run: |
cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
shell: cmd
- name: Build
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
shell: cmd
- name: Configure CMake(ClangCL)
run: |
cmake -B ${{github.workspace}}/build_clang -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -T clangcl
shell: cmd
- name: Build SymDBHelper
run: cmake --build ${{github.workspace}}/build_clang --config ${{env.BUILD_TYPE}} --target SymDBHelper
- name: Pack Release
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
cd Scripts
./PackRelease.cmd action
shell: cmd
- name: Move PDB to path
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
mkdir PDB
cp x64/Release/*.pdb PDB
shell: bash
- name: Upload LiteLoader
uses: actions/upload-artifact@v3.1.0
with:
name: LiteLoader
path: ${{ github.workspace }}\RELEASE\
- name: Upload PDB
uses: actions/upload-artifact@v3.1.0
with:
name: PDB
path: ${{ github.workspace }}\PDB
- name: Prepare for creating Release
working-directory: ${{ env.GITHUB_WORKSPACE }}
id: rel
if: startsWith(github.ref, 'refs/tags/')
run: |
echo ::set-output name=tag::${GITHUB_REF#refs/*/}
mv LiteLoader.zip LiteLoader-${GITHUB_REF#refs/*/}.zip
shell: bash
- name: Create New Release
uses: softprops/action-gh-release@v0.1.14
if: startsWith(github.ref, 'refs/tags/')
with:
body_path: ${{ github.workspace }}\CHANGELOG.md
files: |
${{ github.workspace }}\LiteLoader-${{ steps.rel.outputs.tag }}.zip
${{ github.workspace }}\PDB.zip
env:
GITHUB_REPOSITORY: quizhizhe/LiteLoaderBDS-1.16.40

267
.github/workflows/publish_release.yml vendored Normal file
View File

@ -0,0 +1,267 @@
name: Release
on:
workflow_dispatch:
inputs:
tag:
required: true
description: 'Release Tag'
status:
required: true
description: 'Release Status (beta, stable)'
env:
BUILD_TYPE: Release
jobs:
build:
name: Build
runs-on: windows-2022
steps:
- name: Checkout repository
uses: actions/checkout@v3.2.0
with:
fetch-depth: 1
submodules: 'true'
- name: Create tag
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag | xargs git tag -d
git tag ${{ github.event.inputs.tag }}
git push origin ${{ github.event.inputs.tag }}
shell: bash
- name: Cache BDS libraries
id: cache-bds-lib
uses: actions/cache@v3
env:
cache-name: cache-bds-lib
with:
path: |
${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_api.lib
${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_var.lib
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('scripts/LINK.txt') }}
- name: Download BDS if not cached
if: steps.cache-bds-lib.outputs.cache-hit != 'true'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
mkdir Tools/Server
ServerLink=$(cat 'scripts/LINK.txt')
curl -L -o Tools/Server/server.zip "$ServerLink"
unzip Tools/Server/server.zip -d Tools/Server/ > /dev/null
shell: bash
- name: Build libraries if not cached
if: steps.cache-bds-lib.outputs.cache-hit != 'true'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
cd Tools
LibraryBuilder.exe Server
mkdir ..\LiteLoader\lib
move bedrock_server_api.lib ..\LiteLoader\lib
move bedrock_server_var.lib ..\LiteLoader\lib
shell: cmd
- name: Get short SHA
id: sha_short
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Set LITELOADER_VERSION_COMMIT_SHA
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
sed -r -i 's/#define\s+LITELOADER_VERSION_COMMIT_SHA\s+.*/#define LITELOADER_VERSION_COMMIT_SHA ${{ steps.sha_short.outputs.sha_short }}\r/' LiteLoader/include/liteloader/Version.h
shell: bash
- name: Set LITELOADER_VERSION_STATUS_BETA
working-directory: ${{ env.GITHUB_WORKSPACE }}
if: github.event.inputs.status == 'beta'
run: |
sed -r -i 's/#define\s+LITELOADER_VERSION_STATUS\s+LITELOADER_VERSION_\w+/#define LITELOADER_VERSION_STATUS LITELOADER_VERSION_BETA/' LiteLoader/include/liteloader/Version.h
shell: bash
- name: Set LITELOADER_VERSION_STATUS_RELEASE
working-directory: ${{ env.GITHUB_WORKSPACE }}
if: github.event.inputs.status == 'stable'
run: |
sed -r -i 's/#define\s+LITELOADER_VERSION_STATUS\s+LITELOADER_VERSION_\w+/#define LITELOADER_VERSION_STATUS LITELOADER_VERSION_RELEASE/' LiteLoader/include/liteloader/Version.h
shell: bash
- name: Configure CMake (MSVC)
run: |
cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
shell: cmd
- name: Build all
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
shell: cmd
- name: Pack output
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target PackOutput
shell: cmd
- name: Pack SDK
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target PackSDK
shell: cmd
- name: Configure CMake (ClangCL)
run: |
cmake -B ${{github.workspace}}/build_clang -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -T clangcl
shell: cmd
- name: Build SymDBHelper
run: cmake --build ${{github.workspace}}/build_clang --config ${{env.BUILD_TYPE}} --target SymDBHelper
- name: Compress resource packs for LiteLoaderBDS
run: |
cd build/output/plugins/LiteLoader/ResourcePacks
7z a LiteLoaderBDS-CUI.tar LiteLoaderBDS-CUI
rm -r LiteLoaderBDS-CUI
shell: bash
- name: Update C++ SDK
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
cd scripts
./UploadSDK.cmd action release
env:
REPO_KEY: ${{secrets.PUSH_TOKEN}}
USERNAME: github-actions[bot]
shell: cmd
# - name: Download LLMoney
# working-directory: ${{ env.GITHUB_WORKSPACE }}
# run: |
# git clone https://github.com/Tooth-Hub/LLMoney.git LLMoney-bin
# cp LLMoney-bin/LLMoney.dll build/output/plugins/
# shell: bash
- name: Upload LiteLoaderBDS
uses: actions/upload-artifact@v3.1.0
with:
name: LiteLoaderBDS
path: |
${{ github.workspace }}\build\output\LLPeEditor.exe
${{ github.workspace }}\build\output\LLPreLoader.dll
${{ github.workspace }}\build\output\LiteLoader.dll
${{ github.workspace }}\build\output\plugins\lib\
${{ github.workspace }}\build\output\plugins\LiteLoader\LangPack\
${{ github.workspace }}\build\output\plugins\LiteLoader\CrashLogger_Daemon.exe
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Js.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Lua.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.NodeJs.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\7z\
${{ github.workspace }}\build\output\plugins\LiteLoader\ParticleAPI.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\ResourcePacks\LiteLoaderBDS-CUI.tar
${{ github.workspace }}\build\output\plugins\LiteLoader\PermissionAPI.dll
# ${{ github.workspace }}\build\output\plugins\LLMoney.dll
- name: Upload PeEditor
uses: actions/upload-artifact@v3.1.0
with:
name: PeEditor
path: ${{ github.workspace }}\build\output\LLPeEditor.exe
- name: Upload PreLoader
uses: actions/upload-artifact@v3.1.0
with:
name: PreLoader
path: ${{ github.workspace }}\build\output\LLPreLoader.dll
- name: Upload LiteLoader
uses: actions/upload-artifact@v3.1.0
with:
name: LiteLoader
path: |
${{ github.workspace }}\build\output\LiteLoader.dll
${{ github.workspace }}\build\output\plugins\lib\*.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LangPack\
${{ github.workspace }}\build\output\plugins\LiteLoader\7z\
${{ github.workspace }}\build\output\plugins\LiteLoader\CrashLogger_Daemon.exe
- name: Upload ScriptEngine
uses: actions/upload-artifact@v3.1.0
with:
name: ScriptEngine
path: |
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Js.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Lua.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.NodeJs.dll
${{ github.workspace }}\build\output\plugins\lib\node_modules.tar
${{ github.workspace }}\build\output\plugins\lib\package.json
- name: Upload LLParticle
uses: actions/upload-artifact@v3.1.0
with:
name: LLParticle
path: |
${{ github.workspace }}\build\output\plugins\LiteLoader\ParticleAPI.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\ResourcePacks\LiteLoaderBDS-CUI.tar
- name: Upload LLPermission
uses: actions/upload-artifact@v3.1.0
with:
name: LLPermission
path: ${{ github.workspace }}\build\output\plugins\LiteLoader\PermissionAPI.dll
- name: Upload PDB files
uses: actions/upload-artifact@v3.1.0
with:
name: PDB
path: ${{ github.workspace }}\build\pdb\
publish_release:
name: Publish release
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Download artifacts
uses: actions/download-artifact@v3
with:
path: build/
- name: Pack artifacts
run: |
cd build/
zip -9r LiteLoaderBDS.zip LiteLoaderBDS/*
zip -9r PDB.zip PDB/*
zip -9r Modules.zip PeEditor PreLoader LiteLoader ScriptEngine LLParticle LLPermission
shell: bash
- name: Create release
if: github.event.inputs.status == 'stable'
uses: ncipollo/release-action@v1
with:
prerelease: false
tag: ${{ github.event.inputs.tag }}
bodyFile: RELEASE_NOTES.md
artifacts: |
build/LiteLoaderBDS.zip
build/Modules.zip
build/PDB.zip
env:
GITHUB_REPOSITORY: quizhizhe/LiteLoaderBDS-1.16.40
- name: Create pre-release
if: github.event.inputs.status != 'stable'
uses: ncipollo/release-action@v1
with:
prerelease: true
tag: ${{ github.event.inputs.tag }}
bodyFile: RELEASE_NOTES.md
artifacts: |
build/Modules.zip
build/PDB.zip
env:
GITHUB_REPOSITORY: quizhizhe/LiteLoaderBDS-1.16.40

6
.gitignore vendored
View File

@ -7,7 +7,7 @@
**/bedrock_server_api.lib
**/bedrock_server_var.lib
**/SymDB_DelayLoadHelper.lib
LiteLoader/Lib/SymDBHelper.lib
LiteLoader/lib/SymDBHelper.lib
**/*.lastcodeanalysissucceeded
*.zip
@ -27,8 +27,8 @@ RELEASE/plugins/LiteLoader/pdb
cmake-build-release/
/out
LiteLoader/Lib/Demangler.pdb
LiteLoader/Lib/Demangler.lib
LiteLoader/lib/Demangler.pdb
LiteLoader/lib/Demangler.lib
/build
**/Directory.build.props

10
.gitmodules vendored
View File

@ -1,3 +1,9 @@
[submodule "RELEASE/plugins/LiteLoader/ResourcePacks/LiteLoaderBDS-CUI"]
path = RELEASE/plugins/LiteLoader/ResourcePacks/LiteLoaderBDS-CUI
[submodule "assets/plugins/LiteLoader/ResourcePacks/LiteLoaderBDS-CUI"]
path = assets/plugins/LiteLoader/ResourcePacks/LiteLoaderBDS-CUI
url = https://github.com/OEOTYAN/LiteLoaderBDS-CUI.git
[submodule "ParticleAPI-1.16.40"]
path = ParticleAPI-1.16.40
url = https://github.com/quizhizhe/ParticleAPI-1.16.40
[submodule "PermissionAPI-1.16.40"]
path = PermissionAPI-1.16.40
url = https://github.com/quizhizhe/PermissionAPI-1.16.40

8
CMake/CleanOutput.cmake Normal file
View File

@ -0,0 +1,8 @@
add_custom_target(
CleanOutput
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/output
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/pdb
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/sdk
COMMENT "Cleaning output/pdb/sdk directory"
VERBATIM
)

29
CMake/PackOutput.cmake Normal file
View File

@ -0,0 +1,29 @@
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/pdb)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/output)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/output/plugins/LiteLoader/)
add_custom_target(PackOutput)
# Copy assets to output after build all.
add_custom_command(
TARGET PackOutput POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/assets/plugins ${CMAKE_BINARY_DIR}/output/plugins/
COMMENT "Copying assets to output"
VERBATIM
)
# Copy ScriptEngine BaseLib to output after build all.
add_custom_command(
TARGET PackOutput POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/ScriptEngine/assets ${CMAKE_BINARY_DIR}/output/plugins/lib/
COMMENT "Copying ScriptEngine BaseLib to output"
VERBATIM
)
# Copy LLPeEditor to output after build all.
add_custom_command(
TARGET PackOutput POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Tools/LLPeEditor.exe ${CMAKE_BINARY_DIR}/output/
COMMENT "Copying LLPeEditor to output"
VERBATIM
)

20
CMake/PackSDK.cmake Normal file
View File

@ -0,0 +1,20 @@
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/sdk)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/sdk/include)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/sdk/include/llapi)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/sdk/tools)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/sdk/lib)
add_custom_target(PackSDK)
add_custom_command(
TARGET PackSDK POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LiteLoader_SOURCE_DIR}/include/llapi ${CMAKE_BINARY_DIR}/sdk/include/llapi
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LiteLoader_SOURCE_DIR}/third-party/include ${CMAKE_BINARY_DIR}/sdk/include
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Tools/LibraryBuilder.exe ${CMAKE_BINARY_DIR}/sdk/tools/
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Tools/LLPeEditor.exe ${CMAKE_BINARY_DIR}/sdk/tools/
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Tools/SDK-submodule-add.cmd ${CMAKE_BINARY_DIR}/sdk/tools/
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Tools/SDK-submodule-update.cmd ${CMAKE_BINARY_DIR}/sdk/tools/
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Tools/SDK-subtree.cmd ${CMAKE_BINARY_DIR}/sdk/tools/
COMMENT "Copying SDK files"
VERBATIM
)

View File

@ -1,14 +1,25 @@
cmake_minimum_required(VERSION 3.21)
project(LL-Parent)
project(LiteLoaderBDS)
set(LiteLoader_SOURCE_DIR ${CMAKE_SOURCE_DIR}/LiteLoader)
set(Demangler_SOURCE_DIR ${CMAKE_SOURCE_DIR}/Tools/Demangler)
set(SCRIPTENGINE_SOURCE_DIR ${CMAKE_SOURCE_DIR}/ScriptEngine)
set(SCRIPTX_SOURCE_DIR ${CMAKE_SOURCE_DIR}/ScriptX)
# Add sub directories
add_subdirectory(PreLoader)
add_subdirectory(LLPreLoader)
add_subdirectory(LiteLoader)
add_subdirectory(ScriptEngine/CMake/ScriptEngine-Lua)
add_subdirectory(ScriptEngine/CMake/ScriptEngine-QuickJs)
add_subdirectory(ScriptEngine/CMake/ScriptEngine-NodeJs)
add_subdirectory(Tools/Demangler)
add_subdirectory(ScriptEngine/third-party/ScriptX/CMake/ScriptX-Lua)
add_subdirectory(ScriptEngine/third-party/ScriptX/CMake/ScriptX-QuickJs)
add_subdirectory(ScriptEngine/third-party/ScriptX/CMake/ScriptX-NodeJs)
add_subdirectory(Tools/SymDBHelper)
add_subdirectory(Tools/ScriptX/CMake/ScriptX-Lua)
add_subdirectory(Tools/ScriptX/CMake/ScriptX-QuickJs)
add_subdirectory(Tools/ScriptX/CMake/ScriptX-NodeJs)
add_subdirectory(Tools/SymDBHelper)
add_subdirectory(ParticleAPI-1.16.40)
add_subdirectory(PermissionAPI-1.16.40/PermissionAPI)
include(${CMAKE_SOURCE_DIR}/CMake/PackOutput.cmake)
include(${CMAKE_SOURCE_DIR}/CMake/PackSDK.cmake)
include(${CMAKE_SOURCE_DIR}/CMake/CleanOutput.cmake)

View File

@ -0,0 +1,45 @@
cmake_minimum_required(VERSION 3.21)
project(LLPreLoader)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_BUILD_TYPE Release)
add_definitions(-D"NDEBUG" -D"_WINDOWS" -D"_USRDLL" -D"_WINDLL" -D"_UNICODE" -D"UNICODE")
add_compile_options(
/permissive- /GS /GL /W0 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Zc:inline /fp:precise
/errorReport:prompt /WX- /Zc:forScope /Gd /Oi /MD /FC /EHsc /nologo /diagnostics:column
)
add_link_options(
/MANIFEST /LTCG:incremental /NXCOMPAT /DEBUG /DLL /MACHINE:X64 /OPT:REF /INCREMENTAL:NO
/SUBSYSTEM:WINDOWS /MANIFESTUAC:NO /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
)
aux_source_directory(${PROJECT_SOURCE_DIR}/third-party/rawpdb DIR_LIB_SRCS)
aux_source_directory(${PROJECT_SOURCE_DIR}/src PROJECT_SRCS)
aux_source_directory(${PROJECT_SOURCE_DIR}/include PROJECT_INCLUDES)
add_library(LLPreLoader SHARED ${PROJECT_INCLUDES} ${PROJECT_SRCS} ${DIR_LIB_SRCS})
target_link_libraries(
LLPreLoader SymDBHelper Demangler
"${LiteLoader_SOURCE_DIR}/third-party/lib/detours/detours.lib"
)
target_include_directories(
LLPreLoader
PRIVATE ${LiteLoader_SOURCE_DIR}/include
PRIVATE ${LiteLoader_SOURCE_DIR}/third-party/include
PRIVATE ${PROJECT_SOURCE_DIR}/include
PRIVATE ${PROJECT_SOURCE_DIR}/third-party
PRIVATE ${Demangler_SOURCE_DIR}/include
)
# Copy the dll and pdb to the output directory
add_custom_command(
TARGET LLPreLoader POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:LLPreLoader> ${CMAKE_BINARY_DIR}/output/
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PDB_FILE:LLPreLoader> ${CMAKE_BINARY_DIR}/pdb/
COMMENT "Copying dll and pdb to output directory"
VERBATIM
)

View File

@ -2,7 +2,7 @@
#include <optional>
#include <string>
#include "../Tools/Demangler/include/MicrosoftDemangle.h"
#include "MicrosoftDemangle.h"
namespace FakeSymbol {

View File

@ -2,12 +2,12 @@
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include "../LiteLoader/Header/third-party/FMT/chrono.h"
#include "../LiteLoader/Header/third-party/FMT/color.h"
#include "../LiteLoader/Header/third-party/FMT/core.h"
#include "../LiteLoader/Header/third-party/FMT/os.h"
#include "../LiteLoader/Header/third-party/FMT/format.h"
#include "../LiteLoader/Header/third-party/Nlohmann/json.hpp"
#include "FMT/chrono.h"
#include "FMT/color.h"
#include "FMT/core.h"
#include "FMT/os.h"
#include "FMT/format.h"
#include "Nlohmann/json.hpp"
#include <string>
#include <filesystem>
#include <fstream>

View File

@ -9,7 +9,7 @@
#endif
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <Windows.h>
#include <filesystem>
#include <fstream>
#include <iostream>

View File

@ -1,9 +1,9 @@
#include "pch.h"
#include "Logger.h"
#include "../include/pch.h"
#include "../include/Logger.h"
#include <string>
#include <set>
#include <filesystem>
#include <windows.h>
#include <Windows.h>
using std::string;
using std::wstring;

View File

@ -1,4 +1,4 @@
#include "pch.h"
#include "../include/pch.h"
#include <cstdio>
#include <filesystem>
#include <fstream>
@ -10,22 +10,22 @@
#include <vector>
#include <mutex>
#include "../LiteLoader/Header/Utils/Hash.h"
#include "../LiteLoader/Header/third-party/detours/detours.h"
#include "../LiteLoader/Lib/third-party/rawpdb/PDB.h"
#include "../LiteLoader/Lib/third-party/rawpdb/PDB_RawFile.h"
#include "../LiteLoader/Lib/third-party/rawpdb/PDB_InfoStream.h"
#include "../LiteLoader/Lib/third-party/rawpdb/PDB_DBIStream.h"
#include "../LiteLoader/Lib/third-party/rawpdb/Foundation/PDB_DisableWarningsPop.h"
#include "llapi/utils/Hash.h"
#include "detours/detours.h"
#include "rawpdb/PDB.h"
#include "rawpdb/PDB_RawFile.h"
#include "rawpdb/PDB_InfoStream.h"
#include "rawpdb/PDB_DBIStream.h"
#include "rawpdb/Foundation/PDB_DisableWarningsPop.h"
#include "../LiteLoader/Header/third-party/parallel_hashmap/phmap.h"
#include "parallel_hashmap/phmap.h"
#include "Logger.h"
#include "../LiteLoader/Header/third-party/FMT/printf.h"
#include "FMT/printf.h"
#include <iomanip>
#include "Utils.h"
#include "FakeSymbol.hpp"
#include "../include/FakeSymbol.hpp"
using std::list;
using std::string, std::string_view;

View File

@ -1,5 +1,5 @@
#include "pch.h"
#include "Utils.h"
#include "../include/pch.h"
#include "../include/Utils.h"
#include <Psapi.h>
std::string GetCallerModuleFileName(unsigned long FramesToSkip) {
static const int maxFrameCount = 1;

View File

@ -1,6 +1,6 @@
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include "Logger.h"
#include "../include/pch.h"
#include "../include/Logger.h"
void fixUpLibDir();
void loadDlls();
#pragma comment(linker, "/export:GetServerSymbol=LLPreLoader.dlsym_real")

View File

@ -2,4 +2,4 @@
/cmake-build-release/
/cmake-build-debug/
/.idea/
Lib/LiteLoader.lib
lib/LiteLoader.lib

View File

@ -4,67 +4,90 @@ project(LiteLoader)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_BUILD_TYPE Release) # Always uses Release mode to build BDS plugin for ABI Compatibility
set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/x64/)
set(TARGET_DIR ${CMAKE_SOURCE_DIR}/x64/Release/)
file(GLOB_RECURSE SRC_FILES
${PROJECT_SOURCE_DIR}/Lib/third-party/nbt-cpp/*.cpp
${PROJECT_SOURCE_DIR}/Header/*.cpp
${PROJECT_SOURCE_DIR}/Header/*.hpp
${PROJECT_SOURCE_DIR}/Header/*.h
${PROJECT_SOURCE_DIR}/Kernel/*.cpp
${PROJECT_SOURCE_DIR}/Kernel/*.hpp
${PROJECT_SOURCE_DIR}/Kernel/*.h
${PROJECT_SOURCE_DIR}/Main/*.cpp
${PROJECT_SOURCE_DIR}/Main/*.hpp
${PROJECT_SOURCE_DIR}/Main/*.h
${PROJECT_SOURCE_DIR}/Resource/*.rc
${PROJECT_SOURCE_DIR}/Resource/*.h
file(
GLOB_RECURSE SRC_FILES
${PROJECT_SOURCE_DIR}/third-party/include/*.h
${PROJECT_SOURCE_DIR}/third-party/include/*.hpp
${PROJECT_SOURCE_DIR}/include/*.h
${PROJECT_SOURCE_DIR}/include/*.hpp
${PROJECT_SOURCE_DIR}/src/*.cpp
${PROJECT_SOURCE_DIR}/src/*.hpp
${PROJECT_SOURCE_DIR}/src/*.h
${PROJECT_SOURCE_DIR}/src/*.rc
)
add_definitions(
-DUNICODE -DNDEBUG -DLITELOADER_EXPORTS -DWIN32_LEAN_AND_MEAN
-DCPPHTTPLIB_OPENSSL_SUPPORT -D_CRT_SECURE_NO_WARNINGS -D_WINDOWS
-D_USRDLL -D_AMD64_ -DNOMINMAX
# third-party source files
file(GLOB_RECURSE THIRD_PARTY_SRC_FILES ${PROJECT_SOURCE_DIR}/third-party/src/*)
add_library(LiteLoader SHARED ${SRC_FILES} ${THIRD_PARTY_SRC_FILES})
# Replace Compile Flag /EHsc to /EHa
string(REPLACE "/EHsc" "/EHa" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
target_compile_options(
LiteLoader
PRIVATE /permissive- /MD /MP /analyze:external- /GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Zc:inline /fp:precise /errorReport:prompt /WX- /Zc:forScope /Gd /Oi /FC /nologo /Ot /diagnostics:column /utf-8
)
add_compile_options(
/permissive /MP /analyze:external- /GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Zc:inline /fp:precise
/external:W1 /errorReport:prompt /WX- /Zc:forScope /Gd /Oi /MD /FC /EHa /nologo /Ot /diagnostics:column
/utf-8
target_compile_definitions(
LiteLoader
PRIVATE -DUNICODE -DNDEBUG -DLITELOADER_EXPORTS -DWIN32_LEAN_AND_MEAN -DCPPHTTPLIB_OPENSSL_SUPPORT -D_CRT_SECURE_NO_WARNINGS -D_WINDOWS -D_USRDLL -D_AMD64_ -DNOMINMAX
)
add_link_options(
/MANIFEST /LTCG:incremental /NXCOMPAT /DEBUG:FULL /DLL /MACHINE:X64 /OPT:REF /INCREMENTAL:NO /SUBSYSTEM:CONSOLE
/MANIFESTUAC:NO /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
/DELAYLOAD:bedrock_server.dll # use delayload to import BDS APIs manually(bedrock_server.dll does not need to exist)
# use delayload to import BDS APIs manually(bedrock_server.dll does not need to exist)
target_link_options(
LiteLoader
PRIVATE /MANIFEST /LTCG:incremental /NXCOMPAT /DEBUG:FULL /DLL /MACHINE:X64 /OPT:REF /INCREMENTAL:NO /SUBSYSTEM:CONSOLE /MANIFESTUAC:NO /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1 /DELAYLOAD:bedrock_server.dll
)
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR}/Header)
include_directories(${PROJECT_SOURCE_DIR}/Header/third-party)
include_directories(${CMAKE_SOURCE_DIR})
link_directories(${PROJECT_SOURCE_DIR})
link_directories(${CMAKE_SOURCE_DIR}/x64/Release)
add_library(LiteLoader SHARED ${SRC_FILES})
target_link_libraries(LiteLoader LLPreLoader
"${PROJECT_SOURCE_DIR}/Lib/third-party/leveldb/leveldb.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/openssl/libcrypto.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/openssl/libssl.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/SQLiteCpp/SQLiteCpp.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/SQLiteCpp/sqlite3.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/mysql/mysqlclient.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/compact_enc_det/ced.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/dyncall/dyncall_s.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/dyncall/dyncallback_s.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/dyncall/dynload_s.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/compact_enc_det/ced.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/dbghelp/dbghelp.lib"
target_link_libraries(
LiteLoader
"${PROJECT_SOURCE_DIR}/third-party/lib/leveldb/leveldb.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/openssl/libcrypto.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/openssl/libssl.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/SQLiteCpp/SQLiteCpp.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/SQLiteCpp/sqlite3.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/mysql/mysqlclient.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/compact_enc_det/ced.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/dyncall/dyncall_s.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/dyncall/dyncallback_s.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/dyncall/dynload_s.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/dbghelp/dbghelp.lib"
# Please make sure that the BDS APIs ImportLibrary is at the bottom of the list to ensure proper linking.
"${PROJECT_SOURCE_DIR}/Lib/bedrock_server_api.lib"
"${PROJECT_SOURCE_DIR}/Lib/bedrock_server_var.lib"
LLPreLoader
)
target_include_directories(
LiteLoader SYSTEM
PRIVATE ${PROJECT_SOURCE_DIR}/third-party/include
)
target_include_directories(
LiteLoader
PRIVATE ${PROJECT_SOURCE_DIR}/include/
PRIVATE ${CMAKE_SOURCE_DIR}
)
add_custom_command(
TARGET LiteLoader PRE_BUILD
COMMAND ${CMAKE_SOURCE_DIR}/scripts/PrepareLibraries.cmd ${CMAKE_SOURCE_DIR}
)
# Copy the built DLL and PDB to the output directory
add_custom_command(
TARGET LiteLoader POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:LiteLoader> ${CMAKE_BINARY_DIR}/output/
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PDB_FILE:LiteLoader> ${CMAKE_BINARY_DIR}/pdb/
COMMENT "Copying LiteLoader DLL and PDB to output directory"
VERBATIM
)
# Copy the built lib to the SDK directory
add_custom_command(
TARGET LiteLoader POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_LINKER_FILE:LiteLoader> ${CMAKE_BINARY_DIR}/sdk/lib/
COMMENT "Copying LiteLoader Lib to SDK directory"
VERBATIM
)

View File

@ -1,5 +0,0 @@
#pragma once
#include "../Global.h"
LIAPI uint64_t NewScoreId();

View File

@ -1,85 +0,0 @@
#ifndef ENTT_CONFIG_CONFIG_H
#define ENTT_CONFIG_CONFIG_H
#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION)
# define ENTT_NOEXCEPT noexcept
# define ENTT_THROW throw
# define ENTT_TRY try
# define ENTT_CATCH catch(...)
#else
# define ENTT_NOEXCEPT
# define ENTT_THROW
# define ENTT_TRY if(true)
# define ENTT_CATCH if(false)
#endif
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
# include <new>
# define ENTT_LAUNDER(expr) std::launder(expr)
#else
# define ENTT_LAUNDER(expr) expr
#endif
#ifndef ENTT_USE_ATOMIC
# define ENTT_MAYBE_ATOMIC(Type) Type
#else
# include <atomic>
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
#endif
#ifndef ENTT_ID_TYPE
# include <cstdint>
# define ENTT_ID_TYPE std::uint32_t
#endif
#ifdef ENTT_SPARSE_PAGE
static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE & (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two");
#else
# define ENTT_SPARSE_PAGE 4096
#endif
#ifdef ENTT_PACKED_PAGE
static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE & (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two");
#else
# define ENTT_PACKED_PAGE 1024
#endif
#ifdef ENTT_DISABLE_ASSERT
# undef ENTT_ASSERT
# define ENTT_ASSERT(...) (void(0))
#elif !defined ENTT_ASSERT
# include <cassert>
# define ENTT_ASSERT(condition, ...) assert(condition)
#endif
#ifdef ENTT_NO_ETO
# include <type_traits>
# define ENTT_IGNORE_IF_EMPTY std::false_type
#else
# include <type_traits>
# define ENTT_IGNORE_IF_EMPTY std::true_type
#endif
#ifndef ENTT_STANDARD_CPP
# 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
#endif

View File

@ -1,10 +0,0 @@
#ifndef ENTT_CONFIG_VERSION_H
#define ENTT_CONFIG_VERSION_H
#define ENTT_VERSION_MAJOR 3
#define ENTT_VERSION_MINOR 8
#define ENTT_VERSION_PATCH 1
#endif

View File

@ -1,456 +0,0 @@
#ifndef ENTT_CORE_ANY_HPP
#define ENTT_CORE_ANY_HPP
#include <cstddef>
#include <functional>
#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 {
/**
* @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 {
enum class operation: std::uint8_t { COPY, MOVE, DTOR, COMP, ADDR, CADDR, TYPE };
enum class policy: std::uint8_t { OWNER, REF, CREF };
using storage_type = std::aligned_storage_t<Len + !Len, Align>;
using vtable_type = const void *(const operation, const basic_any &, void *);
template<typename Type>
static constexpr bool in_situ = Len && alignof(Type) <= alignof(storage_type) && sizeof(Type) <= sizeof(storage_type) && std::is_nothrow_move_constructible_v<Type>;
template<typename Type>
[[nodiscard]] static constexpr policy type_to_policy() {
if constexpr(std::is_lvalue_reference_v<Type>) {
if constexpr(std::is_const_v<std::remove_reference_t<Type>>) {
return policy::CREF;
} else {
return policy::REF;
}
} else {
return policy::OWNER;
}
}
template<typename Type>
[[nodiscard]] static bool compare(const void *lhs, const void *rhs) {
if constexpr(!std::is_function_v<Type> && is_equality_comparable_v<Type>) {
return *static_cast<const Type *>(lhs) == *static_cast<const Type *>(rhs);
} else {
return lhs == rhs;
}
}
template<typename Type>
static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] void *to) {
static_assert(std::is_same_v<std::remove_reference_t<std::remove_const_t<Type>>, Type>, "Invalid type");
if constexpr(!std::is_void_v<Type>) {
const Type *instance = (in_situ<Type> && from.mode == policy::OWNER)
? ENTT_LAUNDER(reinterpret_cast<const Type *>(&from.storage))
: static_cast<const Type *>(from.instance);
switch(op) {
case operation::COPY:
if constexpr(std::is_copy_constructible_v<Type>) {
static_cast<basic_any *>(to)->emplace<Type>(*instance);
}
break;
case operation::MOVE:
if constexpr(in_situ<Type>) {
if(from.mode == policy::OWNER) {
return new (&static_cast<basic_any *>(to)->storage) Type{std::move(*const_cast<Type *>(instance))};
}
}
return (static_cast<basic_any *>(to)->instance = std::exchange(const_cast<basic_any &>(from).instance, nullptr));
case operation::DTOR:
if(from.mode == policy::OWNER) {
if constexpr(in_situ<Type>) {
instance->~Type();
} else if constexpr(std::is_array_v<Type>) {
delete[] instance;
} else {
delete instance;
}
}
break;
case operation::COMP:
return compare<Type>(instance, (*static_cast<const basic_any **>(to))->data()) ? to : nullptr;
case operation::ADDR:
if(from.mode == policy::CREF) {
return nullptr;
}
[[fallthrough]];
case operation::CADDR:
return instance;
case operation::TYPE:
*static_cast<type_info *>(to) = type_id<Type>();
break;
}
}
return nullptr;
}
template<typename Type, typename... Args>
void initialize([[maybe_unused]] Args &&... args) {
if constexpr(!std::is_void_v<Type>) {
if constexpr(std::is_lvalue_reference_v<Type>) {
static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v<Args> && ...), "Invalid arguments");
instance = (std::addressof(args), ...);
} else if constexpr(in_situ<Type>) {
if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<Type>) {
new (&storage) Type{std::forward<Args>(args)...};
} else {
new (&storage) Type(std::forward<Args>(args)...);
}
} else {
if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<Type>) {
instance = new Type{std::forward<Args>(args)...};
} else {
instance = new Type(std::forward<Args>(args)...);
}
}
}
}
basic_any(const basic_any &other, const policy pol) ENTT_NOEXCEPT
: instance{other.data()},
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. */
basic_any() ENTT_NOEXCEPT
: instance{},
vtable{&basic_vtable<void>},
mode{policy::OWNER}
{}
/**
* @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{},
vtable{&basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>},
mode{type_to_policy<Type>()}
{
initialize<Type>(std::forward<Args>(args)...);
}
/**
* @brief Constructs a wrapper that holds an unmanaged object.
* @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>
basic_any(std::reference_wrapper<Type> value) ENTT_NOEXCEPT
: basic_any{}
{
// invokes deprecated assignment operator (and avoids issues with vs2017)
*this = value;
}
/**
* @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)
: instance{},
vtable{&basic_vtable<std::decay_t<Type>>},
mode{policy::OWNER}
{
initialize<std::decay_t<Type>>(std::forward<Type>(value));
}
/**
* @brief Copy constructor.
* @param other The instance to copy from.
*/
basic_any(const basic_any &other)
: instance{},
vtable{&basic_vtable<void>},
mode{policy::OWNER}
{
other.vtable(operation::COPY, other, this);
}
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
basic_any(basic_any &&other) ENTT_NOEXCEPT
: instance{},
vtable{other.vtable},
mode{other.mode}
{
vtable(operation::MOVE, other, this);
}
/*! @brief Frees the internal storage, whatever it means. */
~basic_any() {
vtable(operation::DTOR, *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();
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) ENTT_NOEXCEPT {
std::exchange(vtable, other.vtable)(operation::DTOR, *this, nullptr);
other.vtable(operation::MOVE, other, this);
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>
[[deprecated("Use std::in_place_type<T &>, entt::make_any<T &>, emplace<Type &> or forward_as_any instead")]]
basic_any & operator=(std::reference_wrapper<Type> value) ENTT_NOEXCEPT {
emplace<Type &>(value.get());
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 type of the contained object.
* @return The type of the contained object, if any.
*/
[[nodiscard]] type_info type() const ENTT_NOEXCEPT {
type_info info{};
vtable(operation::TYPE, *this, &info);
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 ENTT_NOEXCEPT {
return vtable(operation::CADDR, *this, nullptr);
}
/*! @copydoc data */
[[nodiscard]] void * data() ENTT_NOEXCEPT {
return const_cast<void *>(vtable(operation::ADDR, *this, nullptr));
}
/**
* @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) {
std::exchange(vtable, &basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>)(operation::DTOR, *this, nullptr);
mode = type_to_policy<Type>();
initialize<Type>(std::forward<Args>(args)...);
}
/*! @brief Destroys contained object */
void reset() {
std::exchange(vtable, &basic_vtable<void>)(operation::DTOR, *this, 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 ENTT_NOEXCEPT {
return !(vtable(operation::CADDR, *this, nullptr) == 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.
*/
bool operator==(const basic_any &other) const ENTT_NOEXCEPT {
const basic_any *trampoline = &other;
return type() == other.type() && (vtable(operation::COMP, *this, &trampoline) || !other.data());
}
/**
* @brief Aliasing constructor.
* @return A wrapper that shares a reference to an unmanaged object.
*/
[[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT {
return basic_any{*this, (mode == policy::CREF ? policy::CREF : policy::REF)};
}
/*! @copydoc as_ref */
[[nodiscard]] basic_any as_ref() const ENTT_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 ENTT_NOEXCEPT {
return (mode == policy::OWNER);
}
private:
union { const void *instance; storage_type storage; };
vtable_type *vtable;
policy mode;
};
/**
* @brief Checks if two wrappers differ in their content.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Alignment requirement.
* @param lhs A wrapper, either empty or not.
* @param rhs A wrapper, either empty or not.
* @return True if the two wrappers differ in their content, false otherwise.
*/
template<std::size_t Len, std::size_t Align>
[[nodiscard]] inline bool operator!=(const basic_any<Len, Align> &lhs, const basic_any<Len, Align> &rhs) ENTT_NOEXCEPT {
return !(lhs == rhs);
}
/**
* @brief Performs type-safe access to the contained object.
* @tparam Type Type to which conversion is required.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Alignment requirement.
* @param data Target any object.
* @return The element converted to the requested type.
*/
template<typename Type, std::size_t Len, std::size_t Align>
Type any_cast(const basic_any<Len, Align> &data) ENTT_NOEXCEPT {
const auto * const instance = any_cast<std::remove_reference_t<Type>>(&data);
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(*instance);
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
Type any_cast(basic_any<Len, Align> &data) ENTT_NOEXCEPT {
// forces const on non-reference types to make them work also with wrappers for const references
auto * const instance = any_cast<std::remove_reference_t<const Type>>(&data);
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(*instance);
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
Type any_cast(basic_any<Len, Align> &&data) ENTT_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>(std::move(*instance));
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
const Type * any_cast(const basic_any<Len, Align> *data) ENTT_NOEXCEPT {
return (data->type() == type_id<Type>() ? static_cast<const Type *>(data->data()) : nullptr);
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
Type * any_cast(basic_any<Len, Align> *data) ENTT_NOEXCEPT {
// last attempt to make wrappers for const references return their values
return (data->type() == type_id<Type>() ? static_cast<Type *>(static_cast<constness_as_t<basic_any<Len, Align>, Type> *>(data)->data()) : nullptr);
}
/**
* @brief Constructs a wrapper from a given type, passing it all arguments.
* @tparam Type Type of object to use to initialize the wrapper.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Optional alignment requirement.
* @tparam Args Types of arguments to use to construct the new instance.
* @param args Parameters to use to construct the instance.
* @return A properly initialized wrapper for an object of the given type.
*/
template<typename Type, std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename... Args>
basic_any<Len, Align> make_any(Args &&... args) {
return basic_any<Len, Align>{std::in_place_type<Type>, std::forward<Args>(args)...};
}
/**
* @brief Forwards its argument and avoids copies for lvalue references.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Optional alignment requirement.
* @tparam Type Type of argument to use to construct the new instance.
* @param value Parameter to use to construct the instance.
* @return A properly initialized and not necessarily owning wrapper.
*/
template<std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename Type>
basic_any<Len, Align> forward_as_any(Type &&value) {
return basic_any<Len, Align>{std::in_place_type<std::conditional_t<std::is_rvalue_reference_v<Type>, std::decay_t<Type>, Type>>, std::forward<Type>(value)};
}
}
#endif

View File

@ -1,33 +0,0 @@
#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

View File

@ -1,269 +0,0 @@
#ifndef ENTT_CORE_HASHED_STRING_HPP
#define ENTT_CORE_HASHED_STRING_HPP
#include <cstddef>
#include <cstdint>
#include "../config/config.h"
#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;
};
}
/**
* 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 identifers 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.
*
* @tparam Char Character type.
*/
template<typename Char>
class basic_hashed_string {
using traits_type = internal::fnv1a_traits<id_type>;
struct const_wrapper {
// non-explicit constructor on purpose
constexpr const_wrapper(const Char *curr) ENTT_NOEXCEPT: str{curr} {}
const Char *str;
};
// FowlerNollVo hash function v. 1a - the good
[[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT {
auto value = traits_type::offset;
while(*curr != 0) {
value = (value ^ static_cast<traits_type::type>(*(curr++))) * traits_type::prime;
}
return value;
}
public:
/*! @brief Character type. */
using value_type = Char;
/*! @brief Unsigned integer type. */
using hash_type = id_type;
/**
* @brief Returns directly the numeric representation of a string view.
* @param str Human-readable identifer.
* @param size Length of the string to hash.
* @return The numeric representation of the string.
*/
[[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT {
id_type partial{traits_type::offset};
while(size--) { partial = (partial^(str++)[0])*traits_type::prime; }
return partial;
}
/**
* @brief Returns directly the numeric representation of a string.
*
* Forcing template resolution avoids implicit conversions. An
* human-readable identifier can be anything but a plain, old bunch of
* characters.<br/>
* Example of use:
* @code{.cpp}
* const auto value = basic_hashed_string<char>::to_value("my.png");
* @endcode
*
* @tparam N Number of characters of the identifier.
* @param str Human-readable identifer.
* @return The numeric representation of the string.
*/
template<std::size_t N>
[[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT {
return helper(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 hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT {
return helper(wrapper.str);
}
/*! @brief Constructs an empty hashed string. */
constexpr basic_hashed_string() ENTT_NOEXCEPT
: str{nullptr}, hash{}
{}
/**
* @brief Constructs a hashed string from an array of const characters.
*
* Forcing template resolution avoids implicit conversions. An
* human-readable identifier can be anything but a plain, old bunch of
* characters.<br/>
* Example of use:
* @code{.cpp}
* basic_hashed_string<char> hs{"my.png"};
* @endcode
*
* @tparam N Number of characters of the identifier.
* @param curr Human-readable identifer.
*/
template<std::size_t N>
constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT
: str{curr}, hash{helper(curr)}
{}
/**
* @brief Explicit constructor on purpose to avoid constructing a hashed
* string directly from a `const value_type *`.
* @param wrapper Helps achieving the purpose by relying on overloading.
*/
explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT
: str{wrapper.str}, hash{helper(wrapper.str)}
{}
/**
* @brief Returns the human-readable representation of a hashed string.
* @return The string used to initialize the instance.
*/
[[nodiscard]] constexpr const value_type * data() const ENTT_NOEXCEPT {
return str;
}
/**
* @brief Returns the numeric representation of a hashed string.
* @return The numeric representation of the instance.
*/
[[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT {
return hash;
}
/*! @copydoc data */
[[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); }
/**
* @brief Returns the numeric representation of a hashed string.
* @return The numeric representation of the instance.
*/
[[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); }
/**
* @brief Compares two hashed strings.
* @param other Hashed string with which to compare.
* @return True if the two hashed strings are identical, false otherwise.
*/
[[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT {
return hash == other.hash;
}
private:
const value_type *str;
hash_type hash;
};
/**
* @brief Deduction guide.
*
* It allows to deduce the character type of the hashed string directly from a
* human-readable identifer provided to the constructor.
*
* @tparam Char Character type.
* @tparam N Number of characters of the identifier.
* @param str Human-readable identifer.
*/
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) ENTT_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 entt::hashed_string operator"" _hs(const char *str, std::size_t) ENTT_NOEXCEPT {
return entt::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 entt::hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) ENTT_NOEXCEPT {
return entt::hashed_wstring{str};
}
}
}
#endif

View File

@ -1,64 +0,0 @@
#ifndef ENTT_CORE_IDENT_HPP
#define ENTT_CORE_IDENT_HPP
#include <cstddef>
#include <utility>
#include <type_traits>
#include "../config/config.h"
#include "fwd.hpp"
#include "type_traits.hpp"
namespace entt {
/**
* @brief Types identifiers.
*
* Variable template used to generate identifiers at compile-time for the given
* types. Use the `get` member function to know what's the identifier associated
* to the specific type.
*
* @note
* Identifiers are constant expression and can be used in any context where such
* an expression is required. As an example:
* @code{.cpp}
* using id = entt::identifier<a_type, another_type>;
*
* switch(a_type_identifier) {
* case id::type<a_type>:
* // ...
* break;
* case id::type<another_type>:
* // ...
* break;
* default:
* // ...
* }
* @endcode
*
* @tparam Types List of types for which to generate identifiers.
*/
template<typename... Types>
class identifier {
template<typename Type, std::size_t... Index>
[[nodiscard]] static constexpr id_type get(std::index_sequence<Index...>) {
static_assert(std::disjunction_v<std::is_same<Type, Types>...>, "Invalid type");
return (0 + ... + (std::is_same_v<Type, type_list_element_t<Index, type_list<std::decay_t<Types>...>>> ? id_type{Index} : id_type{}));
}
public:
/*! @brief Unsigned integer type. */
using identifier_type = id_type;
/*! @brief Statically generated unique identifier for the given type. */
template<typename Type>
static constexpr identifier_type type = get<std::decay_t<Type>>(std::index_sequence_for<Types...>{});
};
}
#endif

View File

@ -1,260 +0,0 @@
#ifndef ENTT_CORE_TYPE_INFO_HPP
#define ENTT_CORE_TYPE_INFO_HPP
#include <string_view>
#include <type_traits>
#include "../config/config.h"
#include "../core/attribute.h"
#include "hashed_string.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
struct ENTT_API type_seq final {
[[nodiscard]] static id_type next() ENTT_NOEXCEPT {
static ENTT_MAYBE_ATOMIC(id_type) value{};
return value++;
}
};
template<typename Type>
[[nodiscard]] constexpr auto stripped_type_name() ENTT_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) ENTT_NOEXCEPT {
constexpr auto value = stripped_type_name<Type>();
return value;
}
template<typename Type>
[[nodiscard]] static std::string_view type_name(char) ENTT_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) ENTT_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) ENTT_NOEXCEPT {
static const auto value = [](const auto stripped) {
return hashed_string::value(stripped.data(), stripped.size());
}(stripped_type_name<Type>());
return value;
}
}
/**
* 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_seq final {
/**
* @brief Returns the sequential identifier of a given type.
* @return The sequential identifier of a given type.
*/
[[nodiscard]] static id_type value() ENTT_NOEXCEPT {
static const id_type value = internal::type_seq::next();
return value;
}
/*! @copydoc value */
[[nodiscard]] constexpr operator id_type() const ENTT_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() ENTT_NOEXCEPT {
return internal::type_hash<Type>(0);
#else
[[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT {
return type_seq<Type>::value();
#endif
}
/*! @copydoc value */
[[nodiscard]] constexpr operator id_type() const ENTT_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() ENTT_NOEXCEPT {
return internal::type_name<Type>(0);
}
/*! @copydoc value */
[[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); }
};
/*! @brief Implementation specific information about a type. */
class type_info final {
template<typename>
friend type_info type_id() ENTT_NOEXCEPT;
type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT
: seq_value{seq_v},
hash_value{hash_v},
name_value{name_v}
{}
public:
/*! @brief Default constructor. */
type_info() ENTT_NOEXCEPT
: type_info({}, {}, {})
{}
/*! @brief Default copy constructor. */
type_info(const type_info &) ENTT_NOEXCEPT = default;
/*! @brief Default move constructor. */
type_info(type_info &&) ENTT_NOEXCEPT = default;
/**
* @brief Default copy assignment operator.
* @return This type info object.
*/
type_info & operator=(const type_info &) ENTT_NOEXCEPT = default;
/**
* @brief Default move assignment operator.
* @return This type info object.
*/
type_info & operator=(type_info &&) ENTT_NOEXCEPT = default;
/**
* @brief Checks if a type info object is properly initialized.
* @return True if the object is properly initialized, false otherwise.
*/
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return name_value.data() != nullptr;
}
/**
* @brief Type sequential identifier.
* @return Type sequential identifier.
*/
[[nodiscard]] id_type seq() const ENTT_NOEXCEPT {
return seq_value;
}
/**
* @brief Type hash.
* @return Type hash.
*/
[[nodiscard]] id_type hash() const ENTT_NOEXCEPT {
return hash_value;
}
/**
* @brief Type name.
* @return Type name.
*/
[[nodiscard]] std::string_view name() const ENTT_NOEXCEPT {
return name_value;
}
/**
* @brief Compares the contents of two type info objects.
* @param other Object with which to compare.
* @return False if the two contents differ, true otherwise.
*/
[[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT {
return hash_value == other.hash_value;
}
private:
id_type seq_value;
id_type hash_value;
std::string_view name_value;
};
/**
* @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 contents differ, false otherwise.
*/
[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
return !(lhs == rhs);
}
/**
* @brief Returns the type info object for a given type.
* @tparam Type Type for which to generate a type info object.
* @return The type info object for the given type.
*/
template<typename Type>
[[nodiscard]] type_info type_id() ENTT_NOEXCEPT {
return type_info{
type_seq<std::remove_cv_t<std::remove_reference_t<Type>>>::value(),
type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value(),
type_name<std::remove_cv_t<std::remove_reference_t<Type>>>::value()
};
}
}
#endif

View File

@ -1,34 +0,0 @@
#ifndef ENTT_ENTITY_COMPONENT_HPP
#define ENTT_ENTITY_COMPONENT_HPP
#include <type_traits>
#include "../config/config.h"
namespace entt {
/*! @brief Commonly used default traits for all types. */
struct basic_component_traits {
/*! @brief Pointer stability, default is `std::false_type`. */
using in_place_delete = std::false_type;
/*! @brief Empty type optimization, default is `ENTT_IGNORE_IF_EMPTY`. */
using ignore_if_empty = ENTT_IGNORE_IF_EMPTY;
};
/**
* @brief Common way to access various properties of components.
* @tparam Type Type of component.
*/
template<typename Type, typename = void>
struct component_traits: basic_component_traits {
static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
};
}
#endif

View File

@ -1,147 +0,0 @@
#ifndef ENTT_ENTITY_FWD_HPP
#define ENTT_ENTITY_FWD_HPP
#include <memory>
#include "../core/fwd.hpp"
namespace entt {
template<typename Entity, typename = std::allocator<Entity>>
class basic_sparse_set;
template<typename, typename Type, typename = std::allocator<Type>>
struct basic_storage;
template<typename>
class basic_registry;
template<typename...>
struct basic_view;
template<typename>
class basic_runtime_view;
template<typename...>
class basic_group;
template<typename>
class basic_observer;
template<typename>
class basic_organizer;
template<typename, typename...>
struct basic_handle;
template<typename>
class basic_snapshot;
template<typename>
class basic_snapshot_loader;
template<typename>
class basic_continuous_loader;
/*! @brief Default entity identifier. */
enum class entity: id_type {};
/*! @brief Alias declaration for the most common use case. */
using sparse_set = basic_sparse_set<entity>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using storage = basic_storage<entity, Args...>;
/*! @brief Alias declaration for the most common use case. */
using registry = basic_registry<entity>;
/*! @brief Alias declaration for the most common use case. */
using observer = basic_observer<entity>;
/*! @brief Alias declaration for the most common use case. */
using organizer = basic_organizer<entity>;
/*! @brief Alias declaration for the most common use case. */
using handle = basic_handle<entity>;
/*! @brief Alias declaration for the most common use case. */
using const_handle = basic_handle<const entity>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using handle_view = basic_handle<entity, 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 entity, Args...>;
/*! @brief Alias declaration for the most common use case. */
using snapshot = basic_snapshot<entity>;
/*! @brief Alias declaration for the most common use case. */
using snapshot_loader = basic_snapshot_loader<entity>;
/*! @brief Alias declaration for the most common use case. */
using continuous_loader = basic_continuous_loader<entity>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using view = basic_view<entity, Args...>;
/*! @brief Alias declaration for the most common use case. */
using runtime_view = basic_runtime_view<entity>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using group = basic_group<entity, Args...>;
}
#endif

View File

@ -1,969 +0,0 @@
#ifndef ENTT_ENTITY_GROUP_HPP
#define ENTT_ENTITY_GROUP_HPP
#include <tuple>
#include <utility>
#include <type_traits>
#include "../config/config.h"
#include "../core/type_traits.hpp"
#include "entity.hpp"
#include "fwd.hpp"
#include "sparse_set.hpp"
#include "storage.hpp"
#include "utility.hpp"
namespace entt {
/**
* @brief Group.
*
* Primary template isn't defined on purpose. All the specializations give a
* compile-time error, but for a few reasonable cases.
*/
template<typename...>
class basic_group;
/**
* @brief Non-owning group.
*
* A non-owning group returns all entities and only the entities that have at
* least the given components. Moreover, it's guaranteed that the entity list
* is tightly packed in memory for fast iterations.
*
* @b Important
*
* Iterators aren't invalidated if:
*
* * New instances of the given components are created and assigned to entities.
* * The entity currently pointed is modified (as an example, if one of the
* given components is removed from the entity to which the iterator points).
* * The entity currently pointed is destroyed.
*
* In all other cases, modifying the pools iterated by the group in any way
* invalidates all the iterators and using them results in undefined behavior.
*
* @note
* Groups share references to the underlying data structures of the registry
* that generated them. Therefore any change to the entities and to the
* components made by means of the registry are immediately reflected by all the
* groups.<br/>
* Moreover, sorting a non-owning group affects all the instances of the same
* group (it means that users don't have to call `sort` on each instance to sort
* all of them because they _share_ entities and components).
*
* @warning
* Lifetime of a group must not overcome that of the registry that generated it.
* In any other case, attempting to use a group results in undefined behavior.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Exclude Types of components used to filter the group.
* @tparam Get Type of components observed by the group.
*/
template<typename Entity, typename... Exclude, typename... Get>
class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> final {
/*! @brief A registry is allowed to create groups. */
friend class basic_registry<Entity>;
using basic_common_type = basic_sparse_set<Entity>;
template<typename Component>
using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Component>>::storage_type, Component>;
class iterable final {
template<typename It>
struct iterable_iterator final {
using difference_type = std::ptrdiff_t;
using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_group>().get({})));
using pointer = void;
using reference = value_type;
using iterator_category = std::input_iterator_tag;
template<typename... Args>
iterable_iterator(It from, const std::tuple<storage_type<Get> *...> &args) ENTT_NOEXCEPT
: it{from},
pools{args}
{}
iterable_iterator & operator++() ENTT_NOEXCEPT {
return ++it, *this;
}
iterable_iterator operator++(int) ENTT_NOEXCEPT {
iterable_iterator orig = *this;
return ++(*this), orig;
}
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
const auto entt = *it;
return std::tuple_cat(std::make_tuple(entt), get_as_tuple(*std::get<storage_type<Get> *>(pools), entt)...);
}
[[nodiscard]] bool operator==(const iterable_iterator &other) const ENTT_NOEXCEPT {
return other.it == it;
}
[[nodiscard]] bool operator!=(const iterable_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
private:
It it;
std::tuple<storage_type<Get> *...> pools;
};
public:
using iterator = iterable_iterator<typename basic_common_type::iterator>;
using reverse_iterator = iterable_iterator<typename basic_common_type::reverse_iterator>;
iterable(basic_common_type * const ref, const std::tuple<storage_type<Get> *...> &cpools)
: handler{ref},
pools{cpools}
{}
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return handler ? iterator{handler->begin(), pools} : iterator{{}, pools};
}
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return handler ? iterator{handler->end(), pools} : iterator{{}, pools};
}
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
return handler ? reverse_iterator{handler->rbegin(), pools} : reverse_iterator{{}, pools};
}
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
return handler ? reverse_iterator{handler->rend(), pools} : reverse_iterator{{}, pools};
}
private:
basic_common_type * const handler;
const std::tuple<storage_type<Get> *...> pools;
};
basic_group(basic_common_type &ref, storage_type<Get> &... gpool) ENTT_NOEXCEPT
: handler{&ref},
pools{&gpool...}
{}
public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Random access iterator type. */
using iterator = typename basic_common_type::iterator;
/*! @brief Reversed iterator type. */
using reverse_iterator = typename basic_common_type::reverse_iterator;
/*! @brief Iterable group type. */
using iterable_group = iterable;
/*! @brief Default constructor to use to create empty, invalid groups. */
basic_group() ENTT_NOEXCEPT
: handler{}
{}
/**
* @brief Returns the number of entities that have the given components.
* @return Number of entities that have the given components.
*/
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
return *this ? handler->size() : size_type{};
}
/**
* @brief Returns the number of elements that a group has currently
* allocated space for.
* @return Capacity of the group.
*/
[[nodiscard]] size_type capacity() const ENTT_NOEXCEPT {
return *this ? handler->capacity() : size_type{};
}
/*! @brief Requests the removal of unused capacity. */
void shrink_to_fit() {
if(*this) {
handler->shrink_to_fit();
}
}
/**
* @brief Checks whether a group is empty.
* @return True if the group is empty, false otherwise.
*/
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return !*this || handler->empty();
}
/**
* @brief Direct access to the list of entities.
*
* The returned pointer is such that range `[data(), data() + size())` is
* always a valid range, even if the container is empty.
*
* @return A pointer to the array of entities.
*/
[[nodiscard]] auto data() const ENTT_NOEXCEPT {
return *this ? handler->data() : nullptr;
}
/**
* @brief Returns an iterator to the first entity of the group.
*
* The returned iterator points to the first entity of the group. If the
* group is empty, the returned iterator will be equal to `end()`.
*
* @return An iterator to the first entity of the group.
*/
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return *this ? handler->begin() : iterator{};
}
/**
* @brief Returns an iterator that is past the last entity of the group.
*
* The returned iterator points to the entity following the last entity of
* the group. Attempting to dereference the returned iterator results in
* undefined behavior.
*
* @return An iterator to the entity following the last entity of the
* group.
*/
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return *this ? handler->end() : iterator{};
}
/**
* @brief Returns an iterator to the first entity of the reversed group.
*
* The returned iterator points to the first entity of the reversed group.
* If the group is empty, the returned iterator will be equal to `rend()`.
*
* @return An iterator to the first entity of the reversed group.
*/
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
return *this ? handler->rbegin() : reverse_iterator{};
}
/**
* @brief Returns an iterator that is past the last entity of the reversed
* group.
*
* The returned iterator points to the entity following the last entity of
* the reversed group. Attempting to dereference the returned iterator
* results in undefined behavior.
*
* @return An iterator to the entity following the last entity of the
* reversed group.
*/
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
return *this ? handler->rend() : reverse_iterator{};
}
/**
* @brief Returns the first entity of the group, if any.
* @return The first entity of the group if one exists, the null entity
* otherwise.
*/
[[nodiscard]] entity_type front() const {
const auto it = begin();
return it != end() ? *it : null;
}
/**
* @brief Returns the last entity of the group, if any.
* @return The last entity of the group if one exists, the null entity
* otherwise.
*/
[[nodiscard]] entity_type back() const {
const auto it = rbegin();
return it != rend() ? *it : null;
}
/**
* @brief Finds an entity.
* @param entt A valid entity identifier.
* @return An iterator to the given entity if it's found, past the end
* iterator otherwise.
*/
[[nodiscard]] iterator find(const entity_type entt) const {
const auto it = *this ? handler->find(entt) : iterator{};
return it != end() && *it == entt ? it : end();
}
/**
* @brief Returns the identifier that occupies the given position.
* @param pos Position of the element to return.
* @return The identifier that occupies the given position.
*/
[[nodiscard]] entity_type operator[](const size_type pos) const {
return begin()[pos];
}
/**
* @brief Checks if a group is properly initialized.
* @return True if the group is properly initialized, false otherwise.
*/
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return handler != nullptr;
}
/**
* @brief Checks if a group contains an entity.
* @param entt A valid entity identifier.
* @return True if the group contains the given entity, false otherwise.
*/
[[nodiscard]] bool contains(const entity_type entt) const {
return *this && handler->contains(entt);
}
/**
* @brief Returns the components assigned to the given entity.
*
* Prefer this function instead of `registry::get` during iterations. It has
* far better performance than its counterpart.
*
* @warning
* Attempting to use an invalid component type results in a compilation
* error. Attempting to use an entity that doesn't belong to the group
* results in undefined behavior.
*
* @tparam Component Types of components to get.
* @param entt A valid entity identifier.
* @return The components assigned to the entity.
*/
template<typename... Component>
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
ENTT_ASSERT(contains(entt), "Group does not contain entity");
if constexpr(sizeof...(Component) == 0) {
return std::tuple_cat(get_as_tuple(*std::get<storage_type<Get> *>(pools), entt)...);
} else if constexpr(sizeof...(Component) == 1) {
return (std::get<storage_type<Component> *>(pools)->get(entt), ...);
} else {
return std::tuple_cat(get_as_tuple(*std::get<storage_type<Component> *>(pools), entt)...);
}
}
/**
* @brief Iterates entities and components and applies the given function
* object to them.
*
* The function object is invoked for each entity. It is provided with the
* entity itself and a set of references to non-empty components. The
* _constness_ of the components is as requested.<br/>
* The signature of the function must be equivalent to one of the following
* forms:
*
* @code{.cpp}
* void(const entity_type, Type &...);
* void(Type &...);
* @endcode
*
* @note
* Empty types aren't explicitly instantiated and therefore they are never
* returned during iterations.
*
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template<typename Func>
void each(Func func) const {
for(const auto entt: *this) {
if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt)));
} else {
std::apply(func, get(entt));
}
}
}
/**
* @brief Returns an iterable object to use to _visit_ the group.
*
* The iterable object returns tuples that contain the current entity and a
* set of references to its non-empty components. The _constness_ of the
* components is as requested.
*
* @note
* Empty types aren't explicitly instantiated and therefore they are never
* returned during iterations.
*
* @return An iterable object to use to _visit_ the group.
*/
[[nodiscard]] iterable_group each() const ENTT_NOEXCEPT {
return iterable_group{handler, pools};
}
/**
* @brief Sort a group according to the given comparison function.
*
* Sort the group so that iterating it with a couple of iterators returns
* entities and components in the expected order. See `begin` and `end` for
* more details.
*
* The comparison function object must return `true` if the first element
* is _less_ than the second one, `false` otherwise. The signature of the
* comparison function should be equivalent to one of the following:
*
* @code{.cpp}
* bool(std::tuple<Component &...>, std::tuple<Component &...>);
* bool(const Component &..., const Component &...);
* bool(const Entity, const Entity);
* @endcode
*
* Where `Component` are such that they are iterated by the group.<br/>
* Moreover, the comparison function object shall induce a
* _strict weak ordering_ on the values.
*
* The sort function oject must offer a member function template
* `operator()` that accepts three arguments:
*
* * An iterator to the first element of the range to sort.
* * An iterator past the last element of the range to sort.
* * A comparison function to use to compare the elements.
*
* @tparam Component Optional types of components to compare.
* @tparam Compare Type of comparison function object.
* @tparam Sort Type of sort function object.
* @tparam Args Types of arguments to forward to the sort function object.
* @param compare A valid comparison function object.
* @param algo A valid sort function object.
* @param args Arguments to forward to the sort function object, if any.
*/
template<typename... Component, typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
if(*this) {
if constexpr(sizeof...(Component) == 0) {
static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
handler->sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
} else if constexpr(sizeof...(Component) == 1) {
handler->sort([this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
return compare((std::get<storage_type<Component> *>(pools)->get(lhs), ...), (std::get<storage_type<Component> *>(pools)->get(rhs), ...));
}, std::move(algo), std::forward<Args>(args)...);
} else {
handler->sort([this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
return compare(std::forward_as_tuple(std::get<storage_type<Component> *>(pools)->get(lhs)...), std::forward_as_tuple(std::get<storage_type<Component> *>(pools)->get(rhs)...));
}, std::move(algo), std::forward<Args>(args)...);
}
}
}
/**
* @brief Sort the shared pool of entities according to the given component.
*
* Non-owning groups of the same type share with the registry a pool of
* entities with its own order that doesn't depend on the order of any pool
* of components. Users can order the underlying data structure so that it
* respects the order of the pool of the given component.
*
* @note
* The shared pool of entities and thus its order is affected by the changes
* to each and every pool that it tracks. Therefore changes to those pools
* can quickly ruin the order imposed to the pool of entities shared between
* the non-owning groups.
*
* @tparam Component Type of component to use to impose the order.
*/
template<typename Component>
void sort() const {
if(*this) {
handler->respect(*std::get<storage_type<Component> *>(pools));
}
}
private:
basic_common_type * const handler;
const std::tuple<storage_type<Get> *...> pools;
};
/**
* @brief Owning group.
*
* Owning groups return all entities and only the entities that have at least
* the given components. Moreover:
*
* * It's guaranteed that the entity list is tightly packed in memory for fast
* iterations.
* * It's guaranteed that the lists of owned components are tightly packed in
* memory for even faster iterations and to allow direct access.
* * They stay true to the order of the owned components and all instances have
* the same order in memory.
*
* The more types of components are owned by a group, the faster it is to
* iterate them.
*
* @b Important
*
* Iterators aren't invalidated if:
*
* * New instances of the given components are created and assigned to entities.
* * The entity currently pointed is modified (as an example, if one of the
* given components is removed from the entity to which the iterator points).
* * The entity currently pointed is destroyed.
*
* In all other cases, modifying the pools iterated by the group in any way
* invalidates all the iterators and using them results in undefined behavior.
*
* @note
* Groups share references to the underlying data structures of the registry
* that generated them. Therefore any change to the entities and to the
* components made by means of the registry are immediately reflected by all the
* groups.
* Moreover, sorting an owning group affects all the instance of the same group
* (it means that users don't have to call `sort` on each instance to sort all
* of them because they share the underlying data structure).
*
* @warning
* Lifetime of a group must not overcome that of the registry that generated it.
* In any other case, attempting to use a group results in undefined behavior.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Exclude Types of components used to filter the group.
* @tparam Get Types of components observed by the group.
* @tparam Owned Types of components owned by the group.
*/
template<typename Entity, typename... Exclude, typename... Get, typename... Owned>
class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> final {
/*! @brief A registry is allowed to create groups. */
friend class basic_registry<Entity>;
using basic_common_type = basic_sparse_set<Entity>;
template<typename Component>
using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Component>>::storage_type, Component>;
class iterable final {
template<typename, typename>
struct iterable_iterator;
template<typename It, typename... OIt>
struct iterable_iterator<It, type_list<OIt...>> final {
using difference_type = std::ptrdiff_t;
using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_group>().get({})));
using pointer = void;
using reference = value_type;
using iterator_category = std::input_iterator_tag;
template<typename... Other>
iterable_iterator(It from, const std::tuple<Other...> &other, const std::tuple<storage_type<Get> *...> &cpools) ENTT_NOEXCEPT
: it{from},
owned{std::get<OIt>(other)...},
get{cpools}
{}
iterable_iterator & operator++() ENTT_NOEXCEPT {
return ++it, (++std::get<OIt>(owned), ...), *this;
}
iterable_iterator operator++(int) ENTT_NOEXCEPT {
iterable_iterator orig = *this;
return ++(*this), orig;
}
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
return std::tuple_cat(
std::make_tuple(*it),
std::forward_as_tuple(*std::get<OIt>(owned)...),
get_as_tuple(*std::get<storage_type<Get> *>(get), *it)...
);
}
[[nodiscard]] bool operator==(const iterable_iterator &other) const ENTT_NOEXCEPT {
return other.it == it;
}
[[nodiscard]] bool operator!=(const iterable_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
private:
It it;
std::tuple<OIt...> owned;
std::tuple<storage_type<Get> *...> get;
};
public:
using iterator = iterable_iterator<
typename basic_common_type::iterator,
type_list_cat_t<std::conditional_t<std::is_void_v<decltype(std::declval<storage_type<Owned>>().get({}))>, type_list<>, type_list<decltype(std::declval<storage_type<Owned>>().end())>>...>
>;
using reverse_iterator = iterable_iterator<
typename basic_common_type::reverse_iterator,
type_list_cat_t<std::conditional_t<std::is_void_v<decltype(std::declval<storage_type<Owned>>().get({}))>, type_list<>, type_list<decltype(std::declval<storage_type<Owned>>().rbegin())>>...>
>;
iterable(std::tuple<storage_type<Owned> *..., storage_type<Get> *...> cpools, const std::size_t * const extent)
: pools{cpools},
length{extent}
{}
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return length ? iterator{
std::get<0>(pools)->basic_common_type::end() - *length,
std::make_tuple((std::get<storage_type<Owned> *>(pools)->end() - *length)...),
std::make_tuple(std::get<storage_type<Get> *>(pools)...)
} : iterator{{}, std::make_tuple(decltype(std::get<storage_type<Owned> *>(pools)->end()){}...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
}
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return length ? iterator{
std::get<0>(pools)->basic_common_type::end(),
std::make_tuple((std::get<storage_type<Owned> *>(pools)->end())...),
std::make_tuple(std::get<storage_type<Get> *>(pools)...)
} : iterator{{}, std::make_tuple(decltype(std::get<storage_type<Owned> *>(pools)->end()){}...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
}
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
return length ? reverse_iterator{
std::get<0>(pools)->basic_common_type::rbegin(),
std::make_tuple((std::get<storage_type<Owned> *>(pools)->rbegin())...),
std::make_tuple(std::get<storage_type<Get> *>(pools)...)
} : reverse_iterator{{}, std::make_tuple(decltype(std::get<storage_type<Owned> *>(pools)->rbegin()){}...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
}
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
return length ? reverse_iterator{
std::get<0>(pools)->basic_common_type::rbegin() + *length,
std::make_tuple((std::get<storage_type<Owned> *>(pools)->rbegin() + *length)...),
std::make_tuple(std::get<storage_type<Get> *>(pools)...)
} : reverse_iterator{{}, std::make_tuple(decltype(std::get<storage_type<Owned> *>(pools)->rbegin()){}...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
}
private:
const std::tuple<storage_type<Owned> *..., storage_type<Get> *...> pools;
const std::size_t * const length;
};
basic_group(const std::size_t &extent, storage_type<Owned> &... opool, storage_type<Get> &... gpool) ENTT_NOEXCEPT
: pools{&opool..., &gpool...},
length{&extent}
{}
public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Random access iterator type. */
using iterator = typename basic_common_type::iterator;
/*! @brief Reversed iterator type. */
using reverse_iterator = typename basic_common_type::reverse_iterator;
/*! @brief Iterable group type. */
using iterable_group = iterable;
/*! @brief Default constructor to use to create empty, invalid groups. */
basic_group() ENTT_NOEXCEPT
: length{}
{}
/**
* @brief Returns the number of entities that have the given components.
* @return Number of entities that have the given components.
*/
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
return *this ? *length : size_type{};
}
/**
* @brief Checks whether a group is empty.
* @return True if the group is empty, false otherwise.
*/
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return !*this || !*length;
}
/**
* @brief Direct access to the raw representation offered by the storage.
*
* @warning
* This function is only available for owned types.
*
* @tparam Component Type of component in which one is interested.
* @return A pointer to the array of components.
*/
template<typename Component>
[[nodiscard]] auto raw() const ENTT_NOEXCEPT {
static_assert((std::is_same_v<Component, Owned> || ...), "Non-owned type");
auto *cpool = std::get<storage_type<Component> *>(pools);
return cpool ? cpool->raw() : decltype(cpool->raw()){};
}
/**
* @brief Direct access to the list of entities.
*
* The returned pointer is such that range `[data(), data() + size())` is
* always a valid range, even if the container is empty.
*
* @return A pointer to the array of entities.
*/
[[nodiscard]] auto data() const ENTT_NOEXCEPT {
return *this ? std::get<0>(pools)->data() : nullptr;
}
/**
* @brief Returns an iterator to the first entity of the group.
*
* The returned iterator points to the first entity of the group. If the
* group is empty, the returned iterator will be equal to `end()`.
*
* @return An iterator to the first entity of the group.
*/
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return *this ? (std::get<0>(pools)->basic_common_type::end() - *length) : iterator{};
}
/**
* @brief Returns an iterator that is past the last entity of the group.
*
* The returned iterator points to the entity following the last entity of
* the group. Attempting to dereference the returned iterator results in
* undefined behavior.
*
* @return An iterator to the entity following the last entity of the
* group.
*/
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return *this ? std::get<0>(pools)->basic_common_type::end() : iterator{};
}
/**
* @brief Returns an iterator to the first entity of the reversed group.
*
* The returned iterator points to the first entity of the reversed group.
* If the group is empty, the returned iterator will be equal to `rend()`.
*
* @return An iterator to the first entity of the reversed group.
*/
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
return *this ? std::get<0>(pools)->basic_common_type::rbegin() : reverse_iterator{};
}
/**
* @brief Returns an iterator that is past the last entity of the reversed
* group.
*
* The returned iterator points to the entity following the last entity of
* the reversed group. Attempting to dereference the returned iterator
* results in undefined behavior.
*
* @return An iterator to the entity following the last entity of the
* reversed group.
*/
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
return *this ? (std::get<0>(pools)->basic_common_type::rbegin() + *length) : reverse_iterator{};
}
/**
* @brief Returns the first entity of the group, if any.
* @return The first entity of the group if one exists, the null entity
* otherwise.
*/
[[nodiscard]] entity_type front() const {
const auto it = begin();
return it != end() ? *it : null;
}
/**
* @brief Returns the last entity of the group, if any.
* @return The last entity of the group if one exists, the null entity
* otherwise.
*/
[[nodiscard]] entity_type back() const {
const auto it = rbegin();
return it != rend() ? *it : null;
}
/**
* @brief Finds an entity.
* @param entt A valid entity identifier.
* @return An iterator to the given entity if it's found, past the end
* iterator otherwise.
*/
[[nodiscard]] iterator find(const entity_type entt) const {
const auto it = *this ? std::get<0>(pools)->find(entt) : iterator{};
return it != end() && it >= begin() && *it == entt ? it : end();
}
/**
* @brief Returns the identifier that occupies the given position.
* @param pos Position of the element to return.
* @return The identifier that occupies the given position.
*/
[[nodiscard]] entity_type operator[](const size_type pos) const {
return begin()[pos];
}
/**
* @brief Checks if a group is properly initialized.
* @return True if the group is properly initialized, false otherwise.
*/
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return length != nullptr;
}
/**
* @brief Checks if a group contains an entity.
* @param entt A valid entity identifier.
* @return True if the group contains the given entity, false otherwise.
*/
[[nodiscard]] bool contains(const entity_type entt) const {
return *this && std::get<0>(pools)->contains(entt) && (std::get<0>(pools)->index(entt) < (*length));
}
/**
* @brief Returns the components assigned to the given entity.
*
* Prefer this function instead of `registry::get` during iterations. It has
* far better performance than its counterpart.
*
* @warning
* Attempting to use an invalid component type results in a compilation
* error. Attempting to use an entity that doesn't belong to the group
* results in undefined behavior.
*
* @tparam Component Types of components to get.
* @param entt A valid entity identifier.
* @return The components assigned to the entity.
*/
template<typename... Component>
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
ENTT_ASSERT(contains(entt), "Group does not contain entity");
if constexpr(sizeof...(Component) == 0) {
return std::tuple_cat(get_as_tuple(*std::get<storage_type<Owned> *>(pools), entt)..., get_as_tuple(*std::get<storage_type<Get> *>(pools), entt)...);
} else if constexpr(sizeof...(Component) == 1) {
return (std::get<storage_type<Component> *>(pools)->get(entt), ...);
} else {
return std::tuple_cat(get_as_tuple(*std::get<storage_type<Component> *>(pools), entt)...);
}
}
/**
* @brief Iterates entities and components and applies the given function
* object to them.
*
* The function object is invoked for each entity. It is provided with the
* entity itself and a set of references to non-empty components. The
* _constness_ of the components is as requested.<br/>
* The signature of the function must be equivalent to one of the following
* forms:
*
* @code{.cpp}
* void(const entity_type, Type &...);
* void(Type &...);
* @endcode
*
* @note
* Empty types aren't explicitly instantiated and therefore they are never
* returned during iterations.
*
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template<typename Func>
void each(Func func) const {
for(auto args: each()) {
if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
std::apply(func, args);
} else {
std::apply([&func](auto, auto &&... less) { func(std::forward<decltype(less)>(less)...); }, args);
}
}
}
/**
* @brief Returns an iterable object to use to _visit_ the group.
*
* The iterable object returns tuples that contain the current entity and a
* set of references to its non-empty components. The _constness_ of the
* components is as requested.
*
* @note
* Empty types aren't explicitly instantiated and therefore they are never
* returned during iterations.
*
* @return An iterable object to use to _visit_ the group.
*/
[[nodiscard]] iterable_group each() const ENTT_NOEXCEPT {
return iterable_group{pools, length};
}
/**
* @brief Sort a group according to the given comparison function.
*
* Sort the group so that iterating it with a couple of iterators returns
* entities and components in the expected order. See `begin` and `end` for
* more details.
*
* The comparison function object must return `true` if the first element
* is _less_ than the second one, `false` otherwise. The signature of the
* comparison function should be equivalent to one of the following:
*
* @code{.cpp}
* bool(std::tuple<Component &...>, std::tuple<Component &...>);
* bool(const Component &, const Component &);
* bool(const Entity, const Entity);
* @endcode
*
* Where `Component` are either owned types or not but still such that they
* are iterated by the group.<br/>
* Moreover, the comparison function object shall induce a
* _strict weak ordering_ on the values.
*
* The sort function oject must offer a member function template
* `operator()` that accepts three arguments:
*
* * An iterator to the first element of the range to sort.
* * An iterator past the last element of the range to sort.
* * A comparison function to use to compare the elements.
*
* @tparam Component Optional types of components to compare.
* @tparam Compare Type of comparison function object.
* @tparam Sort Type of sort function object.
* @tparam Args Types of arguments to forward to the sort function object.
* @param compare A valid comparison function object.
* @param algo A valid sort function object.
* @param args Arguments to forward to the sort function object, if any.
*/
template<typename... Component, typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&... args) const {
auto *cpool = std::get<0>(pools);
if constexpr(sizeof...(Component) == 0) {
static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
cpool->sort_n(*length, std::move(compare), std::move(algo), std::forward<Args>(args)...);
} else if constexpr(sizeof...(Component) == 1) {
cpool->sort_n(*length, [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
return compare((std::get<storage_type<Component> *>(pools)->get(lhs), ...), (std::get<storage_type<Component> *>(pools)->get(rhs), ...));
}, std::move(algo), std::forward<Args>(args)...);
} else {
cpool->sort_n(*length, [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
return compare(std::forward_as_tuple(std::get<storage_type<Component> *>(pools)->get(lhs)...), std::forward_as_tuple(std::get<storage_type<Component> *>(pools)->get(rhs)...));
}, std::move(algo), std::forward<Args>(args)...);
}
[this](auto *head, auto *... other) {
for(auto next = *length; next; --next) {
const auto pos = next - 1;
[[maybe_unused]] const auto entt = head->data()[pos];
(other->swap(other->data()[pos], entt), ...);
}
}(std::get<storage_type<Owned> *>(pools)...);
}
private:
const std::tuple<storage_type<Owned> *..., storage_type<Get> *...> pools;
const size_type * const length;
};
}
#endif

View File

@ -1,168 +0,0 @@
#ifndef ENTT_ENTITY_HELPER_HPP
#define ENTT_ENTITY_HELPER_HPP
#include <type_traits>
#include "../config/config.h"
#include "../core/fwd.hpp"
#include "../core/type_traits.hpp"
#include "../signal/delegate.hpp"
#include "registry.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @brief Converts a registry to a view.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
struct as_view {
/*! @brief Underlying entity identifier. */
using entity_type = std::remove_const_t<Entity>;
/*! @brief Type of registry to convert. */
using registry_type = constness_as_t<basic_registry<entity_type>, Entity>;
/**
* @brief Constructs a converter for a given registry.
* @param source A valid reference to a registry.
*/
as_view(registry_type &source) ENTT_NOEXCEPT: reg{source} {}
/**
* @brief Conversion function from a registry to a view.
* @tparam Exclude Types of components used to filter the view.
* @tparam Component Type of components used to construct the view.
* @return A newly created view.
*/
template<typename Exclude, typename... Component>
operator basic_view<entity_type, Exclude, Component...>() const {
return reg.template view<Component...>(Exclude{});
}
private:
registry_type &reg;
};
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_view(basic_registry<Entity> &) -> as_view<Entity>;
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_view(const basic_registry<Entity> &) -> as_view<const Entity>;
/**
* @brief Converts a registry to a group.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
struct as_group {
/*! @brief Underlying entity identifier. */
using entity_type = std::remove_const_t<Entity>;
/*! @brief Type of registry to convert. */
using registry_type = constness_as_t<basic_registry<entity_type>, Entity>;
/**
* @brief Constructs a converter for a given registry.
* @param source A valid reference to a registry.
*/
as_group(registry_type &source) ENTT_NOEXCEPT: reg{source} {}
/**
* @brief Conversion function from a registry to a group.
* @tparam Exclude Types of components used to filter the group.
* @tparam Get Types of components observed by the group.
* @tparam Owned Types of components owned by the group.
* @return A newly created group.
*/
template<typename Exclude, typename Get, typename... Owned>
operator basic_group<entity_type, Exclude, Get, Owned...>() const {
if constexpr(std::is_const_v<registry_type>) {
return reg.template group_if_exists<Owned...>(Get{}, Exclude{});
} else {
return reg.template group<Owned...>(Get{}, Exclude{});
}
}
private:
registry_type &reg;
};
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_group(basic_registry<Entity> &) -> as_group<Entity>;
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_group(const basic_registry<Entity> &) -> as_group<const Entity>;
/**
* @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 Entity A valid entity type (see entt_traits for more details).
* @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 Entity = entity>
void invoke(basic_registry<Entity> &reg, const Entity entt) {
static_assert(std::is_member_function_pointer_v<decltype(Member)>, "Invalid pointer to non-static member function");
delegate<void(basic_registry<Entity> &, const Entity)> 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 Entity A valid entity type (see entt_traits for more details).
* @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 Entity, typename Component>
Entity to_entity(const basic_registry<Entity> &reg, const Component &instance) {
const auto view = reg.template view<const Component>();
const auto *addr = std::addressof(instance);
for(auto it = view.rbegin(), last = view.rend(); it < last; it += ENTT_PACKED_PAGE) {
if(const auto dist = (addr - std::addressof(view.template get<const Component>(*it))); dist >= 0 && dist < ENTT_PACKED_PAGE) {
return *(it + dist);
}
}
return entt::null;
}
}
#endif

View File

@ -1,60 +0,0 @@
#ifndef ENTT_ENTITY_POLY_STORAGE_HPP
#define ENTT_ENTITY_POLY_STORAGE_HPP
#include <cstddef>
#include <tuple>
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../poly/poly.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @brief Basic poly storage implementation.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
struct Storage: type_list<type_info() const ENTT_NOEXCEPT> {
/**
* @brief Concept definition.
* @tparam Base Opaque base class from which to inherit.
*/
template<typename Base>
struct type: Base {
/**
* @brief Returns a type info for the contained objects.
* @return The type info for the contained objects.
*/
type_info value_type() const ENTT_NOEXCEPT {
return poly_call<0>(*this);
}
};
/**
* @brief Concept implementation.
* @tparam Type Type for which to generate an implementation.
*/
template<typename Type>
using impl = value_list<&type_id<typename Type::value_type>>;
};
/**
* @brief Defines the poly storage type associate with a given entity type.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity, typename = void>
struct poly_storage_traits {
/*! @brief Poly storage type for the given entity type. */
using storage_type = poly<Storage<Entity>>;
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,245 +0,0 @@
#ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP
#define ENTT_ENTITY_RUNTIME_VIEW_HPP
#include <iterator>
#include <vector>
#include <utility>
#include <algorithm>
#include <type_traits>
#include "../config/config.h"
#include "entity.hpp"
#include "sparse_set.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @brief Runtime view.
*
* Runtime views iterate over those entities that have at least all the given
* components in their bags. During initialization, a runtime view looks at the
* number of entities available for each component and picks up a reference to
* the smallest set of candidate entities in order to get a performance boost
* when iterate.<br/>
* Order of elements during iterations are highly dependent on the order of the
* underlying data structures. See sparse_set and its specializations for more
* details.
*
* @b Important
*
* Iterators aren't invalidated if:
*
* * New instances of the given components are created and assigned to entities.
* * The entity currently pointed is modified (as an example, if one of the
* given components is removed from the entity to which the iterator points).
* * The entity currently pointed is destroyed.
*
* In all the other cases, modifying the pools of the given components in any
* way invalidates all the iterators and using them results in undefined
* behavior.
*
* @note
* Views share references to the underlying data structures of the registry that
* generated them. Therefore any change to the entities and to the components
* made by means of the registry are immediately reflected by the views, unless
* a pool was missing when the view was built (in this case, the view won't
* have a valid reference and won't be updated accordingly).
*
* @warning
* Lifetime of a view must not overcome that of the registry that generated it.
* In any other case, attempting to use a view results in undefined behavior.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
class basic_runtime_view final {
using basic_common_type = basic_sparse_set<Entity>;
using underlying_iterator = typename basic_common_type::iterator;
class view_iterator final {
[[nodiscard]] bool valid() const {
const auto entt = *it;
return (!stable_storage || (entt != tombstone))
&& std::all_of(pools->begin()++, pools->end(), [entt](const auto *curr) { return curr->contains(entt); })
&& std::none_of(filter->cbegin(), filter->cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
}
public:
using difference_type = typename underlying_iterator::difference_type;
using value_type = typename underlying_iterator::value_type;
using pointer = typename underlying_iterator::pointer;
using reference = typename underlying_iterator::reference;
using iterator_category = std::bidirectional_iterator_tag;
view_iterator() ENTT_NOEXCEPT = default;
view_iterator(const std::vector<const basic_common_type *> &cpools, const std::vector<const basic_common_type *> &ignore, underlying_iterator curr) ENTT_NOEXCEPT
: pools{&cpools},
filter{&ignore},
it{curr},
stable_storage{std::any_of(pools->cbegin(), pools->cend(), [](const basic_common_type *cpool) { return (cpool->policy() == deletion_policy::in_place); })}
{
if(it != (*pools)[0]->end() && !valid()) {
++(*this);
}
}
view_iterator & operator++() {
while(++it != (*pools)[0]->end() && !valid());
return *this;
}
view_iterator operator++(int) {
view_iterator orig = *this;
return ++(*this), orig;
}
view_iterator & operator--() ENTT_NOEXCEPT {
while(--it != (*pools)[0]->begin() && !valid());
return *this;
}
view_iterator operator--(int) ENTT_NOEXCEPT {
view_iterator orig = *this;
return operator--(), orig;
}
[[nodiscard]] bool operator==(const view_iterator &other) const ENTT_NOEXCEPT {
return other.it == it;
}
[[nodiscard]] bool operator!=(const view_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
[[nodiscard]] pointer operator->() const {
return it.operator->();
}
[[nodiscard]] reference operator*() const {
return *operator->();
}
private:
const std::vector<const basic_common_type *> *pools;
const std::vector<const basic_common_type *> *filter;
underlying_iterator it;
bool stable_storage;
};
[[nodiscard]] bool valid() const {
return !pools.empty() && pools.front();
}
public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Bidirectional iterator type. */
using iterator = view_iterator;
/*! @brief Default constructor to use to create empty, invalid views. */
basic_runtime_view() ENTT_NOEXCEPT
: pools{},
filter{}
{}
/**
* @brief Constructs a runtime view from a set of storage classes.
* @param cpools The storage for the types to iterate.
* @param epools The storage for the types used to filter the view.
*/
basic_runtime_view(std::vector<const basic_common_type *> cpools, std::vector<const basic_common_type *> epools) ENTT_NOEXCEPT
: pools{std::move(cpools)},
filter{std::move(epools)}
{
// brings the best candidate (if any) on front of the vector
std::rotate(pools.begin(), std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) {
return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size());
}), pools.end());
}
/**
* @brief Estimates the number of entities iterated by the view.
* @return Estimated number of entities iterated by the view.
*/
[[nodiscard]] size_type size_hint() const {
return valid() ? pools.front()->size() : size_type{};
}
/**
* @brief Returns an iterator to the first entity that has the given
* components.
*
* The returned iterator points to the first entity that has the given
* components. If the view is empty, the returned iterator will be equal to
* `end()`.
*
* @return An iterator to the first entity that has the given components.
*/
[[nodiscard]] iterator begin() const {
return valid() ? iterator{pools, filter, pools[0]->begin()} : iterator{};
}
/**
* @brief Returns an iterator that is past the last entity that has the
* given components.
*
* The returned iterator points to the entity following the last entity that
* has the given components. Attempting to dereference the returned iterator
* results in undefined behavior.
*
* @return An iterator to the entity following the last entity that has the
* given components.
*/
[[nodiscard]] iterator end() const {
return valid() ? iterator{pools, filter, pools[0]->end()} : iterator{};
}
/**
* @brief Checks if a view contains an entity.
* @param entt A valid entity identifier.
* @return True if the view contains the given entity, false otherwise.
*/
[[nodiscard]] bool contains(const entity_type entt) const {
return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
&& std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
}
/**
* @brief Iterates entities and applies the given function object to them.
*
* The function object is invoked for each entity. It is provided only with
* the entity itself. To get the components, users can use the registry with
* which the view was built.<br/>
* The signature of the function should be equivalent to the following:
*
* @code{.cpp}
* void(const entity_type);
* @endcode
*
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template<typename Func>
void each(Func func) const {
for(const auto entity: *this) {
func(entity);
}
}
private:
std::vector<const basic_common_type *> pools;
std::vector<const basic_common_type *> filter;
};
}
#endif

View File

@ -1,870 +0,0 @@
#ifndef ENTT_ENTITY_SPARSE_SET_HPP
#define ENTT_ENTITY_SPARSE_SET_HPP
#include <cstddef>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/algorithm.hpp"
#include "../core/fwd.hpp"
#include "entity.hpp"
#include "fwd.hpp"
namespace entt {
/*! @brief Sparse set deletion policy. */
enum class deletion_policy: std::uint8_t {
/*! @brief Swap-and-pop deletion policy. */
swap_and_pop = 0u,
/*! @brief In-place deletion policy. */
in_place = 1u
};
/**
* @brief Basic sparse set implementation.
*
* Sparse set or packed array or whatever is the name users give it.<br/>
* Two arrays: an _external_ one and an _internal_ one; a _sparse_ one and a
* _packed_ one; one used for direct access through contiguous memory, the other
* one used to get the data through an extra level of indirection.<br/>
* This is largely used by the registry to offer users the fastest access ever
* to the components. Views and groups in general are almost entirely designed
* around sparse sets.
*
* This type of data structure is widely documented in the literature and on the
* web. This is nothing more than a customized implementation suitable for the
* purpose of the framework.
*
* @note
* Internal data structures arrange elements to maximize performance. There are
* no guarantees that entities are returned in the insertion order when iterate
* a sparse set. Do not make assumption on the order in any case.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Entity, typename Allocator>
class basic_sparse_set {
static constexpr auto growth_factor = 1.5;
static constexpr auto sparse_page = ENTT_SPARSE_PAGE;
using traits_type = entt_traits<Entity>;
using alloc_traits = typename std::allocator_traits<Allocator>::template rebind_traits<Entity>;
using alloc_pointer = typename alloc_traits::pointer;
using alloc_const_pointer = typename alloc_traits::const_pointer;
using bucket_alloc_traits = typename std::allocator_traits<Allocator>::template rebind_traits<alloc_pointer>;
using bucket_alloc_pointer = typename bucket_alloc_traits::pointer;
static_assert(alloc_traits::propagate_on_container_move_assignment::value);
static_assert(bucket_alloc_traits::propagate_on_container_move_assignment::value);
struct sparse_set_iterator final {
using difference_type = typename traits_type::difference_type;
using value_type = Entity;
using pointer = const value_type *;
using reference = const value_type &;
using iterator_category = std::random_access_iterator_tag;
sparse_set_iterator() ENTT_NOEXCEPT = default;
sparse_set_iterator(const alloc_const_pointer *ref, const difference_type idx) ENTT_NOEXCEPT
: packed{ref},
index{idx}
{}
sparse_set_iterator & operator++() ENTT_NOEXCEPT {
return --index, *this;
}
sparse_set_iterator operator++(int) ENTT_NOEXCEPT {
iterator orig = *this;
return ++(*this), orig;
}
sparse_set_iterator & operator--() ENTT_NOEXCEPT {
return ++index, *this;
}
sparse_set_iterator operator--(int) ENTT_NOEXCEPT {
sparse_set_iterator orig = *this;
return operator--(), orig;
}
sparse_set_iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
index -= value;
return *this;
}
sparse_set_iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
sparse_set_iterator copy = *this;
return (copy += value);
}
sparse_set_iterator & operator-=(const difference_type value) ENTT_NOEXCEPT {
return (*this += -value);
}
sparse_set_iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
return (*this + -value);
}
difference_type operator-(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return other.index - index;
}
[[nodiscard]] reference operator[](const difference_type value) const {
const auto pos = size_type(index-value-1u);
return (*packed)[pos];
}
[[nodiscard]] bool operator==(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return other.index == index;
}
[[nodiscard]] bool operator!=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
[[nodiscard]] bool operator<(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return index > other.index;
}
[[nodiscard]] bool operator>(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return index < other.index;
}
[[nodiscard]] bool operator<=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return !(*this > other);
}
[[nodiscard]] bool operator>=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return !(*this < other);
}
[[nodiscard]] pointer operator->() const {
const auto pos = size_type(index-1u);
return std::addressof((*packed)[pos]);
}
[[nodiscard]] reference operator*() const {
return *operator->();
}
private:
const alloc_const_pointer *packed;
difference_type index;
};
[[nodiscard]] static auto page(const Entity entt) ENTT_NOEXCEPT {
return static_cast<size_type>(traits_type::to_entity(entt) / sparse_page);
}
[[nodiscard]] static auto offset(const Entity entt) ENTT_NOEXCEPT {
return static_cast<size_type>(traits_type::to_entity(entt) & (sparse_page - 1));
}
[[nodiscard]] auto assure_page(const std::size_t idx) {
if(!(idx < bucket)) {
const size_type sz = idx + 1u;
const auto mem = bucket_alloc_traits::allocate(bucket_allocator, sz);
std::uninitialized_value_construct(mem + bucket, mem + sz);
std::uninitialized_copy(sparse, sparse + bucket, mem);
std::destroy(sparse, sparse + bucket);
bucket_alloc_traits::deallocate(bucket_allocator, sparse, bucket);
sparse = mem;
bucket = sz;
}
if(!sparse[idx]) {
sparse[idx] = alloc_traits::allocate(allocator, sparse_page);
std::uninitialized_fill(sparse[idx], sparse[idx] + sparse_page, null);
}
return sparse[idx];
}
void resize_packed(const std::size_t req) {
ENTT_ASSERT((req != reserved) && !(req < count), "Invalid request");
const auto mem = alloc_traits::allocate(allocator, req);
std::uninitialized_copy(packed, packed + count, mem);
std::uninitialized_fill(mem + count, mem + req, tombstone);
std::destroy(packed, packed + reserved);
alloc_traits::deallocate(allocator, packed, reserved);
packed = mem;
reserved = req;
}
void release_memory() {
if(packed) {
for(size_type pos{}; pos < bucket; ++pos) {
if(sparse[pos]) {
std::destroy(sparse[pos], sparse[pos] + sparse_page);
alloc_traits::deallocate(allocator, sparse[pos], sparse_page);
}
}
std::destroy(packed, packed + reserved);
std::destroy(sparse, sparse + bucket);
alloc_traits::deallocate(allocator, packed, reserved);
bucket_alloc_traits::deallocate(bucket_allocator, sparse, bucket);
}
}
protected:
/**
* @brief Swaps two entities in the internal packed array.
* @param lhs A valid position of an entity within storage.
* @param rhs A valid position of an entity within storage.
*/
virtual void swap_at([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) {}
/**
* @brief Moves an entity in the internal packed array.
* @param from A valid position of an entity within storage.
* @param to A valid position of an entity within storage.
*/
virtual void move_and_pop([[maybe_unused]] const std::size_t from, [[maybe_unused]] const std::size_t to) {}
/**
* @brief Attempts to erase an entity from the internal packed array.
* @param entt A valid entity identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
virtual void swap_and_pop(const Entity entt, [[maybe_unused]] void *ud) {
auto &ref = sparse[page(entt)][offset(entt)];
const auto pos = static_cast<size_type>(traits_type::to_entity(ref));
ENTT_ASSERT(packed[pos] == entt, "Invalid entity identifier");
auto &last = packed[--count];
packed[pos] = last;
sparse[page(last)][offset(last)] = ref;
// lazy self-assignment guard
ref = null;
// unnecessary but it helps to detect nasty bugs
ENTT_ASSERT((last = tombstone, true), "");
}
/**
* @brief Attempts to erase an entity from the internal packed array.
* @param entt A valid entity identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
virtual void in_place_pop(const Entity entt, [[maybe_unused]] void *ud) {
auto &ref = sparse[page(entt)][offset(entt)];
const auto pos = static_cast<size_type>(traits_type::to_entity(ref));
ENTT_ASSERT(packed[pos] == entt, "Invalid entity identifier");
packed[pos] = std::exchange(free_list, traits_type::construct(static_cast<typename traits_type::entity_type>(pos)));
// lazy self-assignment guard
ref = null;
}
public:
/*! @brief Allocator type. */
using allocator_type = typename alloc_traits::allocator_type;
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Pointer type to contained entities. */
using pointer = alloc_const_pointer;
/*! @brief Random access iterator type. */
using iterator = sparse_set_iterator;
/*! @brief Reverse iterator type. */
using reverse_iterator = std::reverse_iterator<iterator>;
/**
* @brief Constructs an empty container with the given policy and allocator.
* @param pol Type of deletion policy.
* @param alloc Allocator to use (possibly default-constructed).
*/
explicit basic_sparse_set(deletion_policy pol, const allocator_type &alloc = {})
: allocator{alloc},
bucket_allocator{alloc},
sparse{bucket_alloc_traits::allocate(bucket_allocator, 0u)},
packed{alloc_traits::allocate(allocator, 0u)},
bucket{0u},
count{0u},
reserved{0u},
free_list{tombstone},
mode{pol}
{}
/**
* @brief Constructs an empty container with the given allocator.
* @param alloc Allocator to use (possibly default-constructed).
*/
explicit basic_sparse_set(const allocator_type &alloc = {})
: basic_sparse_set{deletion_policy::swap_and_pop, alloc}
{}
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
basic_sparse_set(basic_sparse_set &&other) ENTT_NOEXCEPT
: allocator{std::move(other.allocator)},
bucket_allocator{std::move(other.bucket_allocator)},
sparse{std::exchange(other.sparse, bucket_alloc_pointer{})},
packed{std::exchange(other.packed, alloc_pointer{})},
bucket{std::exchange(other.bucket, 0u)},
count{std::exchange(other.count, 0u)},
reserved{std::exchange(other.reserved, 0u)},
free_list{std::exchange(other.free_list, tombstone)},
mode{other.mode}
{}
/*! @brief Default destructor. */
virtual ~basic_sparse_set() {
release_memory();
}
/**
* @brief Move assignment operator.
* @param other The instance to move from.
* @return This sparse set.
*/
basic_sparse_set & operator=(basic_sparse_set &&other) ENTT_NOEXCEPT {
release_memory();
allocator = std::move(other.allocator);
bucket_allocator = std::move(other.bucket_allocator);
sparse = std::exchange(other.sparse, bucket_alloc_pointer{});
packed = std::exchange(other.packed, alloc_pointer{});
bucket = std::exchange(other.bucket, 0u);
count = std::exchange(other.count, 0u);
reserved = std::exchange(other.reserved, 0u);
free_list = std::exchange(other.free_list, tombstone);
mode = other.mode;
return *this;
}
/**
* @brief Returns the deletion policy of a sparse set.
* @return The deletion policy of the sparse set.
*/
[[nodiscard]] deletion_policy policy() const ENTT_NOEXCEPT {
return mode;
}
/**
* @brief Returns the next slot available for insertion.
* @return The next slot available for insertion.
*/
[[nodiscard]] size_type slot() const ENTT_NOEXCEPT {
return free_list == null ? count : static_cast<size_type>(traits_type::to_entity(free_list));
}
/**
* @brief Increases the capacity of a sparse set.
*
* If the new capacity is greater than the current capacity, new storage is
* allocated, otherwise the method does nothing.
*
* @param cap Desired capacity.
*/
void reserve(const size_type cap) {
if(cap > reserved) {
resize_packed(cap);
}
}
/**
* @brief Returns the number of elements that a sparse set has currently
* allocated space for.
* @return Capacity of the sparse set.
*/
[[nodiscard]] size_type capacity() const ENTT_NOEXCEPT {
return reserved;
}
/*! @brief Requests the removal of unused capacity. */
void shrink_to_fit() {
if(count < reserved) {
resize_packed(count);
}
}
/**
* @brief Returns the extent of a sparse set.
*
* The extent of a sparse set is also the size of the internal sparse array.
* There is no guarantee that the internal packed array has the same size.
* Usually the size of the internal sparse array is equal or greater than
* the one of the internal packed array.
*
* @return Extent of the sparse set.
*/
[[nodiscard]] size_type extent() const ENTT_NOEXCEPT {
return bucket * sparse_page;
}
/**
* @brief Returns the number of elements in a sparse set.
*
* The number of elements is also the size of the internal packed array.
* There is no guarantee that the internal sparse array has the same size.
* Usually the size of the internal sparse array is equal or greater than
* the one of the internal packed array.
*
* @return Number of elements.
*/
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
return count;
}
/**
* @brief Checks whether a sparse set is empty.
* @return True if the sparse set is empty, false otherwise.
*/
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return (count == size_type{});
}
/**
* @brief Direct access to the internal packed array.
* @return A pointer to the internal packed array.
*/
[[nodiscard]] pointer data() const ENTT_NOEXCEPT {
return packed;
}
/**
* @brief Returns an iterator to the beginning.
*
* The returned iterator points to the first entity of the internal packed
* array. If the sparse set is empty, the returned iterator will be equal to
* `end()`.
*
* @return An iterator to the first entity of the internal packed array.
*/
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return iterator{std::addressof(packed), static_cast<typename traits_type::difference_type>(count)};
}
/**
* @brief Returns an iterator to the end.
*
* The returned iterator points to the element following the last entity in
* the internal packed array. Attempting to dereference the returned
* iterator results in undefined behavior.
*
* @return An iterator to the element following the last entity of the
* internal packed array.
*/
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return iterator{std::addressof(packed), {}};
}
/**
* @brief Returns a reverse iterator to the beginning.
*
* The returned iterator points to the first entity of the reversed internal
* packed array. If the sparse set is empty, the returned iterator will be
* equal to `rend()`.
*
* @return An iterator to the first entity of the reversed internal packed
* array.
*/
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
return std::make_reverse_iterator(end());
}
/**
* @brief Returns a reverse iterator to the end.
*
* The returned iterator points to the element following the last entity in
* the reversed internal packed array. Attempting to dereference the
* returned iterator results in undefined behavior.
*
* @return An iterator to the element following the last entity of the
* reversed internal packed array.
*/
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
return std::make_reverse_iterator(begin());
}
/**
* @brief Finds an entity.
* @param entt A valid entity identifier.
* @return An iterator to the given entity if it's found, past the end
* iterator otherwise.
*/
[[nodiscard]] iterator find(const entity_type entt) const ENTT_NOEXCEPT {
return contains(entt) ? --(end() - index(entt)) : end();
}
/**
* @brief Checks if a sparse set contains an entity.
* @param entt A valid entity identifier.
* @return True if the sparse set contains the entity, false otherwise.
*/
[[nodiscard]] bool contains(const entity_type entt) const ENTT_NOEXCEPT {
ENTT_ASSERT(entt != tombstone && entt != null, "Invalid entity");
const auto curr = page(entt);
// testing versions permits to avoid accessing the packed array
return (curr < bucket && sparse[curr] && sparse[curr][offset(entt)] != null);
}
/**
* @brief Returns the position of an entity in a sparse set.
*
* @warning
* Attempting to get the position of an entity that doesn't belong to the
* sparse set results in undefined behavior.
*
* @param entt A valid entity identifier.
* @return The position of the entity in the sparse set.
*/
[[nodiscard]] size_type index(const entity_type entt) const ENTT_NOEXCEPT {
ENTT_ASSERT(contains(entt), "Set does not contain entity");
return static_cast<size_type>(traits_type::to_entity(sparse[page(entt)][offset(entt)]));
}
/**
* @brief Returns the entity at specified location, with bounds checking.
* @param pos The position for which to return the entity.
* @return The entity at specified location if any, a null entity otherwise.
*/
[[nodiscard]] entity_type at(const size_type pos) const ENTT_NOEXCEPT {
return pos < count ? packed[pos] : null;
}
/**
* @brief Returns the entity at specified location, without bounds checking.
* @param pos The position for which to return the entity.
* @return The entity at specified location.
*/
[[nodiscard]] entity_type operator[](const size_type pos) const ENTT_NOEXCEPT {
ENTT_ASSERT(pos < count, "Position is out of bounds");
return packed[pos];
}
/**
* @brief Appends an entity to a sparse set.
*
* @warning
* Attempting to assign an entity that already belongs to the sparse set
* results in undefined behavior.
*
* @param entt A valid entity identifier.
* @return The slot used for insertion.
*/
size_type emplace_back(const entity_type entt) {
ENTT_ASSERT(!contains(entt), "Set already contains entity");
if(count == reserved) {
const size_type sz = static_cast<size_type>(reserved * growth_factor);
resize_packed(sz + !(sz > reserved));
}
assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(count));
packed[count] = entt;
return count++;
}
/**
* @brief Assigns an entity to a sparse set.
*
* @warning
* Attempting to assign an entity that already belongs to the sparse set
* results in undefined behavior.
*
* @param entt A valid entity identifier.
* @return The slot used for insertion.
*/
size_type emplace(const entity_type entt) {
if(free_list == null) {
return emplace_back(entt);
} else {
ENTT_ASSERT(!contains(entt), "Set already contains entity");
const auto pos = static_cast<size_type>(traits_type::to_entity(free_list));
assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(pos));
free_list = std::exchange(packed[pos], entt);
return pos;
}
}
/**
* @brief Assigns one or more entities to a sparse set.
*
* @warning
* Attempting to assign an entity that already belongs to the sparse set
* results in undefined behavior.
*
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
*/
template<typename It>
void insert(It first, It last) {
reserve(count + std::distance(first, last));
for(; first != last; ++first) {
const auto entt = *first;
ENTT_ASSERT(!contains(entt), "Set already contains entity");
assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(count));
packed[count++] = entt;
}
}
/**
* @brief Erases an entity from a sparse set.
*
* @warning
* Attempting to erase an entity that doesn't belong to the sparse set
* results in undefined behavior.
*
* @param entt A valid entity identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
void erase(const entity_type entt, void *ud = nullptr) {
ENTT_ASSERT(contains(entt), "Set does not contain entity");
(mode == deletion_policy::in_place) ? in_place_pop(entt, ud) : swap_and_pop(entt, ud);
}
/**
* @brief Erases entities from a set.
*
* @sa erase
*
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
template<typename It>
void erase(It first, It last, void *ud = nullptr) {
for(; first != last; ++first) {
erase(*first, ud);
}
}
/**
* @brief Removes an entity from a sparse set if it exists.
* @param entt A valid entity identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
* @return True if the entity is actually removed, false otherwise.
*/
bool remove(const entity_type entt, void *ud = nullptr) {
return contains(entt) && (erase(entt, ud), true);
}
/**
* @brief Removes entities from a sparse set if they exist.
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
* @param ud Optional user data that are forwarded as-is to derived classes.
* @return The number of entities actually removed.
*/
template<typename It>
size_type remove(It first, It last, void *ud = nullptr) {
size_type found{};
for(; first != last; ++first) {
found += remove(*first, ud);
}
return found;
}
/*! @brief Removes all tombstones from the packed array of a sparse set. */
void compact() {
size_type next = count;
for(; next && packed[next - 1u] == tombstone; --next);
for(auto *it = &free_list; *it != null && next; it = std::addressof(packed[traits_type::to_entity(*it)])) {
if(const size_type pos = traits_type::to_entity(*it); pos < next) {
--next;
move_and_pop(next, pos);
std::swap(packed[next], packed[pos]);
sparse[page(packed[pos])][offset(packed[pos])] = traits_type::construct(static_cast<const typename traits_type::entity_type>(pos));
*it = traits_type::construct(static_cast<typename traits_type::entity_type>(next));
for(; next && packed[next - 1u] == tombstone; --next);
}
}
free_list = tombstone;
count = next;
}
/**
* @copybrief swap_at
*
* For what it's worth, this function affects both the internal sparse array
* and the internal packed array. Users should not care of that anyway.
*
* @warning
* Attempting to swap entities that don't belong to the sparse set results
* in undefined behavior.
*
* @param lhs A valid entity identifier.
* @param rhs A valid entity identifier.
*/
void swap(const entity_type lhs, const entity_type rhs) {
ENTT_ASSERT(contains(lhs), "Set does not contain entity");
ENTT_ASSERT(contains(rhs), "Set does not contain entity");
auto &entt = sparse[page(lhs)][offset(lhs)];
auto &other = sparse[page(rhs)][offset(rhs)];
const auto from = static_cast<size_type>(traits_type::to_entity(entt));
const auto to = static_cast<size_type>(traits_type::to_entity(other));
// basic no-leak guarantee (with invalid state) if swapping throws
swap_at(from, to);
std::swap(entt, other);
std::swap(packed[from], packed[to]);
}
/**
* @brief Sort the first count elements according to the given comparison
* function.
*
* The comparison function object must return `true` if the first element
* is _less_ than the second one, `false` otherwise. The signature of the
* comparison function should be equivalent to the following:
*
* @code{.cpp}
* bool(const Entity, const Entity);
* @endcode
*
* Moreover, the comparison function object shall induce a
* _strict weak ordering_ on the values.
*
* The sort function object must offer a member function template
* `operator()` that accepts three arguments:
*
* * An iterator to the first element of the range to sort.
* * An iterator past the last element of the range to sort.
* * A comparison function to use to compare the elements.
*
* @tparam Compare Type of comparison function object.
* @tparam Sort Type of sort function object.
* @tparam Args Types of arguments to forward to the sort function object.
* @param length Number of elements to sort.
* @param compare A valid comparison function object.
* @param algo A valid sort function object.
* @param args Arguments to forward to the sort function object, if any.
*/
template<typename Compare, typename Sort = std_sort, typename... Args>
void sort_n(const size_type length, Compare compare, Sort algo = Sort{}, Args &&... args) {
// basic no-leak guarantee (with invalid state) if sorting throws
ENTT_ASSERT(!(length > count), "Length exceeds the number of elements");
compact();
algo(std::make_reverse_iterator(packed + length), std::make_reverse_iterator(packed), std::move(compare), std::forward<Args>(args)...);
for(size_type pos{}; pos < length; ++pos) {
auto curr = pos;
auto next = index(packed[curr]);
while(curr != next) {
const auto idx = index(packed[next]);
const auto entt = packed[curr];
swap_at(next, idx);
sparse[page(entt)][offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(curr));
curr = std::exchange(next, idx);
}
}
}
/**
* @brief Sort all elements according to the given comparison function.
*
* @sa sort_n
*
* @tparam Compare Type of comparison function object.
* @tparam Sort Type of sort function object.
* @tparam Args Types of arguments to forward to the sort function object.
* @param compare A valid comparison function object.
* @param algo A valid sort function object.
* @param args Arguments to forward to the sort function object, if any.
*/
template<typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
sort_n(count, std::move(compare), std::move(algo), std::forward<Args>(args)...);
}
/**
* @brief Sort entities according to their order in another sparse set.
*
* Entities that are part of both the sparse sets are ordered internally
* according to the order they have in `other`. All the other entities goes
* to the end of the list and there are no guarantees on their order.<br/>
* In other terms, this function can be used to impose the same order on two
* sets by using one of them as a master and the other one as a slave.
*
* Iterating the sparse set with a couple of iterators returns elements in
* the expected order after a call to `respect`. See `begin` and `end` for
* more details.
*
* @param other The sparse sets that imposes the order of the entities.
*/
void respect(const basic_sparse_set &other) {
compact();
const auto to = other.end();
auto from = other.begin();
for(size_type pos = count - 1; pos && from != to; ++from) {
if(contains(*from)) {
if(*from != packed[pos]) {
// basic no-leak guarantee (with invalid state) if swapping throws
swap(packed[pos], *from);
}
--pos;
}
}
}
/**
* @brief Clears a sparse set.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
void clear(void *ud = nullptr) {
for(auto &&entity: *this) {
if(entity != tombstone) {
in_place_pop(entity, ud);
}
}
free_list = tombstone;
count = 0u;
}
private:
typename alloc_traits::allocator_type allocator;
typename bucket_alloc_traits::allocator_type bucket_allocator;
bucket_alloc_pointer sparse;
alloc_pointer packed;
std::size_t bucket;
std::size_t count;
std::size_t reserved;
entity_type free_list;
deletion_policy mode;
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,46 +0,0 @@
#ifndef ENTT_ENTITY_UTILITY_HPP
#define ENTT_ENTITY_UTILITY_HPP
#include "../core/type_traits.hpp"
namespace entt {
/**
* @brief Alias for exclusion lists.
* @tparam Type List of types.
*/
template<typename... Type>
struct exclude_t: type_list<Type...> {};
/**
* @brief Variable template for exclusion lists.
* @tparam Type List of types.
*/
template<typename... Type>
inline constexpr exclude_t<Type...> exclude{};
/**
* @brief Alias for lists of observed components.
* @tparam Type List of types.
*/
template<typename... Type>
struct get_t: type_list<Type...>{};
/**
* @brief Variable template for lists of observed components.
* @tparam Type List of types.
*/
template<typename... Type>
inline constexpr get_t<Type...> get{};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
#include "core/fwd.hpp"
#include "entity/fwd.hpp"
#include "poly/fwd.hpp"
#include "resource/fwd.hpp"
#include "signal/fwd.hpp"

View File

@ -1,111 +0,0 @@
#ifndef ENTT_LOCATOR_LOCATOR_HPP
#define ENTT_LOCATOR_LOCATOR_HPP
#include <memory>
#include <utility>
#include "../config/config.h"
namespace entt {
/**
* @brief Service locator, nothing more.
*
* A service locator can be used to do what it promises: locate services.<br/>
* Usually service locators are tightly bound to the services they expose and
* thus it's hard to define a general purpose class to do that. This template
* based implementation tries to fill the gap and to get rid of the burden of
* defining a different specific locator for each application.
*
* @tparam Service Type of service managed by the locator.
*/
template<typename Service>
struct service_locator {
/*! @brief Type of service offered. */
using service_type = Service;
/*! @brief Default constructor, deleted on purpose. */
service_locator() = delete;
/*! @brief Default destructor, deleted on purpose. */
~service_locator() = delete;
/**
* @brief Tests if a valid service implementation is set.
* @return True if the service is set, false otherwise.
*/
[[nodiscard]] static bool empty() ENTT_NOEXCEPT {
return !static_cast<bool>(service);
}
/**
* @brief Returns a weak pointer to a service implementation, if any.
*
* Clients of a service shouldn't retain references to it. The recommended
* way is to retrieve the service implementation currently set each and
* every time the need of using it arises. Otherwise users can incur in
* unexpected behaviors.
*
* @return A reference to the service implementation currently set, if any.
*/
[[nodiscard]] static std::weak_ptr<Service> get() ENTT_NOEXCEPT {
return service;
}
/**
* @brief Returns a weak reference to a service implementation, if any.
*
* Clients of a service shouldn't retain references to it. The recommended
* way is to retrieve the service implementation currently set each and
* every time the need of using it arises. Otherwise users can incur in
* unexpected behaviors.
*
* @warning
* In case no service implementation has been set, a call to this function
* results in undefined behavior.
*
* @return A reference to the service implementation currently set, if any.
*/
[[nodiscard]] static Service & ref() ENTT_NOEXCEPT {
return *service;
}
/**
* @brief Sets or replaces a service.
* @tparam Impl Type of the new service to use.
* @tparam Args Types of arguments to use to construct the service.
* @param args Parameters to use to construct the service.
*/
template<typename Impl = Service, typename... Args>
static void set(Args &&... args) {
service = std::make_shared<Impl>(std::forward<Args>(args)...);
}
/**
* @brief Sets or replaces a service.
* @param ptr Service to use to replace the current one.
*/
static void set(std::shared_ptr<Service> ptr) {
ENTT_ASSERT(static_cast<bool>(ptr), "Null service not allowed");
service = std::move(ptr);
}
/**
* @brief Resets a service.
*
* The service is no longer valid after a reset.
*/
static void reset() {
service.reset();
}
private:
inline static std::shared_ptr<Service> service = nullptr;
};
}
#endif

View File

@ -1,406 +0,0 @@
#ifndef ENTT_META_CONTAINER_HPP
#define ENTT_META_CONTAINER_HPP
#include <array>
#include <map>
#include <set>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../core/type_traits.hpp"
#include "type_traits.hpp"
namespace entt {
/**
* @brief Container traits.
* @tparam Container Type of the underlying container.
* @tparam Trait Traits associated with the underlying container.
*/
template<typename Container, template<typename> class... Trait>
struct meta_container_traits: public Trait<Container>... {
/*! @brief Type of container. */
using type = Container;
};
/**
* @brief Basic STL-compatible container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_container {
/**
* @brief Returns the size of the given container.
* @param cont The container for which to return the size.
* @return The size of the given container.
*/
[[nodiscard]] static typename Container::size_type size(const Container &cont) ENTT_NOEXCEPT {
return cont.size();
}
/**
* @brief Returns an iterator to the first element of the given container.
* @param cont The container for which to return the iterator.
* @return An iterator to the first element of the given container.
*/
[[nodiscard]] static typename Container::iterator begin(Container &cont) {
return cont.begin();
}
/**
* @brief Returns an iterator to the first element of the given container.
* @param cont The container for which to return the iterator.
* @return An iterator to the first element of the given container.
*/
[[nodiscard]] static typename Container::const_iterator cbegin(const Container &cont) {
return cont.begin();
}
/**
* @brief Returns an iterator past the last element of the given container.
* @param cont The container for which to return the iterator.
* @return An iterator past the last element of the given container.
*/
[[nodiscard]] static typename Container::iterator end(Container &cont) {
return cont.end();
}
/**
* @brief Returns an iterator past the last element of the given container.
* @param cont The container for which to return the iterator.
* @return An iterator past the last element of the given container.
*/
[[nodiscard]] static typename Container::const_iterator cend(const Container &cont) {
return cont.end();
}
};
/**
* @brief Basic STL-compatible associative container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_associative_container {
/**
* @brief Returns an iterator to the element with key equivalent to the
* given one, if any.
* @param cont The container in which to search for the element.
* @param key The key of the element to search.
* @return An iterator to the element with the given key, if any.
*/
[[nodiscard]] static typename Container::iterator find(Container &cont, const typename Container::key_type &key) {
return cont.find(key);
}
/*! @copydoc find */
[[nodiscard]] static typename Container::const_iterator cfind(const Container &cont, const typename Container::key_type &key) {
return cont.find(key);
}
};
/**
* @brief Basic STL-compatible dynamic container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_dynamic_container {
/**
* @brief Clears the content of the given container.
* @param cont The container for which to clear the content.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool clear([[maybe_unused]] Container &cont) {
return cont.clear(), true;
}
};
/**
* @brief Basic STL-compatible dynamic associative container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_dynamic_associative_container {
/**
* @brief Removes the specified element from the given container.
* @param cont The container from which to remove the element.
* @param key The element to remove.
* @return A bool denoting whether the removal took place.
*/
[[nodiscard]] static bool erase([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) {
const auto sz = cont.size();
return cont.erase(key) != sz;
}
};
/**
* @brief Basic STL-compatible sequence container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_sequence_container {
/**
* @brief Returns a reference to the element at the specified location of
* the given container (no bounds checking is performed).
* @param cont The container from which to get the element.
* @param pos The position of the element to return.
* @return A reference to the requested element.
*/
[[nodiscard]] static typename Container::reference get(Container &cont, typename Container::size_type pos) {
return cont[pos];
}
/*! @copydoc get */
[[nodiscard]] static typename Container::const_reference cget(const Container &cont, typename Container::size_type pos) {
return cont[pos];
}
};
/**
* @brief STL-compatible dynamic associative key-only container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct dynamic_associative_key_only_container {
/**
* @brief Inserts an element into the given container.
* @param cont The container in which to insert the element.
* @param key The element to insert.
* @return A bool denoting whether the insertion took place.
*/
[[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) {
return cont.insert(key).second;
}
};
/**
* @brief STL-compatible dynamic key-value associative container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct dynamic_associative_key_value_container {
/**
* @brief Inserts an element (a key/value pair) into the given container.
* @param cont The container in which to insert the element.
* @param key The key of the element to insert.
* @param value The value of the element to insert.
* @return A bool denoting whether the insertion took place.
*/
[[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key, [[maybe_unused]] const typename Container::mapped_type &value) {
return cont.insert(std::make_pair(key, value)).second;
}
};
/**
* @brief STL-compatible dynamic sequence container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct dynamic_sequence_container {
/**
* @brief Resizes the given container to contain the given number of
* elements.
* @param cont The container to resize.
* @param sz The new size of the container.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool resize([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::size_type sz) {
return cont.resize(sz), true;
}
/**
* @brief Inserts an element at the specified location of the given
* container.
* @param cont The container into which to insert the element.
* @param it Iterator before which the element will be inserted.
* @param value Element value to insert.
* @return A pair consisting of an iterator to the inserted element (in case
* of success) and a bool denoting whether the insertion took place.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> insert([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::const_iterator it, [[maybe_unused]] const typename Container::value_type &value) {
return { cont.insert(it, value), true };
}
/**
* @brief Removes the element at the specified location from the given
* container.
* @param cont The container from which to remove the element.
* @param it Iterator to the element to remove.
* @return A pair consisting of an iterator following the last removed
* element (in case of success) and a bool denoting whether the insertion
* took place.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> erase([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::const_iterator it) {
return { cont.erase(it), true };
}
};
/**
* @brief STL-compatible fixed sequence container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct fixed_sequence_container {
/**
* @brief Does nothing.
* @return False to indicate failure in all cases.
*/
[[nodiscard]] static bool resize(const Container &, typename Container::size_type) {
return false;
}
/**
* @brief Does nothing.
* @return False to indicate failure in all cases.
*/
[[nodiscard]] static bool clear(const Container &) {
return false;
}
/**
* @brief Does nothing.
* @return A pair consisting of an invalid iterator and a false value to
* indicate failure in all cases.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> insert(const Container &, typename Container::const_iterator, const typename Container::value_type &) {
return { {}, false };
}
/**
* @brief Does nothing.
* @return A pair consisting of an invalid iterator and a false value to
* indicate failure in all cases.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> erase(const Container &, typename Container::const_iterator) {
return { {}, false };
}
};
/**
* @brief Meta sequence container traits for `std::vector`s of any type.
* @tparam Type The type of elements.
* @tparam Args Other arguments.
*/
template<typename Type, typename... Args>
struct meta_sequence_container_traits<std::vector<Type, Args...>>
: meta_container_traits<
std::vector<Type, Args...>,
basic_container,
basic_dynamic_container,
basic_sequence_container,
dynamic_sequence_container
>
{};
/**
* @brief Meta sequence container traits for `std::array`s of any type.
* @tparam Type The type of elements.
* @tparam N The number of elements.
*/
template<typename Type, auto N>
struct meta_sequence_container_traits<std::array<Type, N>>
: meta_container_traits<
std::array<Type, N>,
basic_container,
basic_sequence_container,
fixed_sequence_container
>
{};
/**
* @brief Meta associative container traits for `std::map`s of any type.
* @tparam Key The key type of elements.
* @tparam Value The value type of elements.
* @tparam Args Other arguments.
*/
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<std::map<Key, Value, Args...>>
: meta_container_traits<
std::map<Key, Value, Args...>,
basic_container,
basic_associative_container,
basic_dynamic_container,
basic_dynamic_associative_container,
dynamic_associative_key_value_container
>
{};
/**
* @brief Meta associative container traits for `std::unordered_map`s of any
* type.
* @tparam Key The key type of elements.
* @tparam Value The value type of elements.
* @tparam Args Other arguments.
*/
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>>
: meta_container_traits<
std::unordered_map<Key, Value, Args...>,
basic_container,
basic_associative_container,
basic_dynamic_container,
basic_dynamic_associative_container,
dynamic_associative_key_value_container
>
{};
/**
* @brief Meta associative container traits for `std::set`s of any type.
* @tparam Key The type of elements.
* @tparam Args Other arguments.
*/
template<typename Key, typename... Args>
struct meta_associative_container_traits<std::set<Key, Args...>>
: meta_container_traits<
std::set<Key, Args...>,
basic_container,
basic_associative_container,
basic_dynamic_container,
basic_dynamic_associative_container,
dynamic_associative_key_only_container
>
{};
/**
* @brief Meta associative container traits for `std::unordered_set`s of any
* type.
* @tparam Key The type of elements.
* @tparam Args Other arguments.
*/
template<typename Key, typename... Args>
struct meta_associative_container_traits<std::unordered_set<Key, Args...>>
: meta_container_traits<
std::unordered_set<Key, Args...>,
basic_container,
basic_associative_container,
basic_dynamic_container,
basic_dynamic_associative_container,
dynamic_associative_key_only_container
>
{};
}
#endif

View File

@ -1,68 +0,0 @@
#ifndef ENTT_META_CTX_HPP
#define ENTT_META_CTX_HPP
#include "../core/attribute.h"
#include "../config/config.h"
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
struct meta_type_node;
struct ENTT_API meta_context {
// we could use the lines below but VS2017 returns with an ICE if combined with ENTT_API despite the code being valid C++
// inline static meta_type_node *local = nullptr;
// inline static meta_type_node **global = &local;
[[nodiscard]] static meta_type_node * & local() ENTT_NOEXCEPT {
static meta_type_node *chain = nullptr;
return chain;
}
[[nodiscard]] static meta_type_node ** & global() ENTT_NOEXCEPT {
static meta_type_node **chain = &local();
return chain;
}
};
}
/**
* Internal details not to be documented.
* @endcond
*/
/*! @brief Opaque container for a meta context. */
struct meta_ctx {
/**
* @brief Binds the meta system to a given context.
* @param other A valid context to which to bind.
*/
static void bind(meta_ctx other) ENTT_NOEXCEPT {
internal::meta_context::global() = other.ctx;
}
private:
internal::meta_type_node **ctx{&internal::meta_context::local()};
};
}
#endif

View File

@ -1,597 +0,0 @@
#ifndef ENTT_META_FACTORY_HPP
#define ENTT_META_FACTORY_HPP
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/fwd.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "meta.hpp"
#include "node.hpp"
#include "policy.hpp"
#include "utility.hpp"
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
template<typename Node>
[[nodiscard]] bool find_if(const Node *candidate, const Node *node) ENTT_NOEXCEPT {
return node && (node == candidate || find_if(candidate, node->next));
}
template<typename Id, typename Node>
[[nodiscard]] bool find_if_not(const Id id, Node *node, const Node *owner) ENTT_NOEXCEPT {
if constexpr(std::is_pointer_v<Id>) {
return node && ((*node->id == *id && node != owner) || find_if_not(id, node->next, owner));
} else {
return node && ((node->id == id && node != owner) || find_if_not(id, node->next, owner));
}
}
}
/**
* Internal details not to be documented.
* @endcond
*/
/**
* @brief Meta factory to be used for reflection purposes.
*
* The meta factory is an utility class used to reflect types, data members and
* functions of all sorts. This class ensures that the underlying web of types
* is built correctly and performs some checks in debug mode to ensure that
* there are no subtle errors at runtime.
*/
template<typename...>
struct meta_factory;
/**
* @brief Extended meta factory to be used for reflection purposes.
* @tparam Type Reflected type for which the factory was created.
* @tparam Spec Property specialization pack used to disambiguate overloads.
*/
template<typename Type, typename... Spec>
struct meta_factory<Type, Spec...>: public meta_factory<Type> {
private:
template<std::size_t Step = 0, std::size_t... Index, typename... Property, typename... Other>
void unpack(std::index_sequence<Index...>, std::tuple<Property...> property, Other &&... other) {
unroll<Step>(choice<3>, std::move(std::get<Index>(property))..., std::forward<Other>(other)...);
}
template<std::size_t Step = 0, typename... Property, typename... Other>
void unroll(choice_t<3>, std::tuple<Property...> property, Other &&... other) {
unpack<Step>(std::index_sequence_for<Property...>{}, std::move(property), std::forward<Other>(other)...);
}
template<std::size_t Step = 0, typename... Property, typename... Other>
void unroll(choice_t<2>, std::pair<Property...> property, Other &&... other) {
assign<Step>(std::move(property.first), std::move(property.second));
unroll<Step+1>(choice<3>, std::forward<Other>(other)...);
}
template<std::size_t Step = 0, typename Property, typename... Other>
std::enable_if_t<!std::is_invocable_v<Property>>
unroll(choice_t<1>, Property &&property, Other &&... other) {
assign<Step>(std::forward<Property>(property));
unroll<Step+1>(choice<3>, std::forward<Other>(other)...);
}
template<std::size_t Step = 0, typename Func, typename... Other>
void unroll(choice_t<0>, Func &&invocable, Other &&... other) {
unroll<Step>(choice<3>, std::forward<Func>(invocable)(), std::forward<Other>(other)...);
}
template<std::size_t>
void unroll(choice_t<0>) {}
template<std::size_t = 0, typename Key>
void assign(Key &&key, meta_any value = {}) {
static meta_any property[2u]{};
static internal::meta_prop_node node{
nullptr,
property[0u],
property[1u]
};
entt::meta_any instance{std::forward<Key>(key)};
ENTT_ASSERT(!internal::find_if_not(&instance, *curr, &node), "Duplicate key");
property[0u] = std::move(instance);
property[1u] = std::move(value);
if(!internal::find_if(&node, *curr)) {
node.next = *curr;
*curr = &node;
}
}
public:
/**
* @brief Constructs an extended factory from a given node.
* @param target The underlying node to which to assign the properties.
*/
meta_factory(internal::meta_prop_node **target) ENTT_NOEXCEPT
: curr{target}
{}
/**
* @brief Assigns a property to the last meta object created.
*
* Both the key and the value (if any) must be at least copy constructible.
*
* @tparam PropertyOrKey Type of the property or property key.
* @tparam Value Optional type of the property value.
* @param property_or_key Property or property key.
* @param value Optional property value.
* @return A meta factory for the parent type.
*/
template<typename PropertyOrKey, typename... Value>
auto prop(PropertyOrKey &&property_or_key, Value &&... value) && {
if constexpr(sizeof...(Value) == 0) {
unroll(choice<3>, std::forward<PropertyOrKey>(property_or_key));
} else {
assign(std::forward<PropertyOrKey>(property_or_key), std::forward<Value>(value)...);
}
return meta_factory<Type, Spec..., PropertyOrKey, Value...>{curr};
}
/**
* @brief Assigns properties to the last meta object created.
*
* Both the keys and the values (if any) must be at least copy
* constructible.
*
* @tparam Property Types of the properties.
* @param property Properties to assign to the last meta object created.
* @return A meta factory for the parent type.
*/
template <typename... Property>
auto props(Property... property) && {
unroll(choice<3>, std::forward<Property>(property)...);
return meta_factory<Type, Spec..., Property...>{curr};
}
private:
internal::meta_prop_node **curr;
};
/**
* @brief Basic meta factory to be used for reflection purposes.
* @tparam Type Reflected type for which the factory was created.
*/
template<typename Type>
struct meta_factory<Type> {
/**
* @brief Makes a meta type _searchable_.
* @param id Optional unique identifier.
* @return An extended meta factory for the given type.
*/
auto type(const id_type id = type_hash<Type>::value()) {
auto * const node = internal::meta_info<Type>::resolve();
ENTT_ASSERT(!internal::find_if_not(id, *internal::meta_context::global(), node), "Duplicate identifier");
node->id = id;
if(!internal::find_if(node, *internal::meta_context::global())) {
node->next = *internal::meta_context::global();
*internal::meta_context::global() = node;
}
return meta_factory<Type, Type>{&node->prop};
}
/**
* @brief Assigns a meta base to a meta type.
*
* A reflected base class must be a real base class of the reflected type.
*
* @tparam Base Type of the base class to assign to the meta type.
* @return A meta factory for the parent type.
*/
template<typename Base>
auto base() ENTT_NOEXCEPT {
static_assert(std::is_base_of_v<Base, Type>, "Invalid base type");
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_base_node node{
type,
nullptr,
&internal::meta_info<Base>::resolve,
[](const void *instance) ENTT_NOEXCEPT -> const void * {
return static_cast<const Base *>(static_cast<const Type *>(instance));
}
};
if(!internal::find_if(&node, type->base)) {
node.next = type->base;
type->base = &node;
}
return meta_factory<Type>{};
}
/**
* @brief Assigns a meta conversion function to a meta type.
*
* Conversion functions can be either free functions or member
* functions.<br/>
* In case of free functions, they must accept a const reference to an
* instance of the parent type as an argument. In case of member functions,
* they should have no arguments at all.
*
* @tparam Candidate The actual function to use for the conversion.
* @return A meta factory for the parent type.
*/
template<auto Candidate>
std::enable_if_t<std::is_member_function_pointer_v<decltype(Candidate)>, meta_factory<Type>> conv() ENTT_NOEXCEPT {
using conv_type = std::invoke_result_t<decltype(Candidate), Type &>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_conv_node node{
type,
nullptr,
&internal::meta_info<conv_type>::resolve,
[](const void *instance) -> meta_any {
return (static_cast<const Type *>(instance)->*Candidate)();
}
};
if(!internal::find_if(&node, type->conv)) {
node.next = type->conv;
type->conv = &node;
}
return meta_factory<Type>{};
}
/*! @copydoc conv */
template<auto Candidate>
std::enable_if_t<!std::is_member_function_pointer_v<decltype(Candidate)>, meta_factory<Type>> conv() ENTT_NOEXCEPT {
using conv_type = std::invoke_result_t<decltype(Candidate), Type &>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_conv_node node{
type,
nullptr,
&internal::meta_info<conv_type>::resolve,
[](const void *instance) -> meta_any {
return Candidate(*static_cast<const Type *>(instance));
}
};
if(!internal::find_if(&node, type->conv)) {
node.next = type->conv;
type->conv = &node;
}
return meta_factory<Type>{};
}
/**
* @brief Assigns a meta conversion function to a meta type.
*
* The given type must be such that an instance of the reflected type can be
* converted to it.
*
* @tparam To Type of the conversion function to assign to the meta type.
* @return A meta factory for the parent type.
*/
template<typename To>
auto conv() ENTT_NOEXCEPT {
static_assert(std::is_convertible_v<Type, To>, "Could not convert to the required type");
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_conv_node node{
type,
nullptr,
&internal::meta_info<To>::resolve,
[](const void *instance) -> meta_any {
return static_cast<To>(*static_cast<const Type *>(instance));
}
};
if(!internal::find_if(&node, type->conv)) {
node.next = type->conv;
type->conv = &node;
}
return meta_factory<Type>{};
}
/**
* @brief Assigns a meta constructor to a meta type.
*
* Both member functions and free function can be assigned to meta types in
* the role of constructors. All that is required is that they return an
* instance of the underlying type.<br/>
* From a client's point of view, nothing changes if a constructor of a meta
* type is a built-in one or not.
*
* @tparam Candidate The actual function to use as a constructor.
* @tparam Policy Optional policy (no policy set by default).
* @return An extended meta factory for the parent type.
*/
template<auto Candidate, typename Policy = as_is_t>
auto ctor() ENTT_NOEXCEPT {
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
static_assert(std::is_same_v<std::decay_t<typename descriptor::return_type>, Type>, "The function doesn't return an object of the required type");
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_ctor_node node{
type,
nullptr,
nullptr,
descriptor::args_type::size,
[](const typename internal::meta_ctor_node::size_type index) ENTT_NOEXCEPT {
return meta_arg(typename descriptor::args_type{}, index);
},
[](meta_any * const args) {
return meta_invoke<Type, Candidate, Policy>({}, args, std::make_index_sequence<descriptor::args_type::size>{});
}
};
if(!internal::find_if(&node, type->ctor)) {
node.next = type->ctor;
type->ctor = &node;
}
return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
}
/**
* @brief Assigns a meta constructor to a meta type.
*
* A meta constructor is uniquely identified by the types of its arguments
* and is such that there exists an actual constructor of the underlying
* type that can be invoked with parameters whose types are those given.
*
* @tparam Args Types of arguments to use to construct an instance.
* @return An extended meta factory for the parent type.
*/
template<typename... Args>
auto ctor() ENTT_NOEXCEPT {
using descriptor = meta_function_helper_t<Type, Type(*)(Args...)>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_ctor_node node{
type,
nullptr,
nullptr,
descriptor::args_type::size,
[](const typename internal::meta_ctor_node::size_type index) ENTT_NOEXCEPT {
return meta_arg(typename descriptor::args_type{}, index);
},
[](meta_any * const args) {
return meta_construct<Type, Args...>(args, std::make_index_sequence<descriptor::args_type::size>{});
}
};
if(!internal::find_if(&node, type->ctor)) {
node.next = type->ctor;
type->ctor = &node;
}
return meta_factory<Type, Type(Args...)>{&node.prop};
}
/**
* @brief Assigns a meta destructor to a meta type.
*
* Free functions can be assigned to meta types in the role of destructors.
* The signature of the function should identical to the following:
*
* @code{.cpp}
* void(Type &);
* @endcode
*
* The purpose is to give users the ability to free up resources that
* require special treatment before an object is actually destroyed.
*
* @tparam Func The actual function to use as a destructor.
* @return A meta factory for the parent type.
*/
template<auto Func>
auto dtor() ENTT_NOEXCEPT {
static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
auto * const type = internal::meta_info<Type>::resolve();
type->dtor = [](void *instance) {
Func(*static_cast<Type *>(instance));
};
return meta_factory<Type>{};
}
/**
* @brief Assigns a meta data to a meta type.
*
* Both data members and static and global variables, as well as constants
* of any kind, can be assigned to a meta type.<br/>
* From a client's point of view, all the variables associated with the
* reflected object will appear as if they were part of the type itself.
*
* @tparam Data The actual variable to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @return An extended meta factory for the parent type.
*/
template<auto Data, typename Policy = as_is_t>
auto data(const id_type id) ENTT_NOEXCEPT {
if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
return data<Data, Data, Policy>(id);
} else {
using data_type = std::remove_pointer_t<decltype(Data)>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_data_node node{
{},
type,
nullptr,
nullptr,
std::is_same_v<Type, data_type> || std::is_const_v<data_type>,
true,
&internal::meta_info<data_type>::resolve,
&meta_setter<Type, Data>,
&meta_getter<Type, Data, Policy>
};
ENTT_ASSERT(!internal::find_if_not(id, type->data, &node), "Duplicate identifier");
node.id = id;
if(!internal::find_if(&node, type->data)) {
node.next = type->data;
type->data = &node;
}
return meta_factory<Type, std::integral_constant<decltype(Data), Data>>{&node.prop};
}
}
/**
* @brief Assigns a meta data to a meta type by means of its setter and
* getter.
*
* Setters and getters can be either free functions, member functions or a
* mix of them.<br/>
* In case of free functions, setters and getters must accept a reference to
* an instance of the parent type as their first argument. A setter has then
* an extra argument of a type convertible to that of the parameter to
* set.<br/>
* In case of member functions, getters have no arguments at all, while
* setters has an argument of a type convertible to that of the parameter to
* set.
*
* @tparam Setter The actual function to use as a setter.
* @tparam Getter The actual function to use as a getter.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @return An extended meta factory for the parent type.
*/
template<auto Setter, auto Getter, typename Policy = as_is_t>
auto data(const id_type id) ENTT_NOEXCEPT {
using underlying_type = std::remove_reference_t<std::invoke_result_t<decltype(Getter), Type &>>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_data_node node{
{},
type,
nullptr,
nullptr,
std::is_same_v<decltype(Setter), std::nullptr_t> || (std::is_member_object_pointer_v<decltype(Setter)> && std::is_const_v<underlying_type>),
false,
&internal::meta_info<underlying_type>::resolve,
&meta_setter<Type, Setter>,
&meta_getter<Type, Getter, Policy>
};
ENTT_ASSERT(!internal::find_if_not(id, type->data, &node), "Duplicate identifier");
node.id = id;
if(!internal::find_if(&node, type->data)) {
node.next = type->data;
type->data = &node;
}
return meta_factory<Type, std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
}
/**
* @brief Assigns a meta funcion to a meta type.
*
* Both member functions and free functions can be assigned to a meta
* type.<br/>
* From a client's point of view, all the functions associated with the
* reflected object will appear as if they were part of the type itself.
*
* @tparam Candidate The actual function to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @return An extended meta factory for the parent type.
*/
template<auto Candidate, typename Policy = as_is_t>
auto func(const id_type id) ENTT_NOEXCEPT {
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_func_node node{
{},
type,
nullptr,
nullptr,
descriptor::args_type::size,
descriptor::is_const,
descriptor::is_static,
&internal::meta_info<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, typename descriptor::return_type>>::resolve,
[](const typename internal::meta_func_node::size_type index) ENTT_NOEXCEPT {
return meta_arg(typename descriptor::args_type{}, index);
},
[](meta_handle instance, meta_any *args) {
return meta_invoke<Type, Candidate, Policy>(std::move(instance), args, std::make_index_sequence<descriptor::args_type::size>{});
}
};
for(auto *it = &type->func; *it; it = &(*it)->next) {
if(*it == &node) {
*it = node.next;
break;
}
}
internal::meta_func_node **it = &type->func;
for(; *it && (*it)->id != id; it = &(*it)->next);
for(; *it && (*it)->id == id && (*it)->arity < node.arity; it = &(*it)->next);
node.id = id;
node.next = *it;
*it = &node;
return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
}
};
/**
* @brief Utility function to use for reflection.
*
* This is the point from which everything starts.<br/>
* By invoking this function with a type that is not yet reflected, a meta type
* is created to which it will be possible to attach meta objects through a
* dedicated factory.
*
* @tparam Type Type to reflect.
* @return A meta factory for the given type.
*/
template<typename Type>
[[nodiscard]] auto meta() ENTT_NOEXCEPT {
auto * const node = internal::meta_info<Type>::resolve();
// extended meta factory to allow assigning properties to opaque meta types
return meta_factory<Type, Type>{&node->prop};
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,270 +0,0 @@
#ifndef ENTT_META_NODE_HPP
#define ENTT_META_NODE_HPP
#include <cstddef>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/attribute.h"
#include "../core/fwd.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "type_traits.hpp"
namespace entt {
class meta_any;
class meta_type;
struct meta_handle;
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
struct meta_type_node;
struct meta_prop_node {
meta_prop_node * next;
const meta_any &id;
meta_any &value;
};
struct meta_base_node {
meta_type_node * const parent;
meta_base_node * next;
meta_type_node *(* const type)() ENTT_NOEXCEPT;
const void *(* const cast)(const void *) ENTT_NOEXCEPT;
};
struct meta_conv_node {
meta_type_node * const parent;
meta_conv_node * next;
meta_type_node *(* const type)() ENTT_NOEXCEPT;
meta_any(* const conv)(const void *);
};
struct meta_ctor_node {
using size_type = std::size_t;
meta_type_node * const parent;
meta_ctor_node * next;
meta_prop_node * prop;
const size_type arity;
meta_type(* const arg)(const size_type) ENTT_NOEXCEPT;
meta_any(* const invoke)(meta_any * const);
};
struct meta_data_node {
id_type id;
meta_type_node * const parent;
meta_data_node * next;
meta_prop_node * prop;
const bool is_const;
const bool is_static;
meta_type_node *(* const type)() ENTT_NOEXCEPT;
bool(* const set)(meta_handle, meta_any);
meta_any(* const get)(meta_handle);
};
struct meta_func_node {
using size_type = std::size_t;
id_type id;
meta_type_node * const parent;
meta_func_node * next;
meta_prop_node * prop;
const size_type arity;
const bool is_const;
const bool is_static;
meta_type_node *(* const ret)() ENTT_NOEXCEPT;
meta_type(* const arg)(const size_type) ENTT_NOEXCEPT;
meta_any(* const invoke)(meta_handle, meta_any *);
};
struct meta_template_info {
using size_type = std::size_t;
const bool is_template_specialization;
const size_type arity;
meta_type_node *(* const type)() ENTT_NOEXCEPT;
meta_type_node *(* const arg)(const size_type) ENTT_NOEXCEPT;
};
struct meta_type_node {
using size_type = std::size_t;
const type_info info;
id_type id;
meta_type_node * next;
meta_prop_node * prop;
const size_type size_of;
const bool is_void;
const bool is_integral;
const bool is_floating_point;
const bool is_array;
const bool is_enum;
const bool is_union;
const bool is_class;
const bool is_pointer;
const bool is_function_pointer;
const bool is_member_object_pointer;
const bool is_member_function_pointer;
const bool is_pointer_like;
const bool is_sequence_container;
const bool is_associative_container;
const meta_template_info template_info;
const size_type rank;
size_type(* const extent)(const size_type) ENTT_NOEXCEPT ;
meta_type_node *(* const remove_pointer)() ENTT_NOEXCEPT;
meta_type_node *(* const remove_extent)() ENTT_NOEXCEPT;
meta_ctor_node * const def_ctor;
meta_ctor_node *ctor{nullptr};
meta_base_node *base{nullptr};
meta_conv_node *conv{nullptr};
meta_data_node *data{nullptr};
meta_func_node *func{nullptr};
void(* dtor)(void *){nullptr};
};
template<auto Member, typename Op, typename Node>
auto meta_visit(const Op &op, const Node *node)
-> std::decay_t<decltype(node->*Member)> {
for(auto *curr = node->*Member; curr; curr = curr->next) {
if(op(curr)) {
return curr;
}
}
if constexpr(std::is_same_v<Node, meta_type_node>) {
for(auto *curr = node->base; curr; curr = curr->next) {
if(auto *ret = meta_visit<Member>(op, curr->type()); ret) {
return ret;
}
}
}
return nullptr;
}
template<typename... Args>
meta_type_node * meta_arg_node(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT;
template<typename Type>
class ENTT_API meta_node {
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Invalid type");
template<std::size_t... Index>
[[nodiscard]] static auto extent(const meta_type_node::size_type dim, std::index_sequence<Index...>) ENTT_NOEXCEPT {
meta_type_node::size_type ext{};
((ext = (dim == Index ? std::extent_v<Type, Index> : ext)), ...);
return ext;
}
[[nodiscard]] static meta_ctor_node * meta_default_constructor([[maybe_unused]] meta_type_node *type) ENTT_NOEXCEPT {
if constexpr(std::is_default_constructible_v<Type>) {
static meta_ctor_node node{
type,
nullptr,
nullptr,
0u,
nullptr,
[](meta_any * const) { return meta_any{std::in_place_type<Type>}; }
};
return &node;
} else {
return nullptr;
}
}
[[nodiscard]] static meta_template_info meta_template_descriptor() ENTT_NOEXCEPT {
if constexpr(is_complete_v<meta_template_traits<Type>>) {
return {
true,
meta_template_traits<Type>::args_type::size,
&meta_node<typename meta_template_traits<Type>::class_type>::resolve,
[](const std::size_t index) ENTT_NOEXCEPT {
return meta_arg_node(typename meta_template_traits<Type>::args_type{}, index);
}
};
} else {
return { false, 0u, nullptr, nullptr };
}
}
public:
[[nodiscard]] static meta_type_node * resolve() ENTT_NOEXCEPT {
static meta_type_node node{
type_id<Type>(),
{},
nullptr,
nullptr,
size_of_v<Type>,
std::is_void_v<Type>,
std::is_integral_v<Type>,
std::is_floating_point_v<Type>,
std::is_array_v<Type>,
std::is_enum_v<Type>,
std::is_union_v<Type>,
std::is_class_v<Type>,
std::is_pointer_v<Type>,
std::is_pointer_v<Type> && std::is_function_v<std::remove_pointer_t<Type>>,
std::is_member_object_pointer_v<Type>,
std::is_member_function_pointer_v<Type>,
is_meta_pointer_like_v<Type>,
is_complete_v<meta_sequence_container_traits<Type>>,
is_complete_v<meta_associative_container_traits<Type>>,
meta_template_descriptor(),
std::rank_v<Type>,
[](meta_type_node::size_type dim) ENTT_NOEXCEPT { return extent(dim, std::make_index_sequence<std::rank_v<Type>>{}); },
&meta_node<std::remove_cv_t<std::remove_reference_t<std::remove_pointer_t<Type>>>>::resolve,
&meta_node<std::remove_cv_t<std::remove_reference_t<std::remove_extent_t<Type>>>>::resolve,
meta_default_constructor(&node),
meta_default_constructor(&node)
};
return &node;
}
};
template<typename Type>
struct meta_info: meta_node<std::remove_cv_t<std::remove_reference_t<Type>>> {};
template<typename... Args>
meta_type_node * meta_arg_node(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT {
meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_info<Args>::resolve()...};
return args[index + 1u];
}
}
/**
* Internal details not to be documented.
* @endcond
*/
}
#endif

View File

@ -1,27 +0,0 @@
#ifndef ENTT_META_POLICY_HPP
#define ENTT_META_POLICY_HPP
namespace entt {
/*! @brief Empty class type used to request the _as ref_ policy. */
struct as_ref_t {};
/*! @brief Empty class type used to request the _as cref_ policy. */
struct as_cref_t {};
/*! @brief Empty class type used to request the _as-is_ policy. */
struct as_is_t {};
/*! @brief Empty class type used to request the _as void_ policy. */
struct as_void_t {};
}
#endif

Some files were not shown because too many files have changed in this diff Show More