初始化内容
This commit is contained in:
Vendored
+73
@@ -0,0 +1,73 @@
|
||||
---
|
||||
AccessModifierOffset: -4
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 100
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
Language: Cpp
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
|
||||
...
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
paths:
|
||||
- 'Source'
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
repo_token: amVxRIVnLlAXJBJo02AKMkxVHN0IeBArV
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
* text=auto
|
||||
@@ -0,0 +1,34 @@
|
||||
name: Amalgamate
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- "**/workflows/amalgamate.yml"
|
||||
- "**/Source/**"
|
||||
- "**/amalgamate.py"
|
||||
|
||||
jobs:
|
||||
run:
|
||||
name: Create Amalgamation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.9
|
||||
|
||||
- name: Create amalgamation file
|
||||
run: python amalgamate.py
|
||||
|
||||
- name: Commit changes
|
||||
uses: EndBug/add-and-commit@v10
|
||||
with:
|
||||
committer_name: GitHub Actions
|
||||
committer_email: actions@github.com
|
||||
message: Update amalgamation file
|
||||
add: 'Distribution/LuaBridge/*.h'
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
name: ASAN
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "**/workflows/build_asan.yml"
|
||||
- "**/Source/**"
|
||||
- "**/Tests/**"
|
||||
- "**/ThirdParty/**"
|
||||
- "**/CMakeLists.txt"
|
||||
- "**/.gitmodules"
|
||||
- "!**/*.md"
|
||||
- "!**/*.txt"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BUILD_TYPE: RelWithDebInfo
|
||||
|
||||
jobs:
|
||||
lua:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
lua:
|
||||
- { version: "5.1", suffix: "51" }
|
||||
- { version: "5.2", suffix: "52" }
|
||||
- { version: "5.3", suffix: "53" }
|
||||
- { version: "5.4", suffix: "54" }
|
||||
- { version: "5.5", suffix: "55" }
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get -y install ninja-build
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -DLUABRIDGE_SANITIZE=address -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
env:
|
||||
ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -DLUABRIDGE_SANITIZE=address -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
env:
|
||||
ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -DLUABRIDGE_SANITIZE=address -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
env:
|
||||
ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
name: Linux
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "**/workflows/build_linux.yml"
|
||||
- "**/Source/**"
|
||||
- "**/Tests/**"
|
||||
- "**/ThirdParty/**"
|
||||
- "**/CMakeLists.txt"
|
||||
- "**/.gitmodules"
|
||||
- "!**/*.md"
|
||||
- "!**/*.txt"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
lua:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
lua:
|
||||
- { version: "5.1", suffix: "51" }
|
||||
- { version: "5.2", suffix: "52" }
|
||||
- { version: "5.3", suffix: "53" }
|
||||
- { version: "5.4", suffix: "54" }
|
||||
- { version: "5.5", suffix: "55" }
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get -y install ninja-build
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
luajit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install ninja-build
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -G Ninja
|
||||
|
||||
- name: Build LuaJIT (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTestsLuaJIT \
|
||||
LuaBridgeTestsLuaJITNoexcept
|
||||
|
||||
- name: Test LuaJIT (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuaJIT" --output-on-failure
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -G Ninja
|
||||
|
||||
- name: Build LuaJIT (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTestsLuaJIT \
|
||||
LuaBridgeTestsLuaJITNoexcept
|
||||
|
||||
- name: Test LuaJIT (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuaJIT" --output-on-failure
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -G Ninja
|
||||
|
||||
- name: Build LuaJIT (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTestsLuaJIT \
|
||||
LuaBridgeTestsLuaJITNoexcept
|
||||
|
||||
- name: Test LuaJIT (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuaJIT" --output-on-failure
|
||||
|
||||
luau:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get -y install ninja-build
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -G Ninja
|
||||
|
||||
- name: Build Luau (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau
|
||||
|
||||
- name: Test Luau (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuau" --output-on-failure
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -G Ninja
|
||||
|
||||
- name: Build Luau (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau
|
||||
|
||||
- name: Test Luau (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuau" --output-on-failure
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -G Ninja
|
||||
|
||||
- name: Build Luau (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau
|
||||
|
||||
- name: Test Luau (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuau" --output-on-failure
|
||||
|
||||
ravi:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get -y install libreadline-dev ninja-build
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -G Ninja
|
||||
|
||||
- name: Build Ravi (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi
|
||||
|
||||
- name: Test Ravi (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsRavi" --output-on-failure
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -G Ninja
|
||||
|
||||
- name: Build Ravi (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi
|
||||
|
||||
- name: Test Ravi (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsRavi" --output-on-failure
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -G Ninja
|
||||
|
||||
- name: Build Ravi (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi
|
||||
|
||||
- name: Test Ravi (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsRavi" --output-on-failure
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
name: macOS
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "**/workflows/build_macos.yml"
|
||||
- "**/Source/**"
|
||||
- "**/Tests/**"
|
||||
- "**/ThirdParty/**"
|
||||
- "**/CMakeLists.txt"
|
||||
- "**/.gitmodules"
|
||||
- "!**/*.md"
|
||||
- "!**/*.txt"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
lua:
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
lua:
|
||||
- { version: "5.1", suffix: "51" }
|
||||
- { version: "5.2", suffix: "52" }
|
||||
- { version: "5.3", suffix: "53" }
|
||||
- { version: "5.4", suffix: "54" }
|
||||
- { version: "5.5", suffix: "55" }
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
luajit:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -G Ninja
|
||||
|
||||
- name: Build LuaJIT (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTestsLuaJIT \
|
||||
LuaBridgeTestsLuaJITNoexcept
|
||||
|
||||
- name: Test LuaJIT (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuaJIT" --output-on-failure
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -G Ninja
|
||||
|
||||
- name: Build LuaJIT (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTestsLuaJIT \
|
||||
LuaBridgeTestsLuaJITNoexcept
|
||||
|
||||
- name: Test LuaJIT (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuaJIT" --output-on-failure
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -G Ninja
|
||||
|
||||
- name: Build LuaJIT (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTestsLuaJIT \
|
||||
LuaBridgeTestsLuaJITNoexcept
|
||||
|
||||
- name: Test LuaJIT (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuaJIT" --output-on-failure
|
||||
|
||||
luau:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -G Ninja
|
||||
|
||||
- name: Build Luau (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau
|
||||
|
||||
- name: Test Luau (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuau" --output-on-failure
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -G Ninja
|
||||
|
||||
- name: Build Luau (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau
|
||||
|
||||
- name: Test Luau (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuau" --output-on-failure
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -G Ninja
|
||||
|
||||
- name: Build Luau (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau
|
||||
|
||||
- name: Test Luau (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuau" --output-on-failure
|
||||
|
||||
ravi:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -G Ninja
|
||||
|
||||
- name: Build Ravi (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi
|
||||
|
||||
- name: Test Ravi (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsRavi" --output-on-failure
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -G Ninja
|
||||
|
||||
- name: Build Ravi (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi
|
||||
|
||||
- name: Test Ravi (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsRavi" --output-on-failure
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -G Ninja
|
||||
|
||||
- name: Build Ravi (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi
|
||||
|
||||
- name: Test Ravi (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsRavi" --output-on-failure
|
||||
@@ -0,0 +1,68 @@
|
||||
name: TSAN
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "**/workflows/build_tsan.yml"
|
||||
- "**/Source/**"
|
||||
- "**/Tests/**"
|
||||
- "**/ThirdParty/**"
|
||||
- "**/CMakeLists.txt"
|
||||
- "**/.gitmodules"
|
||||
- "!**/*.md"
|
||||
- "!**/*.txt"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BUILD_TYPE: RelWithDebInfo
|
||||
|
||||
jobs:
|
||||
lua:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
lua:
|
||||
- { version: "5.1", suffix: "51" }
|
||||
- { version: "5.2", suffix: "52" }
|
||||
- { version: "5.3", suffix: "53" }
|
||||
- { version: "5.4", suffix: "54" }
|
||||
- { version: "5.5", suffix: "55" }
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get -y install ninja-build
|
||||
|
||||
- name: Create Build Environment
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
|
||||
- name: Configure
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DLUABRIDGE_SANITIZE=thread -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }}
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }}
|
||||
working-directory: ${{runner.workspace}}/build/Tests
|
||||
env:
|
||||
TSAN_OPTIONS: halt_on_error=1:print_stacktrace=1
|
||||
run: |
|
||||
./LuaBridgeTests${{ matrix.lua.suffix }}
|
||||
./LuaBridgeTests${{ matrix.lua.suffix }}LuaC
|
||||
./LuaBridgeTests${{ matrix.lua.suffix }}Noexcept
|
||||
./LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
name: UBSAN
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "**/workflows/build_ubsan.yml"
|
||||
- "**/Source/**"
|
||||
- "**/Tests/**"
|
||||
- "**/ThirdParty/**"
|
||||
- "**/CMakeLists.txt"
|
||||
- "**/.gitmodules"
|
||||
- "!**/*.md"
|
||||
- "!**/*.txt"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BUILD_TYPE: RelWithDebInfo
|
||||
|
||||
jobs:
|
||||
lua:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
lua:
|
||||
- { version: "5.1", suffix: "51" }
|
||||
- { version: "5.2", suffix: "52" }
|
||||
- { version: "5.3", suffix: "53" }
|
||||
- { version: "5.4", suffix: "54" }
|
||||
- { version: "5.5", suffix: "55" }
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get -y install ninja-build
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -DLUABRIDGE_SANITIZE=undefined -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
env:
|
||||
UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -DLUABRIDGE_SANITIZE=undefined -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
env:
|
||||
UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -DLUABRIDGE_SANITIZE=undefined -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
env:
|
||||
UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
@@ -0,0 +1,297 @@
|
||||
name: Windows
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "**/workflows/build_windows.yml"
|
||||
- "**/Source/**"
|
||||
- "**/Tests/**"
|
||||
- "**/ThirdParty/**"
|
||||
- "**/CMakeLists.txt"
|
||||
- "**/.gitmodules"
|
||||
- "!**/*.md"
|
||||
- "!**/*.txt"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
lua:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
lua:
|
||||
- { version: "5.1", suffix: "51" }
|
||||
- { version: "5.2", suffix: "52" }
|
||||
- { version: "5.3", suffix: "53" }
|
||||
- { version: "5.4", suffix: "54" }
|
||||
- { version: "5.5", suffix: "55" }
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
shell: bash
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel 4 --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
shell: bash
|
||||
run: ctest --parallel 4 -C $BUILD_TYPE -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
- name: Configure C++20
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
shell: bash
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel 4 --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
shell: bash
|
||||
run: ctest --parallel 4 -C $BUILD_TYPE -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
- name: Configure C++23
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
shell: bash
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel 4 --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
shell: bash
|
||||
run: ctest --parallel 4 -C $BUILD_TYPE -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
luajit:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17
|
||||
|
||||
- name: Build LuaJIT (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
shell: bash
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel 4 --target \
|
||||
LuaBridgeTestsLuaJIT \
|
||||
LuaBridgeTestsLuaJITNoexcept
|
||||
|
||||
- name: Test LuaJIT (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
shell: bash
|
||||
run: ctest --parallel 4 -C $BUILD_TYPE -R "LuaBridgeTestsLuaJIT" --output-on-failure
|
||||
|
||||
- name: Configure C++20
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20
|
||||
|
||||
- name: Build LuaJIT (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
shell: bash
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel 4 --target \
|
||||
LuaBridgeTestsLuaJIT \
|
||||
LuaBridgeTestsLuaJITNoexcept
|
||||
|
||||
- name: Test LuaJIT (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
shell: bash
|
||||
run: ctest --parallel 4 -C $BUILD_TYPE -R "LuaBridgeTestsLuaJIT" --output-on-failure
|
||||
|
||||
- name: Configure C++23
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23
|
||||
|
||||
- name: Build LuaJIT (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
shell: bash
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel 4 --target \
|
||||
LuaBridgeTestsLuaJIT \
|
||||
LuaBridgeTestsLuaJITNoexcept
|
||||
|
||||
- name: Test LuaJIT (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
shell: bash
|
||||
run: ctest --parallel 4 -C $BUILD_TYPE -R "LuaBridgeTestsLuaJIT" --output-on-failure
|
||||
|
||||
luau:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17
|
||||
|
||||
- name: Build Luau (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel 4 --target LuaBridgeTestsLuau
|
||||
|
||||
- name: Test Luau (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
shell: bash
|
||||
run: ctest --parallel 4 -C $BUILD_TYPE -R "LuaBridgeTestsLuau" --output-on-failure
|
||||
|
||||
- name: Configure C++20
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20
|
||||
|
||||
- name: Build Luau (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel 4 --target LuaBridgeTestsLuau
|
||||
|
||||
- name: Test Luau (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
shell: bash
|
||||
run: ctest --parallel 4 -C $BUILD_TYPE -R "LuaBridgeTestsLuau" --output-on-failure
|
||||
|
||||
- name: Configure C++23
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23
|
||||
|
||||
- name: Build Luau (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel 4 --target LuaBridgeTestsLuau
|
||||
|
||||
- name: Test Luau (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
shell: bash
|
||||
run: ctest --parallel 4 -C $BUILD_TYPE -R "LuaBridgeTestsLuau" --output-on-failure
|
||||
|
||||
ravi:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
|
||||
- name: Configure C++17
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17
|
||||
|
||||
- name: Build Ravi (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel 4 --target LuaBridgeTestsRavi
|
||||
|
||||
- name: Test Ravi (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17/Tests/Release
|
||||
shell: bash
|
||||
run: |
|
||||
cp ../ravi/Release/libravi.dll .
|
||||
./LuaBridgeTestsRavi.exe
|
||||
|
||||
- name: Configure C++20
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20
|
||||
|
||||
- name: Build Ravi (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel 4 --target LuaBridgeTestsRavi
|
||||
|
||||
- name: Test Ravi (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20/Tests/Release
|
||||
shell: bash
|
||||
run: |
|
||||
cp ../ravi/Release/libravi.dll .
|
||||
./LuaBridgeTestsRavi.exe
|
||||
|
||||
- name: Configure C++23
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23
|
||||
|
||||
- name: Build Ravi (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel 4 --target LuaBridgeTestsRavi
|
||||
|
||||
- name: Test Ravi (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23/Tests/Release
|
||||
shell: bash
|
||||
run: |
|
||||
cp ../ravi/Release/libravi.dll .
|
||||
./LuaBridgeTestsRavi.exe
|
||||
@@ -0,0 +1,65 @@
|
||||
name: CodeQL
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths:
|
||||
- "**/workflows/codeql-analysis.yml"
|
||||
- "**/Source/**"
|
||||
- "**/Tests/**"
|
||||
- "**/ThirdParty/**"
|
||||
- "**/CMakeLists.txt"
|
||||
- "**/.gitmodules"
|
||||
- "**/.codeql.yml"
|
||||
- "!**/*.md"
|
||||
- "!**/*.txt"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp' ]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install Ninja
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install ninja-build libreadline-dev
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
config-file: ./.codeql.yml
|
||||
|
||||
- name: Create Build Environment
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
|
||||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc)
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
+512
@@ -0,0 +1,512 @@
|
||||
name: Coverage
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "**/workflows/coverage.yml"
|
||||
- "**/Source/**"
|
||||
- "**/Tests/**"
|
||||
- "**/ThirdParty/**"
|
||||
- "**/CMakeLists.txt"
|
||||
- "**/.gitmodules"
|
||||
- "!**/*.md"
|
||||
- "!**/*.txt"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Debug
|
||||
|
||||
jobs:
|
||||
lua:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
lua:
|
||||
- { version: "5.1", suffix: "51" }
|
||||
- { version: "5.2", suffix: "52" }
|
||||
- { version: "5.3", suffix: "53" }
|
||||
- { version: "5.4", suffix: "54" }
|
||||
- { version: "5.5", suffix: "55" }
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install lcov
|
||||
run: sudo apt-get install -y lcov ninja-build
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
cmake -E make_directory ${{runner.workspace}}/coverage
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -DLUABRIDGE_COVERAGE=ON -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
- name: Coverage Lua ${{ matrix.lua.version }} (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: |
|
||||
lcov -c -d "${{runner.workspace}}/build17" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \
|
||||
--ignore-errors mismatch,unused \
|
||||
--include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \
|
||||
-o "${{runner.workspace}}/coverage/lua${{ matrix.lua.suffix }}_cxx17.info"
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -DLUABRIDGE_COVERAGE=ON -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
- name: Coverage Lua ${{ matrix.lua.version }} (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: |
|
||||
lcov -c -d "${{runner.workspace}}/build20" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \
|
||||
--ignore-errors mismatch,unused \
|
||||
--include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \
|
||||
-o "${{runner.workspace}}/coverage/lua${{ matrix.lua.suffix }}_cxx20.info"
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -DLUABRIDGE_COVERAGE=ON -G Ninja
|
||||
|
||||
- name: Build Lua ${{ matrix.lua.version }} (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }} \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaC \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \
|
||||
LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept
|
||||
|
||||
- name: Test Lua ${{ matrix.lua.version }} (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure
|
||||
|
||||
- name: Coverage Lua ${{ matrix.lua.version }} (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: |
|
||||
lcov -c -d "${{runner.workspace}}/build23" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \
|
||||
--ignore-errors mismatch,unused \
|
||||
--include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \
|
||||
-o "${{runner.workspace}}/coverage/lua${{ matrix.lua.suffix }}_cxx23.info"
|
||||
|
||||
- name: Cache Lcov Files
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: "${{runner.workspace}}/coverage/*.info"
|
||||
key: lcov-lua${{ matrix.lua.suffix }}-${{runner.os}}-${{github.sha}}
|
||||
|
||||
luajit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install lcov
|
||||
run: sudo apt-get install -y lcov ninja-build
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
cmake -E make_directory ${{runner.workspace}}/coverage
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -DLUABRIDGE_COVERAGE=ON -G Ninja
|
||||
|
||||
- name: Build LuaJIT (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTestsLuaJIT \
|
||||
LuaBridgeTestsLuaJITNoexcept
|
||||
|
||||
- name: Test LuaJIT (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuaJIT" --output-on-failure
|
||||
|
||||
- name: Coverage LuaJIT (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: |
|
||||
lcov -c -d "${{runner.workspace}}/build17" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \
|
||||
--ignore-errors mismatch,unused \
|
||||
--include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \
|
||||
-o "${{runner.workspace}}/coverage/luajit_cxx17.info"
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -DLUABRIDGE_COVERAGE=ON -G Ninja
|
||||
|
||||
- name: Build LuaJIT (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTestsLuaJIT \
|
||||
LuaBridgeTestsLuaJITNoexcept
|
||||
|
||||
- name: Test LuaJIT (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuaJIT" --output-on-failure
|
||||
|
||||
- name: Coverage LuaJIT (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: |
|
||||
lcov -c -d "${{runner.workspace}}/build20" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \
|
||||
--ignore-errors mismatch,unused \
|
||||
--include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \
|
||||
-o "${{runner.workspace}}/coverage/luajit_cxx20.info"
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -DLUABRIDGE_COVERAGE=ON -G Ninja
|
||||
|
||||
- name: Build LuaJIT (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: |
|
||||
cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \
|
||||
LuaBridgeTestsLuaJIT \
|
||||
LuaBridgeTestsLuaJITNoexcept
|
||||
|
||||
- name: Test LuaJIT (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuaJIT" --output-on-failure
|
||||
|
||||
- name: Coverage LuaJIT (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: |
|
||||
lcov -c -d "${{runner.workspace}}/build23" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \
|
||||
--ignore-errors mismatch,unused \
|
||||
--include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \
|
||||
-o "${{runner.workspace}}/coverage/luajit_cxx23.info"
|
||||
|
||||
- name: Cache Lcov Files
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: "${{runner.workspace}}/coverage/*.info"
|
||||
key: lcov-luajit-${{runner.os}}-${{github.sha}}
|
||||
|
||||
luau:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install lcov
|
||||
run: sudo apt-get install -y lcov ninja-build
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
cmake -E make_directory ${{runner.workspace}}/coverage
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -DLUABRIDGE_COVERAGE=ON -G Ninja
|
||||
|
||||
- name: Build Luau (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau
|
||||
|
||||
- name: Test Luau (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuau" --output-on-failure
|
||||
|
||||
- name: Coverage Luau (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: |
|
||||
lcov -c -d "${{runner.workspace}}/build17" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \
|
||||
--ignore-errors mismatch,unused \
|
||||
--include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \
|
||||
-o "${{runner.workspace}}/coverage/luau_cxx17.info"
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -DLUABRIDGE_COVERAGE=ON -G Ninja
|
||||
|
||||
- name: Build Luau (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau
|
||||
|
||||
- name: Test Luau (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuau" --output-on-failure
|
||||
|
||||
- name: Coverage Luau (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: |
|
||||
lcov -c -d "${{runner.workspace}}/build20" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \
|
||||
--ignore-errors mismatch,unused \
|
||||
--include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \
|
||||
-o "${{runner.workspace}}/coverage/luau_cxx20.info"
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -DLUABRIDGE_COVERAGE=ON -G Ninja
|
||||
|
||||
- name: Build Luau (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau
|
||||
|
||||
- name: Test Luau (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuau" --output-on-failure
|
||||
|
||||
- name: Coverage Luau (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: |
|
||||
lcov -c -d "${{runner.workspace}}/build23" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \
|
||||
--ignore-errors mismatch,unused \
|
||||
--include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \
|
||||
-o "${{runner.workspace}}/coverage/luau_cxx23.info"
|
||||
|
||||
- name: Cache Lcov Files
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: "${{runner.workspace}}/coverage/*.info"
|
||||
key: lcov-luau-${{runner.os}}-${{github.sha}}
|
||||
|
||||
ravi:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install lcov
|
||||
run: sudo apt-get install -y lcov libreadline-dev ninja-build
|
||||
|
||||
- name: Create Build Environments
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build17
|
||||
cmake -E make_directory ${{runner.workspace}}/build20
|
||||
cmake -E make_directory ${{runner.workspace}}/build23
|
||||
cmake -E make_directory ${{runner.workspace}}/coverage
|
||||
|
||||
- name: Configure C++17
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=17 -DLUABRIDGE_COVERAGE=ON -G Ninja
|
||||
|
||||
- name: Build Ravi (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi
|
||||
|
||||
- name: Test Ravi (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17/Tests
|
||||
run: LD_PRELOAD=$(gcc -print-file-name=libasan.so) ./LuaBridgeTestsRavi
|
||||
|
||||
- name: Coverage Ravi (C++17)
|
||||
working-directory: ${{runner.workspace}}/build17
|
||||
run: |
|
||||
lcov -c -d "${{runner.workspace}}/build17" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \
|
||||
--ignore-errors mismatch,unused \
|
||||
--include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \
|
||||
-o "${{runner.workspace}}/coverage/ravi_cxx17.info"
|
||||
|
||||
- name: Configure C++20
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=20 -DLUABRIDGE_COVERAGE=ON -G Ninja
|
||||
|
||||
- name: Build Ravi (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi
|
||||
|
||||
- name: Test Ravi (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20/Tests
|
||||
run: LD_PRELOAD=$(gcc -print-file-name=libasan.so) ./LuaBridgeTestsRavi
|
||||
|
||||
- name: Coverage Ravi (C++20)
|
||||
working-directory: ${{runner.workspace}}/build20
|
||||
run: |
|
||||
lcov -c -d "${{runner.workspace}}/build20" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \
|
||||
--ignore-errors mismatch,unused \
|
||||
--include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \
|
||||
-o "${{runner.workspace}}/coverage/ravi_cxx20.info"
|
||||
|
||||
- name: Configure C++23
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=23 -DLUABRIDGE_COVERAGE=ON -G Ninja
|
||||
|
||||
- name: Build Ravi (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi
|
||||
|
||||
- name: Test Ravi (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23/Tests
|
||||
run: LD_PRELOAD=$(gcc -print-file-name=libasan.so) ./LuaBridgeTestsRavi
|
||||
|
||||
- name: Coverage Ravi (C++23)
|
||||
working-directory: ${{runner.workspace}}/build23
|
||||
run: |
|
||||
lcov -c -d "${{runner.workspace}}/build23" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \
|
||||
--ignore-errors mismatch,unused \
|
||||
--include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \
|
||||
-o "${{runner.workspace}}/coverage/ravi_cxx23.info"
|
||||
|
||||
- name: Cache Lcov Files
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: "${{runner.workspace}}/coverage/*.info"
|
||||
key: lcov-ravi-${{runner.os}}-${{github.sha}}
|
||||
|
||||
coveralls:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lua, luajit, luau, ravi]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install lcov
|
||||
run: sudo apt-get install -y lcov
|
||||
|
||||
- name: Create Coverage Directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/coverage
|
||||
|
||||
- name: Restore Lcov Files Lua 5.1
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: "${{runner.workspace}}/coverage/*.info"
|
||||
key: lcov-lua51-${{runner.os}}-${{github.sha}}
|
||||
|
||||
- name: Restore Lcov Files Lua 5.2
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: "${{runner.workspace}}/coverage/*.info"
|
||||
key: lcov-lua52-${{runner.os}}-${{github.sha}}
|
||||
|
||||
- name: Restore Lcov Files Lua 5.3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: "${{runner.workspace}}/coverage/*.info"
|
||||
key: lcov-lua53-${{runner.os}}-${{github.sha}}
|
||||
|
||||
- name: Restore Lcov Files Lua 5.4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: "${{runner.workspace}}/coverage/*.info"
|
||||
key: lcov-lua54-${{runner.os}}-${{github.sha}}
|
||||
|
||||
- name: Restore Lcov Files Lua 5.5
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: "${{runner.workspace}}/coverage/*.info"
|
||||
key: lcov-lua55-${{runner.os}}-${{github.sha}}
|
||||
|
||||
- name: Restore Lcov Files LuaJIT
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: "${{runner.workspace}}/coverage/*.info"
|
||||
key: lcov-luajit-${{runner.os}}-${{github.sha}}
|
||||
|
||||
- name: Restore Lcov Files Luau
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: "${{runner.workspace}}/coverage/*.info"
|
||||
key: lcov-luau-${{runner.os}}-${{github.sha}}
|
||||
|
||||
- name: Restore Lcov Files Ravi
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: "${{runner.workspace}}/coverage/*.info"
|
||||
key: lcov-ravi-${{runner.os}}-${{github.sha}}
|
||||
|
||||
- name: Merge Lcov Files
|
||||
working-directory: ${{runner.workspace}}/coverage
|
||||
run: |
|
||||
lcov \
|
||||
-a "lua51_cxx17.info" \
|
||||
-a "lua51_cxx20.info" \
|
||||
-a "lua51_cxx23.info" \
|
||||
-a "lua52_cxx17.info" \
|
||||
-a "lua52_cxx20.info" \
|
||||
-a "lua52_cxx23.info" \
|
||||
-a "lua53_cxx17.info" \
|
||||
-a "lua53_cxx20.info" \
|
||||
-a "lua53_cxx23.info" \
|
||||
-a "lua54_cxx17.info" \
|
||||
-a "lua54_cxx20.info" \
|
||||
-a "lua54_cxx23.info" \
|
||||
-a "lua55_cxx17.info" \
|
||||
-a "lua55_cxx20.info" \
|
||||
-a "lua55_cxx23.info" \
|
||||
-a "luajit_cxx17.info" \
|
||||
-a "luajit_cxx20.info" \
|
||||
-a "luajit_cxx23.info" \
|
||||
-a "luau_cxx17.info" \
|
||||
-a "luau_cxx20.info" \
|
||||
-a "luau_cxx23.info" \
|
||||
-a "ravi_cxx17.info" \
|
||||
-a "ravi_cxx20.info" \
|
||||
-a "ravi_cxx23.info" \
|
||||
-o "merged.info"
|
||||
|
||||
- name: Install lcov2xml
|
||||
run: cargo install lcov2xml
|
||||
|
||||
- name: Convert to Cobertura XML
|
||||
working-directory: ${{runner.workspace}}/coverage
|
||||
run: lcov2xml merged.info -o cobertura.xml
|
||||
|
||||
#- name: Convert to Coverage TXT
|
||||
# working-directory: ${{runner.workspace}}/build
|
||||
# run: python3 ${{runner.workspace}}/cobertura.py coverage/cobertura.info coverage/coverage.txt
|
||||
|
||||
- name: Upload Cobertura XML
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cobertura-coverage
|
||||
path: ${{runner.workspace}}/coverage/cobertura.xml
|
||||
|
||||
#- name: Upload Coverage TXT
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: text-coverage
|
||||
# path: ${{runner.workspace}}/build/coverage/coverage.txt
|
||||
|
||||
- name: Coveralls
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
path-to-lcov: ${{runner.workspace}}/coverage/merged.info
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
name: Sonar
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "**/workflows/sonar.yml"
|
||||
- "**/Source/**"
|
||||
- "**/Tests/**"
|
||||
- "**/ThirdParty/**"
|
||||
- "**/CMakeLists.txt"
|
||||
- "**/.gitmodules"
|
||||
- "**/sonar-project.properties"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and Analyze
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
|
||||
- name: Install sonar-scanner and build-wrapper
|
||||
uses: SonarSource/sonarcloud-github-c-cpp@v2
|
||||
|
||||
- name: Create Build Environment
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
|
||||
- name: Configure
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja
|
||||
|
||||
- name: Run build-wrapper
|
||||
run: |
|
||||
build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build ${{runner.workspace}}/build --config $BUILD_TYPE
|
||||
|
||||
- name: Run sonar-scanner
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
run: |
|
||||
sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}"
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
Documentation
|
||||
*.swp
|
||||
Makefile
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
build*/
|
||||
Build*/
|
||||
*.dir/
|
||||
*.sln
|
||||
*.vcxproj
|
||||
*.vcxproj.filters
|
||||
*.vcxproj.user
|
||||
.vs/
|
||||
.vscode/
|
||||
.idea/
|
||||
.gitnexus/
|
||||
.DS_Store
|
||||
cmake-build-*/
|
||||
tmpunwind.o
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
[submodule "ThirdParty/luau"]
|
||||
path = ThirdParty/luau
|
||||
url = https://github.com/Roblox/luau.git
|
||||
[submodule "ThirdParty/googletest"]
|
||||
path = ThirdParty/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
[submodule "ThirdParty/ravi"]
|
||||
path = ThirdParty/ravi
|
||||
url = https://github.com/dibyendumajumdar/ravi.git
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
cmake_policy (SET CMP0169 OLD)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
set(LUABRIDGE_BENCHMARK_WITH_SOL3 ON CACHE BOOL "Build Sol3 benchmark target")
|
||||
set(LUABRIDGE_SOL2_GIT_REPOSITORY "https://github.com/ThePhD/sol2.git" CACHE STRING "sol2 repository URL")
|
||||
set(LUABRIDGE_SOL2_GIT_TAG "v3.3.0" CACHE STRING "sol2 git tag or commit")
|
||||
|
||||
set(LUABRIDGE_BENCHMARK_WITH_LUABRIDGE ON CACHE BOOL "Build LuaBridge benchmark target")
|
||||
set(LUABRIDGE_VANILLA_GIT_REPOSITORY "https://github.com/vinniefalco/LuaBridge.git" CACHE STRING "LuaBridge vanilla repository URL")
|
||||
set(LUABRIDGE_VANILLA_GIT_TAG "master" CACHE STRING "LuaBridge vanilla git tag or commit")
|
||||
|
||||
set(LUABRIDGE_GOOGLE_BENCHMARK_GIT_REPOSITORY "https://github.com/google/benchmark.git" CACHE STRING "Google Benchmark repository URL")
|
||||
set(LUABRIDGE_GOOGLE_BENCHMARK_GIT_TAG "v1.8.4" CACHE STRING "Google Benchmark git tag or commit")
|
||||
|
||||
set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE)
|
||||
set(BENCHMARK_ENABLE_INSTALL OFF CACHE BOOL "" FORCE)
|
||||
FetchContent_Declare(
|
||||
googlebenchmark
|
||||
GIT_REPOSITORY ${LUABRIDGE_GOOGLE_BENCHMARK_GIT_REPOSITORY}
|
||||
GIT_TAG ${LUABRIDGE_GOOGLE_BENCHMARK_GIT_TAG})
|
||||
FetchContent_MakeAvailable(googlebenchmark)
|
||||
|
||||
if (LUABRIDGE_BENCHMARK_WITH_SOL3)
|
||||
FetchContent_Declare(
|
||||
sol2
|
||||
GIT_REPOSITORY ${LUABRIDGE_SOL2_GIT_REPOSITORY}
|
||||
GIT_TAG ${LUABRIDGE_SOL2_GIT_TAG})
|
||||
FetchContent_GetProperties(sol2)
|
||||
if (NOT sol2_POPULATED)
|
||||
FetchContent_Populate(sol2)
|
||||
endif()
|
||||
|
||||
# Work around a sol2 optional<T&>::emplace bug on recent Apple Clang toolchains.
|
||||
set(SOL2_OPTIONAL_IMPL "${sol2_SOURCE_DIR}/include/sol/optional_implementation.hpp")
|
||||
if (EXISTS "${SOL2_OPTIONAL_IMPL}")
|
||||
file(READ "${SOL2_OPTIONAL_IMPL}" SOL2_OPTIONAL_IMPL_CONTENT)
|
||||
set(SOL2_OPTIONAL_REFBLOCK_OLD "\t\ttemplate <class... Args>\n\t\tT& emplace(Args&&... args) noexcept {\n\t\t\tstatic_assert(std::is_constructible<T, Args&&...>::value, \"T must be constructible with Args\");\n\n\t\t\t*this = nullopt;\n\t\t\tthis->construct(std::forward<Args>(args)...);\n\t\t}\n")
|
||||
string(FIND "${SOL2_OPTIONAL_IMPL_CONTENT}" "${SOL2_OPTIONAL_REFBLOCK_OLD}" SOL2_PATCH_NEEDLE_POS)
|
||||
if (NOT SOL2_PATCH_NEEDLE_POS EQUAL -1)
|
||||
set(SOL2_OPTIONAL_REFBLOCK_NEW "\t\ttemplate <class... Args>\n\t\tT& emplace(Args&&... args) noexcept {\n\t\t\tstatic_assert(std::is_constructible<T, Args&&...>::value, \"T must be constructible with Args\");\n\n\t\t\t*this = nullopt;\n\t\t\tint emplace_workaround[] = { 0, ((*this = std::forward<Args>(args)), 0)... };\n\t\t\t(void) emplace_workaround;\n\t\t\treturn *m_value;\n\t\t}\n")
|
||||
string(REPLACE
|
||||
"${SOL2_OPTIONAL_REFBLOCK_OLD}"
|
||||
"${SOL2_OPTIONAL_REFBLOCK_NEW}"
|
||||
SOL2_OPTIONAL_IMPL_CONTENT
|
||||
"${SOL2_OPTIONAL_IMPL_CONTENT}")
|
||||
file(WRITE "${SOL2_OPTIONAL_IMPL}" "${SOL2_OPTIONAL_IMPL_CONTENT}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (LUABRIDGE_BENCHMARK_WITH_LUABRIDGE)
|
||||
FetchContent_Declare(
|
||||
luabridge_vanilla
|
||||
GIT_REPOSITORY ${LUABRIDGE_VANILLA_GIT_REPOSITORY}
|
||||
GIT_TAG ${LUABRIDGE_VANILLA_GIT_TAG})
|
||||
FetchContent_GetProperties(luabridge_vanilla)
|
||||
if (NOT luabridge_vanilla_POPULATED)
|
||||
FetchContent_Populate(luabridge_vanilla)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(add_luabridge_benchmark_target target_name source_file)
|
||||
add_executable(${target_name}
|
||||
${source_file}
|
||||
benchmark_common.cpp
|
||||
../Tests/Lua/LuaLibrary5.4.8.cpp)
|
||||
|
||||
target_include_directories(${target_name} PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/..
|
||||
${CMAKE_CURRENT_LIST_DIR}/../Tests
|
||||
${CMAKE_CURRENT_LIST_DIR}/../Tests/Lua/Lua.5.4.8/src)
|
||||
|
||||
target_compile_definitions(${target_name} PRIVATE
|
||||
LUABRIDGE_BENCHMARK_LUA54=1
|
||||
LUABRIDGE_TEST_LUA_VERSION=504)
|
||||
|
||||
target_link_libraries(${target_name} PRIVATE
|
||||
benchmark::benchmark
|
||||
benchmark::benchmark_main)
|
||||
endfunction()
|
||||
|
||||
add_luabridge_benchmark_target(LuaBridge3Benchmark benchmark_luabridge3.cpp)
|
||||
target_include_directories(LuaBridge3Benchmark PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/../Source)
|
||||
|
||||
if (LUABRIDGE_BENCHMARK_WITH_LUABRIDGE)
|
||||
add_luabridge_benchmark_target(LuaBridgeVanillaBenchmark benchmark_luabridge.cpp)
|
||||
target_include_directories(LuaBridgeVanillaBenchmark PRIVATE
|
||||
${luabridge_vanilla_SOURCE_DIR}/Source)
|
||||
endif()
|
||||
|
||||
if (LUABRIDGE_BENCHMARK_WITH_SOL3)
|
||||
add_luabridge_benchmark_target(Sol3Benchmark benchmark_sol3.cpp)
|
||||
target_include_directories(Sol3Benchmark PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/../Source
|
||||
${sol2_SOURCE_DIR}/include)
|
||||
|
||||
target_compile_definitions(Sol3Benchmark PRIVATE
|
||||
SOL_ALL_SAFETIES_ON=1
|
||||
SOL_NO_EXCEPTIONS=1
|
||||
SOL_LUA_VERSION=504)
|
||||
endif()
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
# Lua Binding Benchmarks
|
||||
|
||||
This directory contains Google Benchmark based executables for:
|
||||
|
||||
- LuaBridge3 (current workspace)
|
||||
- LuaBridge vanilla (`https://github.com/vinniefalco/LuaBridge`)
|
||||
- sol3 (`https://github.com/ThePhD/sol2`)
|
||||
|
||||
All benchmark executables are built with the same embedded Lua 5.4.8 runtime source (`Tests/Lua/LuaLibrary5.4.8.cpp`) for fair comparisons.
|
||||
|
||||
## Build
|
||||
|
||||
From project root:
|
||||
|
||||
```bash
|
||||
cmake -S . -B Build -DCMAKE_BUILD_TYPE=Release -DLUABRIDGE_BENCHMARKS=ON
|
||||
cmake --build Build --config Release --target LuaBridge3Benchmark LuaBridgeVanillaBenchmark
|
||||
```
|
||||
|
||||
To also build Sol3 benchmark target:
|
||||
|
||||
```bash
|
||||
cmake -S . -B Build -DCMAKE_BUILD_TYPE=Release -DLUABRIDGE_BENCHMARKS=ON -DLUABRIDGE_BENCHMARK_WITH_SOL3=ON
|
||||
cmake --build Build --config Release --target Sol3Benchmark
|
||||
```
|
||||
|
||||
## Dependency Sources (FetchContent)
|
||||
|
||||
Defaults:
|
||||
|
||||
- Google Benchmark: `https://github.com/google/benchmark.git` (`v1.8.4`)
|
||||
- sol3: `https://github.com/ThePhD/sol2.git` (`v3.5.0`)
|
||||
- LuaBridge vanilla: `https://github.com/vinniefalco/LuaBridge.git` (`master`)
|
||||
|
||||
You can override these at configure time:
|
||||
|
||||
```bash
|
||||
cmake -S . -B Build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLUABRIDGE_BENCHMARKS=ON \
|
||||
-DLUABRIDGE_SOL2_GIT_REPOSITORY=https://github.com/ThePhD/sol2.git \
|
||||
-DLUABRIDGE_SOL2_GIT_TAG=v3.5.0 \
|
||||
-DLUABRIDGE_VANILLA_GIT_REPOSITORY=https://github.com/vinniefalco/LuaBridge.git \
|
||||
-DLUABRIDGE_VANILLA_GIT_TAG=master \
|
||||
-DLUABRIDGE_GOOGLE_BENCHMARK_GIT_REPOSITORY=https://github.com/google/benchmark.git \
|
||||
-DLUABRIDGE_GOOGLE_BENCHMARK_GIT_TAG=v1.8.4
|
||||
```
|
||||
|
||||
## Run Benchmarks
|
||||
|
||||
Each executable supports standard Google Benchmark CLI flags.
|
||||
|
||||
```bash
|
||||
./Build/Benchmarks/LuaBridge3Benchmark --benchmark_out=Build/Benchmarks/luabridge3.json --benchmark_out_format=json
|
||||
./Build/Benchmarks/LuaBridgeVanillaBenchmark --benchmark_out=Build/Benchmarks/luabridge_vanilla.json --benchmark_out_format=json
|
||||
./Build/Benchmarks/Sol3Benchmark --benchmark_out=Build/Benchmarks/sol3.json --benchmark_out_format=json # if enabled
|
||||
```
|
||||
|
||||
Recommended consistency flags for fair comparison:
|
||||
|
||||
```bash
|
||||
--benchmark_min_time=0.1 --benchmark_repetitions=5
|
||||
```
|
||||
|
||||
## Plot Results
|
||||
|
||||
The script `plot_benchmarks.py` merges one or more Google Benchmark JSON files and generates a grouped comparison chart.
|
||||
|
||||
```bash
|
||||
python3 Benchmarks/plot_benchmarks.py \
|
||||
--input Build/Benchmarks/luabridge3.json Build/Benchmarks/luabridge_vanilla.json Build/Benchmarks/sol3.json \
|
||||
--output Build/Benchmarks/lua_bindings_comparison.png
|
||||
```
|
||||
|
||||
Outputs:
|
||||
|
||||
- PNG chart (grouped bars, lower is better)
|
||||
- Optional skipped/error report file next to the image (`*_skipped.txt`)
|
||||
|
||||
## Notes
|
||||
|
||||
- Some vanilla LuaBridge benchmarks are marked as skipped where the feature is unsupported.
|
||||
- Sol3 target is optional (`LUABRIDGE_BENCHMARK_WITH_SOL3`) because current sol2 headers can fail to compile on some toolchains.
|
||||
- If you need stricter reproducibility, pin all FetchContent dependencies to commits instead of branches.
|
||||
@@ -0,0 +1,31 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// Inspired from https://github.com/ThePhD/lua-bindings-shootout by ThePhD
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "benchmark_common.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace lbsbench {
|
||||
|
||||
void luaCheckOrThrow(lua_State* L, int status, std::string_view where)
|
||||
{
|
||||
if (status == LUA_OK)
|
||||
return;
|
||||
|
||||
const char* message = lua_tostring(L, -1);
|
||||
std::string error(where);
|
||||
error += ": ";
|
||||
error += (message ? message : "unknown lua error");
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
|
||||
void luaDoStringOrThrow(lua_State* L, std::string_view code, std::string_view where)
|
||||
{
|
||||
const int status = luaL_dostring(L, std::string(code).c_str());
|
||||
luaCheckOrThrow(L, status, where);
|
||||
}
|
||||
|
||||
} // namespace lbsbench
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// Inspired from https://github.com/ThePhD/lua-bindings-shootout by ThePhD
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Lua/LuaLibrary.h"
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace lbsbench {
|
||||
|
||||
inline constexpr double kMagicValue = 24.0;
|
||||
|
||||
struct Counter
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
void inc()
|
||||
{
|
||||
++value;
|
||||
}
|
||||
|
||||
int add(int x)
|
||||
{
|
||||
value += x;
|
||||
return value;
|
||||
}
|
||||
|
||||
int get() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
void set(int v)
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
static int static_add(int a, int b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
};
|
||||
|
||||
struct Basic
|
||||
{
|
||||
double var = 0.0;
|
||||
|
||||
double get() const
|
||||
{
|
||||
return var;
|
||||
}
|
||||
|
||||
void set(double v)
|
||||
{
|
||||
var = v;
|
||||
}
|
||||
};
|
||||
|
||||
struct BasicLarge
|
||||
{
|
||||
std::int64_t var = 0;
|
||||
std::int64_t var0 = 0;
|
||||
std::int64_t var1 = 0;
|
||||
std::int64_t var2 = 0;
|
||||
std::int64_t var3 = 0;
|
||||
std::int64_t var4 = 0;
|
||||
std::int64_t var5 = 0;
|
||||
std::int64_t var6 = 0;
|
||||
std::int64_t var7 = 0;
|
||||
std::int64_t var8 = 0;
|
||||
std::int64_t var9 = 0;
|
||||
std::int64_t var10 = 0;
|
||||
std::int64_t var11 = 0;
|
||||
std::int64_t var12 = 0;
|
||||
std::int64_t var13 = 0;
|
||||
std::int64_t var14 = 0;
|
||||
std::int64_t var15 = 0;
|
||||
std::int64_t var16 = 0;
|
||||
std::int64_t var17 = 0;
|
||||
std::int64_t var18 = 0;
|
||||
std::int64_t var19 = 0;
|
||||
std::int64_t var20 = 0;
|
||||
std::int64_t var21 = 0;
|
||||
std::int64_t var22 = 0;
|
||||
std::int64_t var23 = 0;
|
||||
std::int64_t var24 = 0;
|
||||
std::int64_t var25 = 0;
|
||||
std::int64_t var26 = 0;
|
||||
std::int64_t var27 = 0;
|
||||
std::int64_t var28 = 0;
|
||||
std::int64_t var29 = 0;
|
||||
std::int64_t var30 = 0;
|
||||
std::int64_t var31 = 0;
|
||||
std::int64_t var32 = 0;
|
||||
std::int64_t var33 = 0;
|
||||
std::int64_t var34 = 0;
|
||||
std::int64_t var35 = 0;
|
||||
std::int64_t var36 = 0;
|
||||
std::int64_t var37 = 0;
|
||||
std::int64_t var38 = 0;
|
||||
std::int64_t var39 = 0;
|
||||
std::int64_t var40 = 0;
|
||||
std::int64_t var41 = 0;
|
||||
std::int64_t var42 = 0;
|
||||
std::int64_t var43 = 0;
|
||||
std::int64_t var44 = 0;
|
||||
std::int64_t var45 = 0;
|
||||
std::int64_t var46 = 0;
|
||||
std::int64_t var47 = 0;
|
||||
std::int64_t var48 = 0;
|
||||
std::int64_t var49 = 0;
|
||||
};
|
||||
|
||||
struct ComplexBaseA
|
||||
{
|
||||
double a = kMagicValue;
|
||||
|
||||
double a_func() const
|
||||
{
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
struct ComplexBaseB
|
||||
{
|
||||
double b = kMagicValue;
|
||||
|
||||
double b_func() const
|
||||
{
|
||||
return b;
|
||||
}
|
||||
};
|
||||
|
||||
struct ComplexAB : ComplexBaseA, ComplexBaseB
|
||||
{
|
||||
double ab = kMagicValue;
|
||||
|
||||
double ab_func() const
|
||||
{
|
||||
return ab;
|
||||
}
|
||||
};
|
||||
|
||||
struct StatefulFunction
|
||||
{
|
||||
double operator()(double v) const
|
||||
{
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
struct SharedObject : std::enable_shared_from_this<SharedObject>
|
||||
{
|
||||
double value = kMagicValue;
|
||||
|
||||
double get() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
struct Vec3Source
|
||||
{
|
||||
float x = 0.f, y = 0.f, z = 0.f;
|
||||
Vec3Source() = default;
|
||||
Vec3Source(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {}
|
||||
};
|
||||
|
||||
struct Vec3Target
|
||||
{
|
||||
float x = 0.f, y = 0.f, z = 0.f;
|
||||
Vec3Target() = default;
|
||||
Vec3Target(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {}
|
||||
};
|
||||
|
||||
struct ColorSource
|
||||
{
|
||||
float r = 0.f, g = 0.f, b = 0.f;
|
||||
ColorSource() = default;
|
||||
ColorSource(float r_, float g_, float b_) : r(r_), g(g_), b(b_) {}
|
||||
};
|
||||
|
||||
inline float sumVec3(Vec3Target v)
|
||||
{
|
||||
return v.x + v.y + v.z;
|
||||
}
|
||||
|
||||
inline float sumVec3Ref(const Vec3Target& v)
|
||||
{
|
||||
return v.x + v.y + v.z;
|
||||
}
|
||||
|
||||
inline Basic* basic_return()
|
||||
{
|
||||
static Basic value{};
|
||||
return &value;
|
||||
}
|
||||
|
||||
inline double basic_get_var(Basic* b)
|
||||
{
|
||||
return b ? b->var : 0.0;
|
||||
}
|
||||
|
||||
inline std::shared_ptr<SharedObject> shared_object_return()
|
||||
{
|
||||
static std::shared_ptr<SharedObject> obj = std::make_shared<SharedObject>();
|
||||
return obj;
|
||||
}
|
||||
|
||||
inline double shared_object_get_value(std::shared_ptr<SharedObject> obj)
|
||||
{
|
||||
return obj ? obj->get() : 0.0;
|
||||
}
|
||||
|
||||
void luaCheckOrThrow(lua_State* L, int status, std::string_view where);
|
||||
void luaDoStringOrThrow(lua_State* L, std::string_view code, std::string_view where);
|
||||
|
||||
inline void setSkipped(benchmark::State& state, std::string_view reason)
|
||||
{
|
||||
state.SkipWithError(std::string(reason).c_str());
|
||||
}
|
||||
|
||||
} // namespace lbsbench
|
||||
+514
@@ -0,0 +1,514 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// Inspired from https://github.com/ThePhD/lua-bindings-shootout by ThePhD
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "benchmark_common.hpp"
|
||||
|
||||
#include <LuaBridge/LuaBridge.h>
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace lbsbench;
|
||||
|
||||
int vanilla_multi_return(lua_State* L)
|
||||
{
|
||||
const double i = lua_tonumber(L, 1);
|
||||
luabridge::push(L, i);
|
||||
luabridge::push(L, i * 2.0);
|
||||
return 2;
|
||||
}
|
||||
|
||||
void registerBasicGetterSetter(lua_State* L)
|
||||
{
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<Basic>("c")
|
||||
.addConstructor<void (*)()>()
|
||||
.addProperty("val", &Basic::get, &Basic::set)
|
||||
.endClass();
|
||||
}
|
||||
|
||||
void registerCounter(lua_State* L)
|
||||
{
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<Counter>("Counter")
|
||||
.addConstructor<void (*)()>()
|
||||
.addFunction("get", &Counter::get)
|
||||
.addStaticFunction("static_add", &Counter::static_add)
|
||||
.endClass();
|
||||
}
|
||||
|
||||
lua_State* makeLua()
|
||||
{
|
||||
lua_State* L = luaL_newstate();
|
||||
luaL_openlibs(L);
|
||||
return L;
|
||||
}
|
||||
|
||||
void registerBasic(lua_State* L)
|
||||
{
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<Basic>("c")
|
||||
.addConstructor<void (*)()>()
|
||||
.addFunction("set", &Basic::set)
|
||||
.addFunction("get", &Basic::get)
|
||||
.addData("var", &Basic::var)
|
||||
.endClass();
|
||||
}
|
||||
|
||||
void table_global_string_get_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luabridge::setGlobal(L, kMagicValue, "value");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += static_cast<double>(luabridge::getGlobal(L, "value"));
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void table_global_string_set_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
|
||||
double v = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
v += kMagicValue;
|
||||
luabridge::setGlobal(L, v, "value");
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(v);
|
||||
}
|
||||
|
||||
void table_get_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "warble = { value = 24.0 }", "vanilla table_get setup");
|
||||
luabridge::LuaRef t = luabridge::getGlobal(L, "warble");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += static_cast<double>(t["value"]);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void table_set_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "warble = { value = 24.0 }", "vanilla table_set setup");
|
||||
luabridge::LuaRef t = luabridge::getGlobal(L, "warble");
|
||||
|
||||
double v = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
v += kMagicValue;
|
||||
t["value"] = v;
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(v);
|
||||
}
|
||||
|
||||
void table_chained_get_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "ulahibe = { warble = { value = 24.0 } }", "vanilla chained_get setup");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
luabridge::LuaRef tw = luabridge::getGlobal(L, "ulahibe")["warble"];
|
||||
x += static_cast<double>(tw["value"]);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void table_chained_set_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "ulahibe = { warble = { value = 24.0 } }", "vanilla chained_set setup");
|
||||
|
||||
double v = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
v += kMagicValue;
|
||||
luabridge::LuaRef tw = luabridge::getGlobal(L, "ulahibe")["warble"];
|
||||
tw["value"] = v;
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(v);
|
||||
}
|
||||
|
||||
void c_function_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luabridge::getGlobalNamespace(L).addFunction("f", +[](double v) { return v; });
|
||||
luaDoStringOrThrow(L, "function invoke_f() return f(24.0) end", "vanilla c_function setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_f");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "vanilla invoke_f");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void lua_function_in_c_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "function f(i) return i end", "vanilla lua_function setup");
|
||||
|
||||
luabridge::LuaRef f = luabridge::getGlobal(L, "f");
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += static_cast<double>(f(kMagicValue));
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void c_function_through_lua_in_c_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luabridge::getGlobalNamespace(L).addFunction("f", +[](double v) { return v; });
|
||||
|
||||
luabridge::LuaRef f = luabridge::getGlobal(L, "f");
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += static_cast<double>(f(kMagicValue));
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void member_function_call_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasic(L);
|
||||
luaDoStringOrThrow(L, "b = c()", "vanilla member setup");
|
||||
luaDoStringOrThrow(L, "function call_member() b:set(b:get() + 1.0) end", "vanilla member closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "call_member");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 0, 0), "vanilla call_member");
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_variable_access_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasic(L);
|
||||
luaDoStringOrThrow(L, "b = c()", "vanilla userdata setup");
|
||||
luaDoStringOrThrow(L, "function access_var() b.var = b.var + 1.0 return b.var end", "vanilla userdata closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "access_var");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "vanilla access_var");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_variable_access_large_measure(benchmark::State& state)
|
||||
{
|
||||
setSkipped(state, "unsupported in LuaBridge vanilla benchmark parity mode");
|
||||
}
|
||||
|
||||
void userdata_variable_access_last_measure(benchmark::State& state)
|
||||
{
|
||||
setSkipped(state, "unsupported in LuaBridge vanilla benchmark parity mode");
|
||||
}
|
||||
|
||||
void stateful_function_object_measure(benchmark::State& state)
|
||||
{
|
||||
setSkipped(state, "unsupported in LuaBridge vanilla benchmark parity mode");
|
||||
}
|
||||
|
||||
void multi_return_lua_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luabridge::getGlobalNamespace(L).addCFunction("f", vanilla_multi_return);
|
||||
luaDoStringOrThrow(L, "function invoke_multi() local a,b=f(24.0) return a+b end", "vanilla multi_return_lua setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_multi");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "vanilla invoke_multi");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void multi_return_measure(benchmark::State& state)
|
||||
{
|
||||
setSkipped(state, "unsupported conceptual multi-return conversion in LuaBridge vanilla");
|
||||
}
|
||||
|
||||
void derived_base_measure(benchmark::State& state)
|
||||
{
|
||||
setSkipped(state, "unsupported for multi inheritance in LuaBridge vanilla");
|
||||
}
|
||||
|
||||
void return_userdata_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasic(L);
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.addFunction("f", &basic_return)
|
||||
.addFunction("h", &basic_get_var);
|
||||
luaDoStringOrThrow(L, "function invoke_userdata() return h(f()) end", "vanilla return_userdata setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_userdata");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "vanilla invoke_userdata");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void optional_success_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "warble = { value = 24.0 }", "vanilla optional_success setup");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
luabridge::LuaRef tt = luabridge::getGlobal(L, "warble");
|
||||
if (tt.isTable())
|
||||
{
|
||||
luabridge::LuaRef tv = tt["value"];
|
||||
x += tv.isNumber() ? static_cast<double>(tv) : 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
x += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void optional_half_failure_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "warble = { value = 'x' }", "vanilla optional_half_failure setup");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
luabridge::LuaRef tt = luabridge::getGlobal(L, "warble");
|
||||
if (tt.isTable())
|
||||
{
|
||||
luabridge::LuaRef tv = tt["value"];
|
||||
x += tv.isNumber() ? static_cast<double>(tv) : 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
x += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void optional_failure_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
luabridge::LuaRef tt = luabridge::getGlobal(L, "warble");
|
||||
if (tt.isTable())
|
||||
{
|
||||
luabridge::LuaRef tv = tt["value"];
|
||||
x += tv.isNumber() ? static_cast<double>(tv) : 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
x += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void userdata_variable_write_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasic(L);
|
||||
luaDoStringOrThrow(L, "b = c()", "vanilla userdata_write setup");
|
||||
luaDoStringOrThrow(L, "function write_var() b.var = 24.0 end", "vanilla userdata_write closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "write_var");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 0, 0), "vanilla write_var");
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_property_getter_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasicGetterSetter(L);
|
||||
luaDoStringOrThrow(L, "b = c()", "vanilla property_getter setup");
|
||||
luaDoStringOrThrow(L, "function read_getter() return b.val end", "vanilla property_getter closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "read_getter");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "vanilla read_getter");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_property_setter_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasicGetterSetter(L);
|
||||
luaDoStringOrThrow(L, "b = c()", "vanilla property_setter setup");
|
||||
luaDoStringOrThrow(L, "function write_setter() b.val = 24.0 end", "vanilla property_setter closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "write_setter");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 0, 0), "vanilla write_setter");
|
||||
}
|
||||
}
|
||||
|
||||
void lambda_capture_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
double extra = kMagicValue;
|
||||
luabridge::getGlobalNamespace(L).addFunction("f", std::function<double(double)>([extra](double v) { return v + extra; }));
|
||||
luaDoStringOrThrow(L, "function invoke_lambda() return f(24.0) end", "vanilla lambda_capture setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_lambda");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "vanilla invoke_lambda");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void shared_ptr_return_measure(benchmark::State& state)
|
||||
{
|
||||
setSkipped(state, "unsupported shared_ptr container in LuaBridge vanilla");
|
||||
}
|
||||
|
||||
void shared_ptr_pass_measure(benchmark::State& state)
|
||||
{
|
||||
setSkipped(state, "unsupported shared_ptr container in LuaBridge vanilla");
|
||||
}
|
||||
|
||||
void static_member_function_call_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerCounter(L);
|
||||
luaDoStringOrThrow(L, "function invoke_static() return Counter.static_add(10, 32) end", "vanilla static_member_function setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_static");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "vanilla invoke_static");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void derived_method_call_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<ComplexBaseA>("ComplexBaseA")
|
||||
.addFunction("a_func", &ComplexBaseA::a_func)
|
||||
.addProperty("a", &ComplexBaseA::a)
|
||||
.endClass()
|
||||
.deriveClass<ComplexAB, ComplexBaseA>("ComplexAB")
|
||||
.addConstructor<void (*)()>()
|
||||
.addFunction("ab_func", &ComplexAB::ab_func)
|
||||
.addProperty("ab", &ComplexAB::ab)
|
||||
.endClass();
|
||||
|
||||
luaDoStringOrThrow(L, "obj = ComplexAB()", "vanilla derived_method setup");
|
||||
luaDoStringOrThrow(L, "function call_derived() return obj:ab_func() end", "vanilla derived_method closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "call_derived");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "vanilla call_derived");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void implicit_inheritance_measure(benchmark::State& state)
|
||||
{
|
||||
setSkipped(state, "unsupported for multi inheritance in LuaBridge vanilla");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BENCHMARK(table_global_string_get_measure)->Name("table_global_string_get_measure");
|
||||
BENCHMARK(table_global_string_set_measure)->Name("table_global_string_set_measure");
|
||||
BENCHMARK(table_get_measure)->Name("table_get_measure");
|
||||
BENCHMARK(table_set_measure)->Name("table_set_measure");
|
||||
BENCHMARK(table_chained_get_measure)->Name("table_chained_get_measure");
|
||||
BENCHMARK(table_chained_set_measure)->Name("table_chained_set_measure");
|
||||
BENCHMARK(c_function_measure)->Name("c_function_measure");
|
||||
BENCHMARK(c_function_through_lua_in_c_measure)->Name("c_function_through_lua_in_c_measure");
|
||||
BENCHMARK(lua_function_in_c_measure)->Name("lua_function_in_c_measure");
|
||||
BENCHMARK(member_function_call_measure)->Name("member_function_call_measure");
|
||||
BENCHMARK(userdata_variable_access_measure)->Name("userdata_variable_access_measure");
|
||||
BENCHMARK(userdata_variable_access_large_measure)->Name("userdata_variable_access_large_measure");
|
||||
BENCHMARK(userdata_variable_access_last_measure)->Name("userdata_variable_access_last_measure");
|
||||
BENCHMARK(multi_return_lua_measure)->Name("multi_return_lua_measure");
|
||||
BENCHMARK(multi_return_measure)->Name("multi_return_measure");
|
||||
BENCHMARK(stateful_function_object_measure)->Name("stateful_function_object_measure");
|
||||
BENCHMARK(derived_base_measure)->Name("derived_base_measure");
|
||||
BENCHMARK(return_userdata_measure)->Name("return_userdata_measure");
|
||||
BENCHMARK(optional_success_measure)->Name("optional_success_measure");
|
||||
BENCHMARK(optional_half_failure_measure)->Name("optional_half_failure_measure");
|
||||
BENCHMARK(optional_failure_measure)->Name("optional_failure_measure");
|
||||
BENCHMARK(implicit_inheritance_measure)->Name("implicit_inheritance_measure");
|
||||
BENCHMARK(userdata_variable_write_measure)->Name("userdata_variable_write_measure");
|
||||
BENCHMARK(userdata_property_getter_measure)->Name("userdata_property_getter_measure");
|
||||
BENCHMARK(userdata_property_setter_measure)->Name("userdata_property_setter_measure");
|
||||
BENCHMARK(lambda_capture_measure)->Name("lambda_capture_measure");
|
||||
BENCHMARK(shared_ptr_return_measure)->Name("shared_ptr_return_measure");
|
||||
BENCHMARK(shared_ptr_pass_measure)->Name("shared_ptr_pass_measure");
|
||||
BENCHMARK(static_member_function_call_measure)->Name("static_member_function_call_measure");
|
||||
BENCHMARK(derived_method_call_measure)->Name("derived_method_call_measure");
|
||||
@@ -0,0 +1,805 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// Inspired from https://github.com/ThePhD/lua-bindings-shootout by ThePhD
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "benchmark_common.hpp"
|
||||
|
||||
#include "LuaBridge/LuaBridge.h"
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <tuple>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
template <>
|
||||
struct StackConversion<lbsbench::Vec3Target>
|
||||
{
|
||||
static constexpr bool enabled = true;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct StackConverter<lbsbench::Vec3Target, lbsbench::Vec3Source>
|
||||
{
|
||||
static lbsbench::Vec3Target convert(const lbsbench::Vec3Source& s)
|
||||
{
|
||||
return {s.x, s.y, s.z};
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct StackConverter<lbsbench::Vec3Target, lbsbench::ColorSource>
|
||||
{
|
||||
static lbsbench::Vec3Target convert(const lbsbench::ColorSource& s)
|
||||
{
|
||||
return {s.r, s.g, s.b};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace lbsbench;
|
||||
|
||||
std::tuple<double, double> lb3_multi_return(double value)
|
||||
{
|
||||
return { value, value * 2.0 };
|
||||
}
|
||||
|
||||
void registerBasic(lua_State* L)
|
||||
{
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<Basic>("c")
|
||||
.addConstructor<void (*)()>()
|
||||
.addFunction("set", &Basic::set)
|
||||
.addFunction("get", &Basic::get)
|
||||
.addProperty("var", &Basic::var)
|
||||
.endClass();
|
||||
}
|
||||
|
||||
void registerBasicLarge(lua_State* L)
|
||||
{
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<BasicLarge>("cl")
|
||||
.addConstructor<void (*)()>()
|
||||
.addProperty("var", &BasicLarge::var)
|
||||
.addProperty("var0", &BasicLarge::var0)
|
||||
.addProperty("var1", &BasicLarge::var1)
|
||||
.addProperty("var2", &BasicLarge::var2)
|
||||
.addProperty("var3", &BasicLarge::var3)
|
||||
.addProperty("var4", &BasicLarge::var4)
|
||||
.addProperty("var5", &BasicLarge::var5)
|
||||
.addProperty("var6", &BasicLarge::var6)
|
||||
.addProperty("var7", &BasicLarge::var7)
|
||||
.addProperty("var8", &BasicLarge::var8)
|
||||
.addProperty("var9", &BasicLarge::var9)
|
||||
.addProperty("var10", &BasicLarge::var10)
|
||||
.addProperty("var11", &BasicLarge::var11)
|
||||
.addProperty("var12", &BasicLarge::var12)
|
||||
.addProperty("var13", &BasicLarge::var13)
|
||||
.addProperty("var14", &BasicLarge::var14)
|
||||
.addProperty("var15", &BasicLarge::var15)
|
||||
.addProperty("var16", &BasicLarge::var16)
|
||||
.addProperty("var17", &BasicLarge::var17)
|
||||
.addProperty("var18", &BasicLarge::var18)
|
||||
.addProperty("var19", &BasicLarge::var19)
|
||||
.addProperty("var20", &BasicLarge::var20)
|
||||
.addProperty("var21", &BasicLarge::var21)
|
||||
.addProperty("var22", &BasicLarge::var22)
|
||||
.addProperty("var23", &BasicLarge::var23)
|
||||
.addProperty("var24", &BasicLarge::var24)
|
||||
.addProperty("var25", &BasicLarge::var25)
|
||||
.addProperty("var26", &BasicLarge::var26)
|
||||
.addProperty("var27", &BasicLarge::var27)
|
||||
.addProperty("var28", &BasicLarge::var28)
|
||||
.addProperty("var29", &BasicLarge::var29)
|
||||
.addProperty("var30", &BasicLarge::var30)
|
||||
.addProperty("var31", &BasicLarge::var31)
|
||||
.addProperty("var32", &BasicLarge::var32)
|
||||
.addProperty("var33", &BasicLarge::var33)
|
||||
.addProperty("var34", &BasicLarge::var34)
|
||||
.addProperty("var35", &BasicLarge::var35)
|
||||
.addProperty("var36", &BasicLarge::var36)
|
||||
.addProperty("var37", &BasicLarge::var37)
|
||||
.addProperty("var38", &BasicLarge::var38)
|
||||
.addProperty("var39", &BasicLarge::var39)
|
||||
.addProperty("var40", &BasicLarge::var40)
|
||||
.addProperty("var41", &BasicLarge::var41)
|
||||
.addProperty("var42", &BasicLarge::var42)
|
||||
.addProperty("var43", &BasicLarge::var43)
|
||||
.addProperty("var44", &BasicLarge::var44)
|
||||
.addProperty("var45", &BasicLarge::var45)
|
||||
.addProperty("var46", &BasicLarge::var46)
|
||||
.addProperty("var47", &BasicLarge::var47)
|
||||
.addProperty("var48", &BasicLarge::var48)
|
||||
.addProperty("var49", &BasicLarge::var49)
|
||||
.endClass();
|
||||
}
|
||||
|
||||
void registerBasicRW(lua_State* L)
|
||||
{
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<Basic>("c")
|
||||
.addConstructor<void (*)()>()
|
||||
.addPropertyReadWrite("var", &Basic::var)
|
||||
.endClass();
|
||||
}
|
||||
|
||||
void registerBasicGetterSetter(lua_State* L)
|
||||
{
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<Basic>("c")
|
||||
.addConstructor<void (*)()>()
|
||||
.addProperty("val", &Basic::get, &Basic::set)
|
||||
.endClass();
|
||||
}
|
||||
|
||||
void registerCounter(lua_State* L)
|
||||
{
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<Counter>("Counter")
|
||||
.addConstructor<void (*)()>()
|
||||
.addFunction("get", &Counter::get)
|
||||
.addStaticFunction("static_add", &Counter::static_add)
|
||||
.endClass();
|
||||
}
|
||||
|
||||
void registerSharedObject(lua_State* L)
|
||||
{
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<SharedObject>("SharedObject")
|
||||
.addConstructorFrom<std::shared_ptr<SharedObject>, void(*)()>()
|
||||
.addFunction("get", &SharedObject::get)
|
||||
.endClass()
|
||||
.addFunction("get_shared", &shared_object_return)
|
||||
.addFunction("use_shared", &shared_object_get_value);
|
||||
}
|
||||
|
||||
lua_State* makeLua()
|
||||
{
|
||||
lua_State* L = luaL_newstate();
|
||||
luaL_openlibs(L);
|
||||
luabridge::registerMainThread(L);
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
luabridge::enableExceptions(L);
|
||||
#endif
|
||||
return L;
|
||||
}
|
||||
|
||||
void table_global_string_get_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luabridge::setGlobal(L, kMagicValue, "value");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += static_cast<double>(luabridge::getGlobal(L, "value"));
|
||||
}
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void table_global_string_set_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
|
||||
double v = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
v += kMagicValue;
|
||||
luabridge::setGlobal(L, v, "value");
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(v);
|
||||
}
|
||||
|
||||
void table_get_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "warble = { value = 24.0 }", "table_get setup");
|
||||
luabridge::LuaRef t = luabridge::getGlobal(L, "warble");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += static_cast<double>(t["value"]);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void table_set_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "warble = { value = 24.0 }", "table_set setup");
|
||||
luabridge::LuaRef t = luabridge::getGlobal(L, "warble");
|
||||
|
||||
double v = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
v += kMagicValue;
|
||||
t["value"] = v;
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(v);
|
||||
}
|
||||
|
||||
void table_chained_get_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "ulahibe = { warble = { value = 24.0 } }", "table_chained_get setup");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
luabridge::LuaRef tw = luabridge::getGlobal(L, "ulahibe")["warble"];
|
||||
x += static_cast<double>(tw["value"]);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void table_chained_set_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "ulahibe = { warble = { value = 24.0 } }", "table_chained_set setup");
|
||||
|
||||
double v = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
v += kMagicValue;
|
||||
luabridge::LuaRef tw = luabridge::getGlobal(L, "ulahibe")["warble"];
|
||||
tw["value"] = v;
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(v);
|
||||
}
|
||||
|
||||
void c_function_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luabridge::getGlobalNamespace(L).addFunction("f", +[](double v) { return v; });
|
||||
|
||||
luaDoStringOrThrow(L, "function invoke_f() return f(24.0) end", "c_function setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_f");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "invoke_f");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void lua_function_in_c_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "function f(i) return i end", "lua_function setup");
|
||||
|
||||
luabridge::LuaRef f = luabridge::getGlobal(L, "f");
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += f.call<double>(kMagicValue).valueOr(0.0);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void c_function_through_lua_in_c_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luabridge::getGlobalNamespace(L).addFunction("f", +[](double v) { return v; });
|
||||
|
||||
luabridge::LuaRef f = luabridge::getGlobal(L, "f");
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += f.call<double>(kMagicValue).valueOr(0.0);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void member_function_call_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasic(L);
|
||||
luaDoStringOrThrow(L, "b = c()", "member_function setup");
|
||||
luaDoStringOrThrow(L, "function call_member() b:set(b:get() + 1.0) end", "member_function closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "call_member");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 0, 0), "call_member");
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_variable_access_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasic(L);
|
||||
luaDoStringOrThrow(L, "b = c()", "userdata_variable_access setup");
|
||||
luaDoStringOrThrow(L, "function access_var() return b.var end", "userdata_variable_access closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "access_var");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "access_var");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_variable_access_large_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasicLarge(L);
|
||||
luaDoStringOrThrow(L, "b = cl()", "userdata_variable_access_large setup");
|
||||
luaDoStringOrThrow(L, "function access_var_large() return b.var0 end", "userdata_variable_access_large closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "access_var_large");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "access_var_large");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_variable_access_last_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasicLarge(L);
|
||||
luaDoStringOrThrow(L, "b = cl()", "userdata_variable_access_last setup");
|
||||
luaDoStringOrThrow(L, "function access_var_last() return b.var49 end", "userdata_variable_access_last closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "access_var_last");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "access_var_last");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void stateful_function_object_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luabridge::getGlobalNamespace(L).addFunction("f", StatefulFunction{});
|
||||
|
||||
luabridge::LuaRef f = luabridge::getGlobal(L, "f");
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += f.call<double>(kMagicValue).valueOr(0.0);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void multi_return_lua_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luabridge::getGlobalNamespace(L).addFunction("f", &lb3_multi_return);
|
||||
luaDoStringOrThrow(L, "function invoke_multi() local a,b=f(24.0) return a+b end", "multi_return_lua setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_multi");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "invoke_multi");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void multi_return_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luabridge::getGlobalNamespace(L).addFunction("f", &lb3_multi_return);
|
||||
luabridge::LuaRef f = luabridge::getGlobal(L, "f");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
auto result = f.call<std::tuple<double, double>>(kMagicValue).valueOr(std::make_tuple(0.0, 0.0));
|
||||
x += std::get<0>(result);
|
||||
x += std::get<1>(result);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void derived_base_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<ComplexBaseA>("ComplexBaseA")
|
||||
.addFunction("a_func", &ComplexBaseA::a_func)
|
||||
.addProperty("a", &ComplexBaseA::a)
|
||||
.endClass()
|
||||
.beginClass<ComplexBaseB>("ComplexBaseB")
|
||||
.addFunction("b_func", &ComplexBaseB::b_func)
|
||||
.addProperty("b", &ComplexBaseB::b)
|
||||
.endClass()
|
||||
.deriveClass<ComplexAB, ComplexBaseA, ComplexBaseB>("ComplexAB")
|
||||
.addConstructor<void (*)()>()
|
||||
.addFunction("ab_func", &ComplexAB::ab_func)
|
||||
.addProperty("ab", &ComplexAB::ab)
|
||||
.endClass();
|
||||
|
||||
luaDoStringOrThrow(L, "obj = ComplexAB()", "base_derived setup");
|
||||
luaDoStringOrThrow(L, "function call_base() return obj:a_func() + obj:b_func() end", "base_derived closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "call_base");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "call_base");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void optional_success_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "warble = { value = 24.0 }", "optional_success setup");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
auto result = luabridge::tryGetGlobalField<double>(L, "warble", "value");
|
||||
x += result ? *result : 1.0;
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void optional_half_failure_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
luaDoStringOrThrow(L, "warble = { value = 'x' }", "optional_half_failure setup");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
auto result = luabridge::tryGetGlobalField<double>(L, "warble", "value");
|
||||
x += result ? *result : 1.0;
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void optional_failure_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
auto result = luabridge::tryGetGlobalField<double>(L, "warble", "value");
|
||||
x += result ? *result : 1.0;
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void return_userdata_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasic(L);
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.addFunction("f", &basic_return)
|
||||
.addFunction("h", &basic_get_var);
|
||||
luaDoStringOrThrow(L, "function invoke_userdata() return h(f()) end", "return_userdata setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_userdata");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "invoke_userdata");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_variable_write_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasicRW(L);
|
||||
luaDoStringOrThrow(L, "b = c()", "userdata_variable_write setup");
|
||||
luaDoStringOrThrow(L, "function write_var() b.var = 24.0 end", "userdata_variable_write closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "write_var");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 0, 0), "write_var");
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_property_getter_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasicGetterSetter(L);
|
||||
luaDoStringOrThrow(L, "b = c()", "userdata_property_getter setup");
|
||||
luaDoStringOrThrow(L, "function read_getter() return b.val end", "userdata_property_getter closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "read_getter");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "read_getter");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_property_setter_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerBasicGetterSetter(L);
|
||||
luaDoStringOrThrow(L, "b = c()", "userdata_property_setter setup");
|
||||
luaDoStringOrThrow(L, "function write_setter() b.val = 24.0 end", "userdata_property_setter closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "write_setter");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 0, 0), "write_setter");
|
||||
}
|
||||
}
|
||||
|
||||
void lambda_capture_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
double extra = kMagicValue;
|
||||
luabridge::getGlobalNamespace(L).addFunction("f", [extra](double v) { return v + extra; });
|
||||
luaDoStringOrThrow(L, "function invoke_lambda() return f(24.0) end", "lambda_capture setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_lambda");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "invoke_lambda");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void shared_ptr_return_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerSharedObject(L);
|
||||
luaDoStringOrThrow(L, "function invoke_shared() return get_shared():get() end", "shared_ptr_return setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_shared");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "invoke_shared");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void shared_ptr_pass_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerSharedObject(L);
|
||||
luaDoStringOrThrow(L, "obj = SharedObject()", "shared_ptr_pass setup");
|
||||
luaDoStringOrThrow(L, "function invoke_pass_shared() return use_shared(obj) end", "shared_ptr_pass closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_pass_shared");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "invoke_pass_shared");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void static_member_function_call_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerCounter(L);
|
||||
luaDoStringOrThrow(L, "function invoke_static() return Counter.static_add(10, 32) end", "static_member_function setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_static");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "invoke_static");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void derived_method_call_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<ComplexBaseA>("ComplexBaseA")
|
||||
.addFunction("a_func", &ComplexBaseA::a_func)
|
||||
.addProperty("a", &ComplexBaseA::a)
|
||||
.endClass()
|
||||
.beginClass<ComplexBaseB>("ComplexBaseB")
|
||||
.addFunction("b_func", &ComplexBaseB::b_func)
|
||||
.addProperty("b", &ComplexBaseB::b)
|
||||
.endClass()
|
||||
.deriveClass<ComplexAB, ComplexBaseA, ComplexBaseB>("ComplexAB")
|
||||
.addConstructor<void (*)()>()
|
||||
.addFunction("ab_func", &ComplexAB::ab_func)
|
||||
.addProperty("ab", &ComplexAB::ab)
|
||||
.endClass();
|
||||
|
||||
luaDoStringOrThrow(L, "obj = ComplexAB()", "derived_method setup");
|
||||
luaDoStringOrThrow(L, "function call_derived() return obj:ab_func() end", "derived_method closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "call_derived");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "call_derived");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void implicit_inheritance_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<ComplexBaseA>("ComplexBaseA")
|
||||
.addFunction("a_func", &ComplexBaseA::a_func)
|
||||
.endClass()
|
||||
.deriveClass<ComplexAB, ComplexBaseA>("ComplexAB")
|
||||
.addConstructor<void (*)()>()
|
||||
.addFunction("ab_func", &ComplexAB::ab_func)
|
||||
.endClass()
|
||||
.addFunction("call_a", +[](ComplexBaseA* obj) -> double { return obj->a_func(); });
|
||||
|
||||
luaDoStringOrThrow(L, "obj = ComplexAB()", "implicit_inheritance setup");
|
||||
luaDoStringOrThrow(L, "function test_implicit() return call_a(obj) end", "implicit_inheritance closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "test_implicit");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "test_implicit");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void registerConverter(lua_State* L)
|
||||
{
|
||||
luabridge::getGlobalNamespace(L)
|
||||
.beginClass<Vec3Source>("Vec3Source")
|
||||
.addConstructor<void(float, float, float)>()
|
||||
.addConverter<Vec3Target>()
|
||||
.endClass()
|
||||
.beginClass<ColorSource>("ColorSource")
|
||||
.addConstructor<void(float, float, float)>()
|
||||
.addConverter<Vec3Target>()
|
||||
.endClass()
|
||||
.beginClass<Vec3Target>("Vec3Target")
|
||||
.addConstructor<void(float, float, float)>()
|
||||
.endClass()
|
||||
.addFunction("sumVec3", &sumVec3)
|
||||
.addFunction("sumVec3Ref", &sumVec3Ref);
|
||||
}
|
||||
|
||||
void converter_exact_type_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerConverter(L);
|
||||
luaDoStringOrThrow(L, "obj = Vec3Target(1, 2, 3)", "converter_exact_type setup");
|
||||
luaDoStringOrThrow(L, "function invoke_exact() return sumVec3(obj) end", "converter_exact_type closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_exact");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "invoke_exact");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void converter_phase3_value_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerConverter(L);
|
||||
luaDoStringOrThrow(L, "obj = Vec3Source(1, 2, 3)", "converter_phase3_value setup");
|
||||
luaDoStringOrThrow(L, "function invoke_conv_value() return sumVec3(obj) end", "converter_phase3_value closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_conv_value");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "invoke_conv_value");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void converter_phase3_ref_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerConverter(L);
|
||||
luaDoStringOrThrow(L, "obj = Vec3Source(1, 2, 3)", "converter_phase3_ref setup");
|
||||
luaDoStringOrThrow(L, "function invoke_conv_ref() return sumVec3Ref(obj) end", "converter_phase3_ref closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_conv_ref");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "invoke_conv_ref");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void converter_multi_registered_measure(benchmark::State& state)
|
||||
{
|
||||
lua_State* L = makeLua();
|
||||
registerConverter(L);
|
||||
luaDoStringOrThrow(L, "obj = ColorSource(0.5, 1, 0)", "converter_multi_registered setup");
|
||||
luaDoStringOrThrow(L, "function invoke_conv_multi() return sumVec3(obj) end", "converter_multi_registered closure setup");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua_getglobal(L, "invoke_conv_multi");
|
||||
luaCheckOrThrow(L, lua_pcall(L, 0, 1, 0), "invoke_conv_multi");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BENCHMARK(table_global_string_get_measure)->Name("table_global_string_get_measure");
|
||||
BENCHMARK(table_global_string_set_measure)->Name("table_global_string_set_measure");
|
||||
BENCHMARK(table_get_measure)->Name("table_get_measure");
|
||||
BENCHMARK(table_set_measure)->Name("table_set_measure");
|
||||
BENCHMARK(table_chained_get_measure)->Name("table_chained_get_measure");
|
||||
BENCHMARK(table_chained_set_measure)->Name("table_chained_set_measure");
|
||||
BENCHMARK(c_function_measure)->Name("c_function_measure");
|
||||
BENCHMARK(c_function_through_lua_in_c_measure)->Name("c_function_through_lua_in_c_measure");
|
||||
BENCHMARK(lua_function_in_c_measure)->Name("lua_function_in_c_measure");
|
||||
BENCHMARK(member_function_call_measure)->Name("member_function_call_measure");
|
||||
BENCHMARK(userdata_variable_access_measure)->Name("userdata_variable_access_measure");
|
||||
BENCHMARK(userdata_variable_access_large_measure)->Name("userdata_variable_access_large_measure");
|
||||
BENCHMARK(userdata_variable_access_last_measure)->Name("userdata_variable_access_last_measure");
|
||||
BENCHMARK(multi_return_lua_measure)->Name("multi_return_lua_measure");
|
||||
BENCHMARK(multi_return_measure)->Name("multi_return_measure");
|
||||
BENCHMARK(stateful_function_object_measure)->Name("stateful_function_object_measure");
|
||||
BENCHMARK(derived_base_measure)->Name("derived_base_measure");
|
||||
BENCHMARK(return_userdata_measure)->Name("return_userdata_measure");
|
||||
BENCHMARK(optional_success_measure)->Name("optional_success_measure");
|
||||
BENCHMARK(optional_half_failure_measure)->Name("optional_half_failure_measure");
|
||||
BENCHMARK(optional_failure_measure)->Name("optional_failure_measure");
|
||||
BENCHMARK(implicit_inheritance_measure)->Name("implicit_inheritance_measure");
|
||||
BENCHMARK(userdata_variable_write_measure)->Name("userdata_variable_write_measure");
|
||||
BENCHMARK(userdata_property_getter_measure)->Name("userdata_property_getter_measure");
|
||||
BENCHMARK(userdata_property_setter_measure)->Name("userdata_property_setter_measure");
|
||||
BENCHMARK(lambda_capture_measure)->Name("lambda_capture_measure");
|
||||
BENCHMARK(shared_ptr_return_measure)->Name("shared_ptr_return_measure");
|
||||
BENCHMARK(shared_ptr_pass_measure)->Name("shared_ptr_pass_measure");
|
||||
BENCHMARK(static_member_function_call_measure)->Name("static_member_function_call_measure");
|
||||
BENCHMARK(derived_method_call_measure)->Name("derived_method_call_measure");
|
||||
BENCHMARK(converter_exact_type_measure)->Name("converter_exact_type_measure");
|
||||
BENCHMARK(converter_phase3_value_measure)->Name("converter_phase3_value_measure");
|
||||
BENCHMARK(converter_phase3_ref_measure)->Name("converter_phase3_ref_measure");
|
||||
BENCHMARK(converter_multi_registered_measure)->Name("converter_multi_registered_measure");
|
||||
+618
@@ -0,0 +1,618 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// Inspired from https://github.com/ThePhD/lua-bindings-shootout by ThePhD
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "benchmark_common.hpp"
|
||||
|
||||
#include <sol/sol.hpp>
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace lbsbench;
|
||||
|
||||
std::tuple<double, double> sol3_multi_return(double value)
|
||||
{
|
||||
return { value, value * 2.0 };
|
||||
}
|
||||
|
||||
void registerBasic(sol::state& lua)
|
||||
{
|
||||
lua.new_usertype<Basic>("c",
|
||||
sol::constructors<Basic()>(),
|
||||
"set", &Basic::set,
|
||||
"get", &Basic::get,
|
||||
"var", &Basic::var);
|
||||
}
|
||||
|
||||
void registerBasicLarge(sol::state& lua)
|
||||
{
|
||||
lua.new_usertype<BasicLarge>("cl",
|
||||
sol::constructors<BasicLarge()>(),
|
||||
"var", &BasicLarge::var,
|
||||
"var0", &BasicLarge::var0,
|
||||
"var1", &BasicLarge::var1,
|
||||
"var2", &BasicLarge::var2,
|
||||
"var3", &BasicLarge::var3,
|
||||
"var4", &BasicLarge::var4,
|
||||
"var5", &BasicLarge::var5,
|
||||
"var6", &BasicLarge::var6,
|
||||
"var7", &BasicLarge::var7,
|
||||
"var8", &BasicLarge::var8,
|
||||
"var9", &BasicLarge::var9,
|
||||
"var10", &BasicLarge::var10,
|
||||
"var11", &BasicLarge::var11,
|
||||
"var12", &BasicLarge::var12,
|
||||
"var13", &BasicLarge::var13,
|
||||
"var14", &BasicLarge::var14,
|
||||
"var15", &BasicLarge::var15,
|
||||
"var16", &BasicLarge::var16,
|
||||
"var17", &BasicLarge::var17,
|
||||
"var18", &BasicLarge::var18,
|
||||
"var19", &BasicLarge::var19,
|
||||
"var20", &BasicLarge::var20,
|
||||
"var21", &BasicLarge::var21,
|
||||
"var22", &BasicLarge::var22,
|
||||
"var23", &BasicLarge::var23,
|
||||
"var24", &BasicLarge::var24,
|
||||
"var25", &BasicLarge::var25,
|
||||
"var26", &BasicLarge::var26,
|
||||
"var27", &BasicLarge::var27,
|
||||
"var28", &BasicLarge::var28,
|
||||
"var29", &BasicLarge::var29,
|
||||
"var30", &BasicLarge::var30,
|
||||
"var31", &BasicLarge::var31,
|
||||
"var32", &BasicLarge::var32,
|
||||
"var33", &BasicLarge::var33,
|
||||
"var34", &BasicLarge::var34,
|
||||
"var35", &BasicLarge::var35,
|
||||
"var36", &BasicLarge::var36,
|
||||
"var37", &BasicLarge::var37,
|
||||
"var38", &BasicLarge::var38,
|
||||
"var39", &BasicLarge::var39,
|
||||
"var40", &BasicLarge::var40,
|
||||
"var41", &BasicLarge::var41,
|
||||
"var42", &BasicLarge::var42,
|
||||
"var43", &BasicLarge::var43,
|
||||
"var44", &BasicLarge::var44,
|
||||
"var45", &BasicLarge::var45,
|
||||
"var46", &BasicLarge::var46,
|
||||
"var47", &BasicLarge::var47,
|
||||
"var48", &BasicLarge::var48,
|
||||
"var49", &BasicLarge::var49);
|
||||
}
|
||||
|
||||
void registerBasicGetterSetter(sol::state& lua)
|
||||
{
|
||||
lua.new_usertype<Basic>("c",
|
||||
sol::constructors<Basic()>(),
|
||||
"val", sol::property(&Basic::get, &Basic::set));
|
||||
}
|
||||
|
||||
void registerCounter(sol::state& lua)
|
||||
{
|
||||
lua.new_usertype<Counter>("Counter",
|
||||
sol::constructors<Counter()>(),
|
||||
"get", &Counter::get,
|
||||
"static_add", &Counter::static_add);
|
||||
}
|
||||
|
||||
void registerSharedObject(sol::state& lua)
|
||||
{
|
||||
lua.new_usertype<SharedObject>("SharedObject",
|
||||
sol::call_constructor,
|
||||
sol::factories([]() { return std::make_shared<SharedObject>(); }),
|
||||
"get", &SharedObject::get);
|
||||
lua.set_function("get_shared", &shared_object_return);
|
||||
lua.set_function("use_shared", &shared_object_get_value);
|
||||
}
|
||||
|
||||
void table_global_string_get_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
lua["value"] = kMagicValue;
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += lua["value"].get<double>();
|
||||
}
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void table_global_string_set_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
double v = 0;
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
v += kMagicValue;
|
||||
lua["value"] = v;
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(v);
|
||||
}
|
||||
|
||||
void table_get_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
lua.script("warble = { value = 24.0 }");
|
||||
sol::table t = lua["warble"];
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += t["value"].get<double>();
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void table_set_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
lua.script("warble = { value = 24.0 }");
|
||||
sol::table t = lua["warble"];
|
||||
|
||||
double v = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
v += kMagicValue;
|
||||
t["value"] = v;
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(v);
|
||||
}
|
||||
|
||||
void table_chained_get_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
lua.script("ulahibe = { warble = { value = 24.0 } }");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += lua["ulahibe"]["warble"]["value"].get<double>();
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void table_chained_set_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
lua.script("ulahibe = { warble = { value = 24.0 } }");
|
||||
|
||||
double v = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
v += kMagicValue;
|
||||
lua["ulahibe"]["warble"]["value"] = v;
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(v);
|
||||
}
|
||||
|
||||
void c_function_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
lua.set_function("f", +[](double value) { return value; });
|
||||
lua.script("function invoke_f() return f(24.0) end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["invoke_f"]();
|
||||
}
|
||||
}
|
||||
|
||||
void lua_function_in_c_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
lua.script("function f(i) return i end");
|
||||
sol::function f = lua["f"];
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += f.call<double>(kMagicValue);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void c_function_through_lua_in_c_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
lua.set_function("f", +[](double value) { return value; });
|
||||
sol::function f = lua["f"];
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += f.call<double>(kMagicValue);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void member_function_call_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
registerBasic(lua);
|
||||
lua.script("b = c.new()\nfunction call_member() b:set(b:get() + 1.0) end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["call_member"]();
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_variable_access_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
registerBasic(lua);
|
||||
lua.script("b = c.new()\nfunction access_var() b.var = b.var + 1.0 return b.var end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["access_var"]();
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_variable_access_large_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
registerBasicLarge(lua);
|
||||
lua.script("b = cl.new()\nfunction access_var_large() b.var0 = b.var0 + 1 return b.var0 end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["access_var_large"]();
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_variable_access_last_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
registerBasicLarge(lua);
|
||||
lua.script("b = cl.new()\nfunction access_var_last() b.var49 = b.var49 + 1 return b.var49 end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["access_var_last"]();
|
||||
}
|
||||
}
|
||||
|
||||
void stateful_function_object_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
lua.set_function("f", StatefulFunction{});
|
||||
sol::function f = lua["f"];
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
x += f.call<double>(kMagicValue);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void multi_return_lua_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
lua.set_function("f", &sol3_multi_return);
|
||||
lua.script("function invoke_multi() local a,b=f(24.0) return a+b end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["invoke_multi"]();
|
||||
}
|
||||
}
|
||||
|
||||
void multi_return_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
lua.set_function("f", &sol3_multi_return);
|
||||
sol::function f = lua["f"];
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
std::tuple<double, double> values = f.call<double, double>(kMagicValue);
|
||||
x += std::get<0>(values);
|
||||
x += std::get<1>(values);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void derived_base_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
|
||||
lua.new_usertype<ComplexBaseA>("ComplexBaseA",
|
||||
"a_func", &ComplexBaseA::a_func,
|
||||
"a", &ComplexBaseA::a);
|
||||
|
||||
lua.new_usertype<ComplexBaseB>("ComplexBaseB",
|
||||
"b_func", &ComplexBaseB::b_func,
|
||||
"b", &ComplexBaseB::b);
|
||||
|
||||
lua.new_usertype<ComplexAB>("ComplexAB",
|
||||
sol::base_classes, sol::bases<ComplexBaseA, ComplexBaseB>(),
|
||||
"ab_func", &ComplexAB::ab_func,
|
||||
"ab", &ComplexAB::ab);
|
||||
|
||||
ComplexAB ab;
|
||||
lua["b"] = &ab;
|
||||
|
||||
lua.script("function call_base() return b:a_func() + b:b_func() end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["call_base"]();
|
||||
}
|
||||
}
|
||||
|
||||
void optional_success_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
lua.script("warble = { value = 24.0 }");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
sol::optional<double> value = lua["warble"]["value"];
|
||||
x += value.value_or(1.0);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void optional_half_failure_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
lua.script("warble = { value = 'x' }");
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
sol::optional<double> value = lua["warble"]["value"];
|
||||
x += value.value_or(1.0);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void optional_failure_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
|
||||
double x = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
sol::optional<double> value = lua["warble"]["value"];
|
||||
x += value.value_or(1.0);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
|
||||
void return_userdata_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
registerBasic(lua);
|
||||
lua.set_function("f", &basic_return);
|
||||
lua.set_function("h", &basic_get_var);
|
||||
lua.script("function invoke_userdata() return h(f()) end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["invoke_userdata"]();
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_variable_write_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
registerBasic(lua);
|
||||
lua.script("b = c.new()\nfunction write_var() b.var = 24.0 end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["write_var"]();
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_property_getter_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
registerBasicGetterSetter(lua);
|
||||
lua.script("b = c.new()\nfunction read_getter() return b.val end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["read_getter"]();
|
||||
}
|
||||
}
|
||||
|
||||
void userdata_property_setter_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
registerBasicGetterSetter(lua);
|
||||
lua.script("b = c.new()\nfunction write_setter() b.val = 24.0 end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["write_setter"]();
|
||||
}
|
||||
}
|
||||
|
||||
void lambda_capture_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
double extra = kMagicValue;
|
||||
lua.set_function("f", [extra](double v) { return v + extra; });
|
||||
lua.script("function invoke_lambda() return f(24.0) end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["invoke_lambda"]();
|
||||
}
|
||||
}
|
||||
|
||||
void shared_ptr_return_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
registerSharedObject(lua);
|
||||
lua.script("function invoke_shared() return get_shared():get() end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["invoke_shared"]();
|
||||
}
|
||||
}
|
||||
|
||||
void shared_ptr_pass_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
registerSharedObject(lua);
|
||||
lua.script("obj = SharedObject()\nfunction invoke_pass_shared() return use_shared(obj) end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["invoke_pass_shared"]();
|
||||
}
|
||||
}
|
||||
|
||||
void static_member_function_call_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
registerCounter(lua);
|
||||
lua.script("function invoke_static() return Counter.static_add(10, 32) end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["invoke_static"]();
|
||||
}
|
||||
}
|
||||
|
||||
void derived_method_call_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
|
||||
lua.new_usertype<ComplexBaseA>("ComplexBaseA",
|
||||
"a_func", &ComplexBaseA::a_func,
|
||||
"a", &ComplexBaseA::a);
|
||||
|
||||
lua.new_usertype<ComplexBaseB>("ComplexBaseB",
|
||||
"b_func", &ComplexBaseB::b_func,
|
||||
"b", &ComplexBaseB::b);
|
||||
|
||||
lua.new_usertype<ComplexAB>("ComplexAB",
|
||||
sol::constructors<ComplexAB()>(),
|
||||
sol::base_classes, sol::bases<ComplexBaseA, ComplexBaseB>(),
|
||||
"ab_func", &ComplexAB::ab_func,
|
||||
"ab", &ComplexAB::ab);
|
||||
|
||||
ComplexAB ab;
|
||||
lua["obj"] = &ab;
|
||||
lua.script("function call_derived() return obj:ab_func() end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["call_derived"]();
|
||||
}
|
||||
}
|
||||
|
||||
void implicit_inheritance_measure(benchmark::State& state)
|
||||
{
|
||||
sol::state lua;
|
||||
|
||||
lua.new_usertype<ComplexBaseA>("ComplexBaseA",
|
||||
"a_func", &ComplexBaseA::a_func);
|
||||
|
||||
lua.new_usertype<ComplexAB>("ComplexAB",
|
||||
sol::constructors<ComplexAB()>(),
|
||||
sol::base_classes, sol::bases<ComplexBaseA>(),
|
||||
"ab_func", &ComplexAB::ab_func);
|
||||
|
||||
lua.set_function("call_a", +[](ComplexBaseA* obj) -> double { return obj->a_func(); });
|
||||
|
||||
lua.script("obj = ComplexAB.new()");
|
||||
lua.script("function test_implicit() return call_a(obj) end");
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
(void) _;
|
||||
lua["test_implicit"]();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BENCHMARK(table_global_string_get_measure)->Name("table_global_string_get_measure");
|
||||
BENCHMARK(table_global_string_set_measure)->Name("table_global_string_set_measure");
|
||||
BENCHMARK(table_get_measure)->Name("table_get_measure");
|
||||
BENCHMARK(table_set_measure)->Name("table_set_measure");
|
||||
BENCHMARK(table_chained_get_measure)->Name("table_chained_get_measure");
|
||||
BENCHMARK(table_chained_set_measure)->Name("table_chained_set_measure");
|
||||
BENCHMARK(c_function_measure)->Name("c_function_measure");
|
||||
BENCHMARK(c_function_through_lua_in_c_measure)->Name("c_function_through_lua_in_c_measure");
|
||||
BENCHMARK(lua_function_in_c_measure)->Name("lua_function_in_c_measure");
|
||||
BENCHMARK(member_function_call_measure)->Name("member_function_call_measure");
|
||||
BENCHMARK(userdata_variable_access_measure)->Name("userdata_variable_access_measure");
|
||||
BENCHMARK(userdata_variable_access_large_measure)->Name("userdata_variable_access_large_measure");
|
||||
BENCHMARK(userdata_variable_access_last_measure)->Name("userdata_variable_access_last_measure");
|
||||
BENCHMARK(multi_return_lua_measure)->Name("multi_return_lua_measure");
|
||||
BENCHMARK(multi_return_measure)->Name("multi_return_measure");
|
||||
BENCHMARK(stateful_function_object_measure)->Name("stateful_function_object_measure");
|
||||
BENCHMARK(derived_base_measure)->Name("derived_base_measure");
|
||||
BENCHMARK(return_userdata_measure)->Name("return_userdata_measure");
|
||||
BENCHMARK(optional_success_measure)->Name("optional_success_measure");
|
||||
BENCHMARK(optional_half_failure_measure)->Name("optional_half_failure_measure");
|
||||
BENCHMARK(optional_failure_measure)->Name("optional_failure_measure");
|
||||
BENCHMARK(implicit_inheritance_measure)->Name("implicit_inheritance_measure");
|
||||
BENCHMARK(userdata_variable_write_measure)->Name("userdata_variable_write_measure");
|
||||
BENCHMARK(userdata_property_getter_measure)->Name("userdata_property_getter_measure");
|
||||
BENCHMARK(userdata_property_setter_measure)->Name("userdata_property_setter_measure");
|
||||
BENCHMARK(lambda_capture_measure)->Name("lambda_capture_measure");
|
||||
BENCHMARK(shared_ptr_return_measure)->Name("shared_ptr_return_measure");
|
||||
BENCHMARK(shared_ptr_pass_measure)->Name("shared_ptr_pass_measure");
|
||||
BENCHMARK(static_member_function_call_measure)->Name("static_member_function_call_measure");
|
||||
BENCHMARK(derived_method_call_measure)->Name("derived_method_call_measure");
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.patches as mpatches
|
||||
import numpy as np
|
||||
|
||||
|
||||
# ── Label helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
_SUFFIX = "_measure"
|
||||
|
||||
def _clean_label(name: str) -> str:
|
||||
if name.endswith(_SUFFIX):
|
||||
name = name[: -len(_SUFFIX)]
|
||||
return name.replace("_", " ")
|
||||
|
||||
|
||||
# ── JSON loading ──────────────────────────────────────────────────────────────
|
||||
|
||||
def infer_library_name(path: str) -> str:
|
||||
return Path(path).stem.replace("benchmark_", "")
|
||||
|
||||
|
||||
def load_google_benchmark_json(path: str, library_name: str) -> dict:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
|
||||
case_values: dict[str, float] = {}
|
||||
case_stddev: dict[str, float] = {}
|
||||
case_errors: dict[str, str] = {}
|
||||
|
||||
for entry in data.get("benchmarks", []):
|
||||
name = entry.get("name", "")
|
||||
run_type = entry.get("run_type", "")
|
||||
|
||||
# Prefer aggregate mean/stddev when available
|
||||
if run_type == "aggregate":
|
||||
base_name = entry.get("run_name", name)
|
||||
agg = entry.get("aggregate_name")
|
||||
t = entry.get("real_time", entry.get("cpu_time", 0.0))
|
||||
if agg == "mean":
|
||||
case_values[base_name] = t
|
||||
elif agg == "stddev":
|
||||
case_stddev[base_name] = t
|
||||
continue
|
||||
|
||||
if run_type not in ("iteration", ""):
|
||||
continue
|
||||
|
||||
if entry.get("error_occurred"):
|
||||
case_errors[name] = entry.get("error_message", "error")
|
||||
continue
|
||||
|
||||
if name not in case_values:
|
||||
case_values[name] = entry.get("real_time", entry.get("cpu_time", 0.0))
|
||||
|
||||
return {"library": library_name, "values": case_values, "stddev": case_stddev, "errors": case_errors}
|
||||
|
||||
|
||||
# ── Merge ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
def merge_results(result_sets):
|
||||
merged: dict[str, dict[str, float]] = defaultdict(dict)
|
||||
stddev: dict[str, dict[str, float]] = defaultdict(dict)
|
||||
errors: dict[str, dict[str, str]] = defaultdict(dict)
|
||||
|
||||
for result in result_sets:
|
||||
lib = result["library"]
|
||||
for case_name, value in result["values"].items():
|
||||
merged[case_name][lib] = value
|
||||
for case_name, sd in result.get("stddev", {}).items():
|
||||
stddev[case_name][lib] = sd
|
||||
for case_name, error in result["errors"].items():
|
||||
errors[case_name][lib] = error
|
||||
|
||||
return merged, stddev, errors
|
||||
|
||||
|
||||
# ── Plotting ──────────────────────────────────────────────────────────────────
|
||||
|
||||
# Dark theme colours
|
||||
_BG = "#1E1E2E" # figure / axes background
|
||||
_FG = "#CDD6F4" # text, ticks, labels
|
||||
_GRID = "#313244" # grid lines
|
||||
_SPINE = "#45475A" # axis spines
|
||||
_UNSUP = "#585B70" # "unsupported" text
|
||||
|
||||
# Bright palette suited for dark backgrounds
|
||||
_PALETTE = [
|
||||
"#89B4FA", # blue
|
||||
"#FAB387", # peach
|
||||
"#A6E3A1", # green
|
||||
"#F38BA8", # red
|
||||
"#CBA6F7", # mauve
|
||||
"#94E2D5", # teal
|
||||
"#F9E2AF", # yellow
|
||||
"#89DCEB", # sky
|
||||
]
|
||||
|
||||
_LIB_ORDER = ["LuaBridge3Benchmark", "LuaBridgeVanillaBenchmark", "Sol3Benchmark"]
|
||||
_LIB_ORDER_MAP = {lib: i for i, lib in enumerate(_LIB_ORDER)}
|
||||
|
||||
|
||||
def plot_grouped_bars(merged: dict, stddev: dict, errors: dict, output_file: str, log_scale: bool = False) -> None:
|
||||
case_names = sorted(merged.keys())
|
||||
all_libs = {lib for cases in merged.values() for lib in cases}
|
||||
libraries = sorted(all_libs, key=lambda l: _LIB_ORDER_MAP.get(l, len(_LIB_ORDER)))
|
||||
|
||||
if not case_names or not libraries:
|
||||
raise RuntimeError("No benchmark samples found to plot")
|
||||
|
||||
n_cases = len(case_names)
|
||||
n_libs = len(libraries)
|
||||
clean_labels = [_clean_label(cn) for cn in case_names]
|
||||
|
||||
# ── Layout ────────────────────────────────────────────────────────────────
|
||||
bar_h = 0.80
|
||||
group_h = bar_h / n_libs
|
||||
fig_h = max(10, n_cases * bar_h + 2)
|
||||
|
||||
with plt.rc_context({
|
||||
"text.color": _FG,
|
||||
"axes.labelcolor": _FG,
|
||||
"xtick.color": _FG,
|
||||
"ytick.color": _FG,
|
||||
}):
|
||||
fig, ax = plt.subplots(figsize=(14, fig_h))
|
||||
fig.patch.set_facecolor(_BG)
|
||||
ax.set_facecolor(_BG)
|
||||
|
||||
colors = {lib: _PALETTE[i % len(_PALETTE)] for i, lib in enumerate(libraries)}
|
||||
y_positions = np.arange(n_cases, dtype=float)
|
||||
|
||||
# Max value including error bars — used to size x-axis
|
||||
x_max_with_err = 1.0
|
||||
for cn in case_names:
|
||||
for lib in libraries:
|
||||
val = merged[cn].get(lib, float("nan"))
|
||||
if not np.isnan(val):
|
||||
sd = stddev.get(cn, {}).get(lib, 0.0) or 0.0
|
||||
x_max_with_err = max(x_max_with_err, val + sd)
|
||||
|
||||
for i, library in enumerate(libraries):
|
||||
values = [merged[cn].get(library, float("nan")) for cn in case_names]
|
||||
sds = [stddev.get(cn, {}).get(library, float("nan")) for cn in case_names]
|
||||
bar_y = y_positions + (i - (n_libs - 1) / 2.0) * group_h
|
||||
|
||||
xerr_vals = [sd if not np.isnan(sd) else 0.0 for sd in sds]
|
||||
has_errors = any(sd > 0 for sd in xerr_vals)
|
||||
|
||||
ax.barh(
|
||||
bar_y,
|
||||
values,
|
||||
height=group_h * 0.85,
|
||||
color=colors[library],
|
||||
label=library,
|
||||
xerr=xerr_vals if has_errors else None,
|
||||
error_kw={"ecolor": _FG, "capsize": 3, "elinewidth": 1.2, "capthick": 1.2},
|
||||
zorder=4,
|
||||
)
|
||||
|
||||
for y, val, sd in zip(bar_y, values, sds):
|
||||
if np.isnan(val):
|
||||
ax.text(
|
||||
0, y, " unsupported",
|
||||
va="center", ha="left",
|
||||
fontsize=10, color=_UNSUP, style="italic",
|
||||
zorder=5,
|
||||
)
|
||||
else:
|
||||
label = f" {val:.1f} ±{sd:.1f} ns" if not np.isnan(sd) and sd > 0 else f" {val:.1f} ns"
|
||||
ax.text(
|
||||
val, y, label,
|
||||
va="center", ha="left",
|
||||
fontsize=9, color=_FG,
|
||||
zorder=5,
|
||||
)
|
||||
|
||||
# ── Axes ──────────────────────────────────────────────────────────────
|
||||
ax.set_yticks(y_positions)
|
||||
ax.set_yticklabels(clean_labels, fontsize=12)
|
||||
|
||||
half_span = (n_libs - 1) / 2.0 * group_h + group_h * 0.425
|
||||
ax.set_ylim(-half_span, n_cases - 1 + half_span)
|
||||
ax.invert_yaxis()
|
||||
|
||||
if log_scale:
|
||||
ax.set_xscale("log")
|
||||
ax.set_xlabel("Time (ns, log scale)", fontsize=13)
|
||||
else:
|
||||
ax.set_xlabel("Time (ns)", fontsize=13)
|
||||
|
||||
ax.set_xlim(0, x_max_with_err * 1.20)
|
||||
ax.xaxis.grid(True, color=_GRID, linestyle="--", alpha=1.0, zorder=2)
|
||||
ax.set_axisbelow(True)
|
||||
for spine in ax.spines.values():
|
||||
spine.set_edgecolor(_SPINE)
|
||||
ax.spines["top"].set_visible(True)
|
||||
ax.spines["right"].set_visible(False)
|
||||
ax.xaxis.set_tick_params(which="both", top=True, bottom=True, labeltop=True, labelbottom=True)
|
||||
ax.tick_params(axis="x", which="both", color=_SPINE, labelsize=11)
|
||||
|
||||
# ── Legend & title ────────────────────────────────────────────────────
|
||||
legend_handles = [mpatches.Patch(color=colors[lib], label=lib) for lib in libraries]
|
||||
ax.legend(
|
||||
handles=legend_handles,
|
||||
loc="upper right",
|
||||
fontsize=11,
|
||||
framealpha=1.0,
|
||||
facecolor=_SPINE,
|
||||
edgecolor=_SPINE,
|
||||
labelcolor=_FG,
|
||||
)
|
||||
ax.set_title(
|
||||
"Lua Binding Benchmarks — lower is better (ns)",
|
||||
fontsize=16, pad=10, fontweight="bold", color=_FG,
|
||||
)
|
||||
|
||||
fig.subplots_adjust(left=0.22, right=0.97, top=0.97, bottom=0.03)
|
||||
plt.savefig(output_file, dpi=150, facecolor=fig.get_facecolor())
|
||||
plt.close()
|
||||
|
||||
# ── Text summary ──────────────────────────────────────────────────────────
|
||||
txt_file = Path(output_file).with_suffix(".txt")
|
||||
col_w = max(len(lib) for lib in libraries) + 2
|
||||
label_w = max(len(lbl) for lbl in clean_labels) + 2
|
||||
|
||||
with open(txt_file, "w", encoding="utf-8") as f:
|
||||
header = f"{'Benchmark':<{label_w}}" + "".join(f"{lib:>{col_w}}" for lib in libraries)
|
||||
f.write(header + "\n")
|
||||
f.write("-" * len(header) + "\n")
|
||||
for cn, lbl in zip(case_names, clean_labels):
|
||||
row = f"{lbl:<{label_w}}"
|
||||
for lib in libraries:
|
||||
val = merged[cn].get(lib)
|
||||
cell = f"{val:>{col_w - 3}.1f} ns" if val is not None else f"{'n/a':>{col_w}}"
|
||||
row += cell
|
||||
f.write(row + "\n")
|
||||
print(f"Saved: {txt_file}")
|
||||
|
||||
|
||||
# ── Entry point ───────────────────────────────────────────────────────────────
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Plot comparisons from Google Benchmark JSON files"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--input", nargs="+", required=True,
|
||||
help="One or more Google Benchmark JSON files"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output", default="Benchmarks/benchmark_comparison.png",
|
||||
help="Output PNG file"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--log", action="store_true",
|
||||
help="Use a logarithmic x-axis"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
result_sets = [
|
||||
load_google_benchmark_json(path, infer_library_name(path))
|
||||
for path in args.input
|
||||
]
|
||||
|
||||
merged, stddev, errors = merge_results(result_sets)
|
||||
|
||||
Path(args.output).parent.mkdir(parents=True, exist_ok=True)
|
||||
plot_grouped_bars(merged, stddev, errors, args.output, log_scale=args.log)
|
||||
print(f"Saved: {args.output}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,2 @@
|
||||
matplotlib
|
||||
numpy
|
||||
Vendored
+181
@@ -0,0 +1,181 @@
|
||||
## Version 3.0
|
||||
|
||||
* Moved to C++17 as minimum supported standard C++ version.
|
||||
* Reworked the whole library to be able to use it without c++ exceptions enabled.
|
||||
* Lot of optimisations have been added, and now the library is *fast*, nearly in the same league as sol2 v3.x.
|
||||
* Breaking Change: The method `Stack<T>::push` now takes a `std::error_code&` as last parameter and returns a `bool`.
|
||||
* Breaking Change: The class `LuaException` has been reworked and it now take a `std::error_code` instead of a int.
|
||||
* Breaking Change: The class `LuaException` is now thrown if a unregistered class is pushed via the Stack class, also when calling `LuaRef::operator()`, but only if exceptions are enabled.
|
||||
* Breaking Change: `LuaRef::operator()` now returns the class `LuaResult`, where it is possible to obtain the call results or error message.
|
||||
* Breaking Change: LuaBridge does not silently enable exceptions when calling `getGlobalNamespace`. Call `enableExceptions(lua_State*)` if you want to enable them explicitly.
|
||||
* Breaking Change: Removed `RefCounterPtr`, maintaining the reference counts in a unsynchronized global table is not production quality.
|
||||
* Breaking Change: Removed `Class<T>::addStaticData`, it was just an alias for `Class<T>::addStaticProperty`.
|
||||
* Breaking Change: Removed `Class<T>::addCFunction`, it was just an alias for `Class<T>::addFunction`.
|
||||
* Breaking Change: Removed `Class<T>::addStaticCFunction`, it was just an alias for `Class<T>::addStaticFunction`.
|
||||
* Allow specifying a non virtual base class method when declaring class members (functions or variables) not exposed in the inherited class.
|
||||
* Allow using capturing lambdas in `Namespace::addFunction`, `Namespace::addProperty`, `Class<T>::addFunction`, `Class<T>::addStaticFunction`, `Class<T>::addProperty` and `Class<T>::addStaticProperty`.
|
||||
* Added multiple inheritance support: `deriveClass` now accepts more than one registered base class (e.g. `deriveClass<D, A, B>`).
|
||||
* Added C++20 coroutine integration: `CppCoroutine<R>` type that can be registered via `Namespace::addCoroutine()` to expose C++ generators to Lua using `co_yield` and `co_return`.
|
||||
* Added `LuaCoroutine` awaitable to resume a child Lua thread synchronously from inside a `CppCoroutine` body using `co_await`.
|
||||
* Added `lua_resume_x` and `lua_isyieldable_x` portable helpers in `LuaBridge/detail/LuaHelpers.h`.
|
||||
* Added `LUABRIDGE_HAS_CXX20_COROUTINES` feature-detection macro; opt out with `LUABRIDGE_DISABLE_CXX20_COROUTINES`.
|
||||
* Added `ErrorCode::CoroutineYieldFromNonCoroutine` and `ErrorCode::CoroutineAlreadyDone` error codes.
|
||||
* Added `Namespace::addVariable` to allow adding a modifiable value by copy into the namespace without incurring in function calls or metatables generation.
|
||||
* Added `luabridge::callWithHandler` free function and `LuaRef::callWithHandler` member to provide a custom Lua message handler during `lua_pcall`.
|
||||
* Added `luabridge::newFunction` free function and `LuaRef::newFunction` static method to wrap any C++ callable into a Lua function exposed as a `LuaRef`.
|
||||
* Added `luabridge::getNamespaceFromStack` function to construct a namespace object from a table on the stack.
|
||||
* Added `luabridge::registerMainThread` function especially useful when using lua 5.1 to register the main lua thread.
|
||||
* Added `std::shared_ptr` support for types intrusively deriving from `std::enable_shared_from_this`.
|
||||
* Added `Class<T>::addConstructor` support for specifying factory functor to do placement new of the object instance.
|
||||
* Added `Class<T>::addDestructor` to register a custom `__destruct` metamethod hook invoked just before the C++ destructor runs.
|
||||
* Added `Class<T>::addFunction` overload taking a `lua_CFunction` as if it were a member.
|
||||
* Added `Class<T>::addIndexMetaMethod` to allow register `__index` metamethod fallback on a registered class.
|
||||
* Added `Class<T>::addNewIndexMetaMethod` to allow register `__newindex` metamethod fallback on a registered class.
|
||||
* Added `Class<T>::addStaticIndexMetaMethod` for fallback `__index` handling on the static class table.
|
||||
* Added `Class<T>::addStaticNewIndexMetaMethod` for fallback `__newindex` handling on the static class table.
|
||||
* Added `LuaRef::isValid` to check when the reference is a LUA_NOREF.
|
||||
* Added `LuaRef::isCallable` to check when the reference is a function or has a `__call` metamethod.
|
||||
* Added `LuaException::state` to return the `lua_State` associated with the exception.
|
||||
* Added `void*` and `const void*` stack specializations mapped transparently to Lua lightuserdata.
|
||||
* Added support for `std::byte` as stack value type.
|
||||
* Added support for `std::string_view` as stack value type.
|
||||
* Added support for `std::tuple` as stack value type.
|
||||
* Added support for `std::optional` as stack value type.
|
||||
* Added support for `std::set` as stack value type by using `LuaBridge/Set.h`.
|
||||
* Added support to `LuaRef` for being hashed with `std::hash` (`LuaRef` properly usable in `std::unordered_map`).
|
||||
* Added `LuaRef::append` and variadic `LuaRef::append(vs...)` to append values to a Lua sequence table using `lua_rawseti`.
|
||||
* Added `LuaRef::call<R>()` now returns a strongly-typed `TypeResult<R>` instead of a generic `LuaResult`; `LuaRef::operator()` returns `TypeResult<void>`.
|
||||
* Added `LUABRIDGE_STRICT_STACK_CONVERSIONS` compile-time flag to enforce strict type-safe stack conversions (`bool` requires `LUA_TBOOLEAN`, `std::string` requires `LUA_TSTRING`).
|
||||
* Added `LuaFunction<Signature>` strongly-typed wrapper class for invoking Lua functions with compile-time argument and return-type checking.
|
||||
* Added `TypeResult<T>::valueOr(default)` to extract the contained value or return a fallback when a cast fails.
|
||||
* Added `allowOverridingMethods` class option to permit Lua scripts to override C++ methods registered in an extensible class.
|
||||
* Added single header amalgamated distribution file, to simplify including in projects.
|
||||
* Added more asserts for functions and property names.
|
||||
* Renamed `luabridge::Nil` to `luabridge::LuaNil` to allow including LuaBridge in Obj-C sources.
|
||||
* Removed the limitation of maximum 8 parameters in functions.
|
||||
* Removed the limitation of maximum 8 parameters in constructors.
|
||||
* Removed `Class<T>::addData`, it was just an alias for `Class<T>::addProperty`.
|
||||
* Removed `TypeList` from loki, using parameter packs and `std::tuple` with `std::apply`.
|
||||
* Removed juce traces from unit tests, simplified unit tests runs.
|
||||
* Changed all generic functions in `LuaRef` and `TableItem` to accept arguments by const reference instead of by copy.
|
||||
* Fixed `Stack<bool>::get` to properly require `LUA_TBOOLEAN` when `LUABRIDGE_STRICT_STACK_CONVERSIONS` is enabled; without the flag, legacy `lua_toboolean` semantics are preserved.
|
||||
* Fixed floating-point `Stack<T>::push`, `get`, and `isInstance` to correctly allow NaN and Inf values to pass through without error.
|
||||
* Fixed issue when `LuaRef::cast<>` fails with exceptions enabled, popping from the now empty stack could trigger the panic handler twice.
|
||||
* Fixed unaligned access in user allocated member pointers in 64bit machines reported by ASAN.
|
||||
* Fixed access of `LuaRef` in garbage collected `lua_thread`.
|
||||
* Included testing against Luau VM
|
||||
* Included testing against Ravi VM
|
||||
* Bumped lua 5.2.x in unit tests from lua 5.2.0 to 5.2.4.
|
||||
* Bumped lua 5.4.x in unit tests from lua 5.4.1 to 5.4.8.
|
||||
* Added Lua 5.3.6 and 5.5.0 in unit tests.
|
||||
* Run against PUC-Lua, Luau, LuaJIT and Ravi in CI.
|
||||
* Converted the manual from html to markdown.
|
||||
* Small improvements to code and doxygen comments readability.
|
||||
* Support for `__fastcall` function pointers.
|
||||
|
||||
## Version 2.6
|
||||
|
||||
* Added namespace `addFunction()` accepting `std::function` (C++11 only).
|
||||
* Added class `addStaticFunction()` accepting `std::function` (C++11 only).
|
||||
* Update the Doxygen documentation.
|
||||
* Add brief API reference into the manual.
|
||||
* Hide non-public `luabridge` members into the `detail` namespace.
|
||||
* Fix stack cleanup by `LuaRef::isInstance()` method.
|
||||
|
||||
## Version 2.5
|
||||
|
||||
* Introduce stack `isInstance()` method.
|
||||
* Introduce LuaRef `isInstance()` method.
|
||||
* Added a convenience `isInstance()` function template.
|
||||
|
||||
## Version 2.4.1
|
||||
|
||||
* Do not call the object destructor then its constructor throws.
|
||||
|
||||
## Version 2.4
|
||||
|
||||
* String stack get specialization doesn't change the stack value anymore.
|
||||
* Added namespace `addProperty()` accepting C-functions.
|
||||
* Introduce enableExceptions function.
|
||||
|
||||
## Version 2.3.2
|
||||
|
||||
* Fixed registration continuation for an already registered class.
|
||||
|
||||
## Version 2.3.1
|
||||
|
||||
* Fixed registration continuation issues.
|
||||
|
||||
## Version 2.3
|
||||
|
||||
* Added class `addFunction()` accepting proxy functions (C++11 only).
|
||||
* Added class `addFunction()` accepting `std::function` (C++11 only).
|
||||
* Added class `addProperty()` accepting functions with lua_State* parameter.
|
||||
* Added class `addProperty()` accepting `std::function` (C++11 only).
|
||||
* Added stack traits for `std::unordered_map` (`UnorderedMap.h`).
|
||||
* Now using lightuserdata for function pointers.
|
||||
|
||||
## Version 2.2.2
|
||||
|
||||
* Performance optimization.
|
||||
|
||||
## Version 2.2.1
|
||||
|
||||
* Refactored namespace and class handling.
|
||||
|
||||
## Version 2.2
|
||||
|
||||
* Refactored stack operations.
|
||||
* Handle exceptions in stack operations.
|
||||
|
||||
## Version 2.1.2
|
||||
|
||||
* Added `operator==` and `operator!=` for `RefCountedPtr` template.
|
||||
|
||||
## Version 2.1.1
|
||||
|
||||
* Support for `__stdcall` function pointers.
|
||||
|
||||
## Version 2.1
|
||||
|
||||
* Added stack traits for `std::vector` (`Vector.h`).
|
||||
* Added stack traits for `std::list` (`List.h`).
|
||||
* Added stack traits for `std::map` (`Map.h`).
|
||||
* Added ability to use `LuaRef` objects as an `std::map` keys.
|
||||
* Fixed some manual errata.
|
||||
|
||||
## Version 2.0
|
||||
|
||||
* Numerous bug fixes.
|
||||
* Feature Requests from Github issues.
|
||||
* Added `LuaRef` object.
|
||||
* Rewritten documentation.
|
||||
|
||||
## Version 1.1.0
|
||||
|
||||
* Split code up into several files.
|
||||
* Add Lua table and type representations (based on Nigel's code).
|
||||
* Reformat documentation as external HTML file.
|
||||
|
||||
## Version 1.0.3
|
||||
|
||||
* Pass `nil` to Lua when a null pointer is passed for objects with shared lifetime.
|
||||
|
||||
## Version 1.0.2
|
||||
|
||||
* Option to hide metatables selectable at runtime, default to true.
|
||||
* `addStaticMethod()` renamed to `addStaticFunction()` for consistency.
|
||||
* `addMethod()` renamed to `addFunction()` for consistency.
|
||||
* `addCFunction()` registrations.
|
||||
* Convert null pointers to and from `nil`.
|
||||
* Small performance increase in class pointer extraction.
|
||||
|
||||
## Version 1.0.1
|
||||
|
||||
* Backward compatibility with Lua 5.1.x.
|
||||
|
||||
## Version 1.0
|
||||
|
||||
* Explicit lifetime management models.
|
||||
* Generalized containers.
|
||||
* Single header distribution.
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
cmake_minimum_required (VERSION 3.10)
|
||||
|
||||
project (LuaBridge)
|
||||
|
||||
include (CMakeDependentOption)
|
||||
|
||||
if (NOT CMAKE_CXX_STANDARD)
|
||||
set (CMAKE_CXX_STANDARD 20)
|
||||
endif()
|
||||
|
||||
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set (CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
find_program (FIND_EXECUTABLE find)
|
||||
find_program (LCOV_EXECUTABLE lcov)
|
||||
find_program (GENHTML_EXECUTABLE genhtml)
|
||||
|
||||
cmake_dependent_option (LUABRIDGE_TESTING "Build tests" ON "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
|
||||
cmake_dependent_option (LUABRIDGE_COVERAGE "Enable coverage" OFF "LUABRIDGE_TESTING;FIND_EXECUTABLE;LCOV_EXECUTABLE;GENHTML_EXECUTABLE" OFF)
|
||||
cmake_dependent_option (LUABRIDGE_BENCHMARKS "Build benchmark executable" OFF "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
|
||||
set (LUABRIDGE_SANITIZE "" CACHE STRING "Sanitizer to enable (address, undefined, thread)")
|
||||
|
||||
add_subdirectory (Source)
|
||||
|
||||
if (LUABRIDGE_TESTING)
|
||||
include (CTest)
|
||||
enable_testing()
|
||||
set (gtest_force_shared_crt ON CACHE BOOL "Use /MD and /MDd" FORCE)
|
||||
add_subdirectory (ThirdParty/googletest)
|
||||
add_subdirectory (Tests)
|
||||
endif ()
|
||||
|
||||
if (LUABRIDGE_BENCHMARKS)
|
||||
add_subdirectory (Benchmarks)
|
||||
endif ()
|
||||
|
||||
add_custom_target (Documentation SOURCES
|
||||
CHANGES.md
|
||||
README.md
|
||||
Manual.md
|
||||
Doxyfile
|
||||
)
|
||||
Vendored
+38
@@ -0,0 +1,38 @@
|
||||
Contributing to LuaBridge3
|
||||
==========================
|
||||
|
||||
Thank you for considering contributing to LuaBridge3! We appreciate your interest in helping us make this library better.
|
||||
|
||||
The following is a set of guidelines for contributing to LuaBridge3. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
- Fork the repository and clone it locally.
|
||||
- Create a branch for your changes: `git checkout -b my-branch-name`.
|
||||
- Make your changes and commit them: `git commit -am 'Add some feature'`.
|
||||
- Push your changes to your fork: `git push origin my-branch-name`.
|
||||
- Open a pull request against the main branch of the original repository.
|
||||
|
||||
Testing
|
||||
-------
|
||||
We use Google Test for unit testing. Before submitting a pull request, please make sure that all tests pass by running all variants of them.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
We use Doxygen to provide inline documentation for this project. Please make sure that your code is documented using Doxygen comments. The documentation should explain what the code does, how to use it, and any other relevant information.
|
||||
|
||||
Pull Request Guidelines
|
||||
-----------------------
|
||||
- Pull requests should be focused on a single feature or bug fix.
|
||||
- Please include a summary of the change and which issue is fixed or which feature is added.
|
||||
- If the pull request adds functionality, please include tests for it.
|
||||
- Code coverage should never decrease. If it does, consider writing more tests.
|
||||
- Pull requests should be made against the main branch.
|
||||
|
||||
Code of Conduct
|
||||
===============
|
||||
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
|
||||
|
||||
License
|
||||
=======
|
||||
By contributing to LuaBridge3, you agree that your contributions will be licensed under the MIT License.
|
||||
+14737
File diff suppressed because it is too large
Load Diff
Vendored
+326
@@ -0,0 +1,326 @@
|
||||
# Doxyfile 1.8.13
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = LuaBridge
|
||||
PROJECT_NUMBER =
|
||||
PROJECT_BRIEF =
|
||||
PROJECT_LOGO =
|
||||
OUTPUT_DIRECTORY =
|
||||
CREATE_SUBDIRS = NO
|
||||
ALLOW_UNICODE_NAMES = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = NO
|
||||
ABBREVIATE_BRIEF =
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = YES
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 4
|
||||
ALIASES =
|
||||
TCL_SUBST =
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
EXTENSION_MAPPING =
|
||||
MARKDOWN_SUPPORT = YES
|
||||
TOC_INCLUDE_HEADINGS = 0
|
||||
AUTOLINK_SUPPORT = YES
|
||||
BUILTIN_STL_SUPPORT = YES
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
GROUP_NESTED_COMPOUNDS = NO
|
||||
SUBGROUPING = YES
|
||||
INLINE_GROUPED_CLASSES = NO
|
||||
INLINE_SIMPLE_STRUCTS = NO
|
||||
TYPEDEF_HIDES_STRUCT = NO
|
||||
LOOKUP_CACHE_SIZE = 0
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = YES
|
||||
EXTRACT_PACKAGE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = NO
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = NO
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
HIDE_COMPOUND_REFERENCE= NO
|
||||
SHOW_INCLUDE_FILES = NO
|
||||
SHOW_GROUPED_MEMB_INC = NO
|
||||
FORCE_LOCAL_INCLUDES = NO
|
||||
INLINE_INFO = NO
|
||||
SORT_MEMBER_DOCS = NO
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBERS_CTORS_1ST = YES
|
||||
SORT_GROUP_NAMES = YES
|
||||
SORT_BY_SCOPE_NAME = YES
|
||||
STRICT_PROTO_MATCHING = NO
|
||||
GENERATE_TODOLIST = NO
|
||||
GENERATE_TESTLIST = NO
|
||||
GENERATE_BUGLIST = NO
|
||||
GENERATE_DEPRECATEDLIST= NO
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = NO
|
||||
SHOW_FILES = NO
|
||||
SHOW_NAMESPACES = NO
|
||||
FILE_VERSION_FILTER =
|
||||
LAYOUT_FILE =
|
||||
CITE_BIB_FILES =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = YES
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = YES
|
||||
WARN_AS_ERROR = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = Source
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cpp \
|
||||
*.h \
|
||||
*.hpp
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXCLUDE_SYMBOLS = luabridge::detail::*
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
FILTER_SOURCE_PATTERNS =
|
||||
USE_MDFILE_AS_MAINPAGE =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
SOURCE_TOOLTIPS = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = NO
|
||||
CLANG_ASSISTED_PARSING = NO
|
||||
CLANG_OPTIONS =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = Documentation
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_EXTRA_STYLESHEET =
|
||||
HTML_EXTRA_FILES =
|
||||
HTML_COLORSTYLE_HUE = 240
|
||||
HTML_COLORSTYLE_SAT = 64
|
||||
HTML_COLORSTYLE_GAMMA = 80
|
||||
HTML_TIMESTAMP = NO
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
HTML_INDEX_NUM_ENTRIES = 100
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
|
||||
DOCSET_PUBLISHER_NAME = Publisher
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
CHM_INDEX_ENCODING =
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
GENERATE_QHP = NO
|
||||
QCH_FILE =
|
||||
QHP_NAMESPACE = org.doxygen.Project
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
QHP_CUST_FILTER_NAME =
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
QHG_LOCATION =
|
||||
GENERATE_ECLIPSEHELP = NO
|
||||
ECLIPSE_DOC_ID = org.doxygen.Project
|
||||
DISABLE_INDEX = NO
|
||||
GENERATE_TREEVIEW = YES
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
TREEVIEW_WIDTH = 250
|
||||
EXT_LINKS_IN_WINDOW = NO
|
||||
FORMULA_FONTSIZE = 10
|
||||
FORMULA_TRANSPARENT = YES
|
||||
USE_MATHJAX = NO
|
||||
MATHJAX_FORMAT = HTML-CSS
|
||||
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
|
||||
MATHJAX_EXTENSIONS =
|
||||
MATHJAX_CODEFILE =
|
||||
SEARCHENGINE = YES
|
||||
SERVER_BASED_SEARCH = NO
|
||||
EXTERNAL_SEARCH = NO
|
||||
SEARCHENGINE_URL =
|
||||
SEARCHDATA_FILE = searchdata.xml
|
||||
EXTERNAL_SEARCH_ID =
|
||||
EXTRA_SEARCH_MAPPINGS =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
LATEX_FOOTER =
|
||||
LATEX_EXTRA_STYLESHEET =
|
||||
LATEX_EXTRA_FILES =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_SOURCE_CODE = NO
|
||||
LATEX_BIB_STYLE = plain
|
||||
LATEX_TIMESTAMP = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
RTF_SOURCE_CODE = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_SUBDIR =
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the DOCBOOK output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_DOCBOOK = NO
|
||||
DOCBOOK_OUTPUT = docbook
|
||||
DOCBOOK_PROGRAMLISTING = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = NO
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED = WIN32 \
|
||||
= \
|
||||
1
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
EXTERNAL_PAGES = YES
|
||||
PERL_PATH = /bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = NO
|
||||
MSCGEN_PATH =
|
||||
DIA_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
DOT_NUM_THREADS = 0
|
||||
DOT_FONTNAME = Helvetica
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
UML_LIMIT_NUM_FIELDS = 10
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
INTERACTIVE_SVG = NO
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MSCFILE_DIRS =
|
||||
DIAFILE_DIRS =
|
||||
PLANTUML_JAR_PATH =
|
||||
PLANTUML_CFG_FILE =
|
||||
PLANTUML_INCLUDE_PATH =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
!.gitignore
|
||||
*.txt
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 449 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
LuaBridge3 is published under the terms of the MIT License
|
||||
|
||||
http://www.opensource.org/licenses/mit-license.html
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
* Copyright 2020, kunitoki
|
||||
* Copyright 2019, Dmitry Tarakanov
|
||||
* Copyright 2012, Vinnie Falco
|
||||
* Copyright 2008, Nigel Atkinson
|
||||
* Copyright 2007, Nathan Reed
|
||||
Vendored
+3022
File diff suppressed because it is too large
Load Diff
Vendored
+273
@@ -0,0 +1,273 @@
|
||||
<p float="left">
|
||||
<a href="https://kunitoki.github.io/LuaBridge3">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./Images/logo-dark.png">
|
||||
<img height="118" src="./Images/logo-bright.png">
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
<a href="https://lua.org">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./Images/lua-dark.png">
|
||||
<img height="118" src="./Images/lua-bright.png">
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
[](https://coveralls.io/github/kunitoki/LuaBridge3?branch=master)
|
||||
[](https://github.com/kunitoki/LuaBridge3/actions/workflows/build_macos.yml)
|
||||
[](https://github.com/kunitoki/LuaBridge3/actions/workflows/build_windows.yml)
|
||||
[](https://github.com/kunitoki/LuaBridge3/actions/workflows/build_linux.yml)
|
||||
[](https://github.com/kunitoki/LuaBridge3/actions/workflows/build_ubsan.yml)
|
||||
[](https://github.com/kunitoki/LuaBridge3/actions/workflows/build_asan.yml)
|
||||
<br/>
|
||||
[](https://www.lua.org/manual/5.1/readme.html)
|
||||
[](https://www.lua.org/manual/5.2/readme.html)
|
||||
[](https://www.lua.org/manual/5.3/readme.html)
|
||||
[](https://www.lua.org/manual/5.4/readme.html)
|
||||
[](https://www.lua.org/manual/5.5/readme.html)
|
||||
[](https://luajit.org/luajit.html)
|
||||
[](https://luau.org/)
|
||||
[](https://ravilang.github.io/)
|
||||
|
||||
# LuaBridge 3.0
|
||||
|
||||
[LuaBridge3](https://github.com/kunitoki/LuaBridge3) is a lightweight and dependency-free library for mapping data,
|
||||
functions, and classes back and forth between C++ and [Lua](http://wwww.lua.org) (a powerful,
|
||||
fast, lightweight, embeddable scripting language). LuaBridge has been tested
|
||||
and works with:
|
||||
* [PUC-Lua](https://lua.org) 5.1.5, 5.2.4, 5.3.6, 5.4.8 and 5.5.0
|
||||
* [LuaJit](https://luajit.org/) 2.1
|
||||
* [Luau](https://luau-lang.org/) 0.713
|
||||
* [Ravi](https://github.com/dibyendumajumdar/ravi) 1.0-beta11
|
||||
|
||||
## Features
|
||||
|
||||
LuaBridge3 is usable from a compliant C++17 compiler and offers the following features:
|
||||
|
||||
* [MIT Licensed](https://www.opensource.org/licenses/mit-license.html), no usage restrictions!
|
||||
* Headers-only: No Makefile, no .cpp files, just one `#include` and one header file (optional) !
|
||||
* Works with ANY lua version out there (PUC-Lua, LuaJIT, Luau, Ravi, you name it).
|
||||
* Simple, light, and nothing else needed.
|
||||
* Competitive performance with the fastest C++/Lua binding libraries available.
|
||||
* Fast to compile (even in release mode), scaling linearly with the size of your binded code.
|
||||
* No macros, settings, or configuration scripts needed.
|
||||
* Supports different object lifetime management models.
|
||||
* Convenient, type-safe access to the Lua stack.
|
||||
* Automatic function parameter type binding.
|
||||
* Functions and constructors overloading support.
|
||||
* Easy access to Lua objects like tables and functions.
|
||||
* Expose C++ classes allowing them to use the flexibility of lua property lookup.
|
||||
* Interoperable with a wide range of C++ standard library types, including containers, smart pointers, and modern C++17/20/23 additions.
|
||||
* Written in a clear and easy to debug style.
|
||||
|
||||
## Performance
|
||||
|
||||
LuaBridge3 has been heavily optimized and now competes directly with [sol2](https://github.com/ThePhD/sol2) — one of the fastest C++/Lua binding libraries — across most workloads.
|
||||
|
||||
Benchmarks measure the overhead each library adds on top of the plain Lua C API: the cost of abstracting and wrapping it for C++ use. All libraries are compiled together with the benchmark executable (no separate Lua DLL) so that inlining and link-time optimizations reflect real-world usage scenarios. Every library runs with its maximum safety settings enabled — the numbers represent what you actually ship, not a stripped-down, crash-prone configuration.
|
||||
|
||||
The benchmark suite covers common operations: global and table access, free and member function calls, userdata property access across class hierarchies, shared-pointer ownership, multi-return functions, lambda captures, custom type converters. Each case is run in isolation so the numbers are directly comparable between libraries.
|
||||
|
||||

|
||||
|
||||
## Improvements Over Vanilla LuaBridge
|
||||
|
||||
LuaBridge3 offers a set of improvements compared to vanilla LuaBridge:
|
||||
|
||||
* The only binder library that works with PUC-Lua as well as LuaJIT, Luau and Ravi, wonderful for game development !
|
||||
* Faster runtime execution for most common use cases, playing in the same league as the fastest binders in town.
|
||||
* Can work with both c++ exceptions and without (Works with `-fno-exceptions` and `/EHsc-`).
|
||||
* Full support for capturing lambdas in all namespace and class methods.
|
||||
* Overloaded functions support in Namespace functions, Class constructors, functions and static functions.
|
||||
* Multiple inheritance: `deriveClass<D, A, B, ...>` supports any number of registered base classes.
|
||||
* Supports placement allocation or custom allocations/deallocations of C++ classes exposed to lua.
|
||||
* Lightweight object creation: allow adding lua tables on the stack and register methods and metamethods in them.
|
||||
* Instance metamethods fallbacks via `__index` and `__newindex` in exposed C++ classes.
|
||||
* Static metamethod fallbacks via `__index` and `__newindex` in exposed C++ classes on the class static table.
|
||||
* Custom destructor hook via `addDestructor` (`__destruct` metamethod) called just before the C++ destructor.
|
||||
* Added `std::shared_ptr` to support shared C++/Lua lifetime for types deriving from `std::enable_shared_from_this`.
|
||||
* `std::unique_ptr<T>` supported as an ownership container — Lua gets a non-owning view while C++ retains ownership.
|
||||
* Supports conversion to and from `std::nullptr_t`, `std::byte`, `std::pair`, `std::tuple` and `std::reference_wrapper`.
|
||||
* Supports conversion to and from C style arrays of any supported type.
|
||||
* `void*` and `const void*` are transparently mapped to Lua lightuserdata.
|
||||
* Transparent support of all signed and unsigned integer types up to `int64_t`.
|
||||
* Consistent numeric handling and conversions (signed, unsigned and floats) across all lua versions.
|
||||
* NaN and Inf values pass through floating-point stack conversions without error.
|
||||
* Simplified registration of enum types via the `luabridge::Enum` stack wrapper.
|
||||
* C++20 coroutine integration via `addCoroutine()` and `CppCoroutine<R>`; await Lua threads from C++ with `LuaCoroutine`.
|
||||
* Opt-out handling of safe stack space checks (automatically avoids exhausting lua stack space when pushing values!).
|
||||
* Optional strict stack conversions via `LUABRIDGE_STRICT_STACK_CONVERSIONS` (e.g. `bool` requires an actual boolean, not any truthy value).
|
||||
* Error handler support in Lua calls via `LuaRef::callWithHandler` and `luabridge::callWithHandler`.
|
||||
* `newFunction` free function wraps any C++ callable into a Lua function exposed as a `LuaRef`.
|
||||
* `LuaFunction<Signature>` provides a strongly-typed callable wrapper around a Lua function.
|
||||
* `TypeResult<T>::valueOr(default)` allows safe value extraction with an explicit fallback.
|
||||
* Can safely register and use classes exposed across shared library boundaries.
|
||||
|
||||
### Standard Library Container Support
|
||||
|
||||
Optional headers enable transparent Lua↔C++ conversion for a wide range of STL containers. Include only what you need:
|
||||
|
||||
| Header | Type | Requirement |
|
||||
|--------|------|-------------|
|
||||
| `LuaBridge/Array.h` | `std::array<T,N>` | C++17 |
|
||||
| `LuaBridge/Vector.h` | `std::vector<T>` | C++17 |
|
||||
| `LuaBridge/Deque.h` | `std::deque<T>` | C++17 |
|
||||
| `LuaBridge/ForwardList.h` | `std::forward_list<T>` | C++17 |
|
||||
| `LuaBridge/List.h` | `std::list<T>` | C++17 |
|
||||
| `LuaBridge/Map.h` | `std::map<K,V>` | C++17 |
|
||||
| `LuaBridge/MultiMap.h` | `std::multimap<K,V>` | C++17 |
|
||||
| `LuaBridge/Set.h` | `std::set<K>` | C++17 |
|
||||
| `LuaBridge/UnorderedMap.h` | `std::unordered_map<K,V>` | C++17 |
|
||||
| `LuaBridge/UnorderedMultiMap.h` | `std::unordered_multimap<K,V>` | C++17 |
|
||||
| `LuaBridge/UnorderedSet.h` | `std::unordered_set<K>` | C++17 |
|
||||
| `LuaBridge/Optional.h` | `std::optional<T>` | C++17 |
|
||||
| `LuaBridge/Variant.h` | `std::variant<Ts...>` | C++17 |
|
||||
| `LuaBridge/Any.h` | `std::any` (push-only) | C++17 |
|
||||
| `LuaBridge/Span.h` | `std::span<T>` (push-only) | C++20 |
|
||||
| `LuaBridge/StdExpected.h` | `std::expected<T,E>` | C++23 |
|
||||
| `LuaBridge/FlatMap.h` | `std::flat_map<K,V>` | C++23 |
|
||||
| `LuaBridge/FlatSet.h` | `std::flat_set<K>` | C++23 |
|
||||
|
||||
`std::filesystem::path` is automatically converted to/from a Lua string when C++17 filesystem is available — no additional header required.
|
||||
|
||||
### Modern C++ Feature Detection
|
||||
|
||||
LuaBridge3 auto-detects available C++ standard library features and activates the corresponding support without any manual configuration. Every feature can be force-disabled with a `LUABRIDGE_DISABLE_*` preprocessor flag if needed:
|
||||
|
||||
| Macro | Feature | Standard |
|
||||
|-------|---------|----------|
|
||||
| `LUABRIDGE_HAS_CXX17_FILESYSTEM` | `std::filesystem::path` ↔ string | C++17 |
|
||||
| `LUABRIDGE_HAS_CXX17_ANY` | `std::any` push registry | C++17 |
|
||||
| `LUABRIDGE_HAS_CXX20_SPAN` | `std::span` push support | C++20 |
|
||||
| `LUABRIDGE_HAS_CXX20_RANGES` | `Iterator`/`Range` satisfy `std::ranges` concepts | C++20 |
|
||||
| `LUABRIDGE_HAS_CXX20_COROUTINES` | `CppCoroutine<R>` / `LuaCoroutine` | C++20 |
|
||||
| `LUABRIDGE_HAS_CXX23_EXPECTED` | `std::expected<T,E>` conversion | C++23 |
|
||||
| `LUABRIDGE_HAS_CXX23_FLAT_CONTAINERS` | `std::flat_map` / `std::flat_set` | C++23 |
|
||||
| `LUABRIDGE_HAS_CXX23_MOVE_ONLY_FUNCTION` | `std::move_only_function` as callable | C++23 |
|
||||
|
||||
## Documentation
|
||||
|
||||
Please read the [LuaBridge3 Reference Manual](https://kunitoki.github.io/LuaBridge3/Manual) for more details on the API.
|
||||
|
||||
## Release Notes
|
||||
|
||||
Plase read the [LuaBridge3 Release Notes](https://kunitoki.github.io/LuaBridge3/CHANGES) for more details
|
||||
|
||||
## Installing LuaBridge3 (vcpkg)
|
||||
|
||||
You can download and install LuaBridge3 using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
|
||||
```Powershell or bash
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
./bootstrap-vcpkg.sh # The name of the script should be "./bootstrap-vcpkg.bat" for Powershell
|
||||
./vcpkg integrate install
|
||||
./vcpkg install luabridge3
|
||||
```
|
||||
|
||||
The LuaBridge3 port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
||||
|
||||
### Update vcpkg
|
||||
|
||||
To update the vcpkg port, we need to know the hash of the commit and the sha512 of its downloaded artifact.
|
||||
Starting from the commit hash that needs to be published, download the archived artifact and get the sha512 of it:
|
||||
|
||||
```bash
|
||||
COMMIT_HASH=$(git rev-parse HEAD)
|
||||
|
||||
wget https://github.com/kunitoki/LuaBridge3/archive/${COMMIT_HASH}.tar.gz
|
||||
|
||||
shasum -a 512 ${COMMIT_HASH}.tar.gz
|
||||
# fbdf09e3bd0d4e55c27afa314ff231537b57653b7c3d96b51eac2a41de0c302ed093500298f341cb168695bae5d3094fb67e019e93620c11c7d6f8c86d3802e2 0e17140276d215e98764813078f48731125e4784.tar.gz
|
||||
```
|
||||
Now update the version in https://github.com/microsoft/vcpkg/blob/master/ports/luabridge3/vcpkg.json and the commit hash and sha512 in https://github.com/microsoft/vcpkg/blob/master/ports/luabridge3/portfile.cmake then commit the changes.
|
||||
Enter into vcpkg folder and issue:
|
||||
|
||||
```bash
|
||||
./vcpkg x-add-version --all
|
||||
```
|
||||
|
||||
Commit the changed files and create a Pull Request for vcpkg.
|
||||
|
||||
## Unit Tests
|
||||
|
||||
Unit test build requires a CMake and C++17 compliant compiler.
|
||||
|
||||
These are the unit test targets:
|
||||
* `LuaBridgeTests51` - uses Lua 5.1 in C++ mode
|
||||
* `LuaBridgeTests51Noexcept` - uses Lua 5.1 in C++ mode without exceptions enabled
|
||||
* `LuaBridgeTests51LuaC` - uses Lua 5.1 in C mode
|
||||
* `LuaBridgeTests51LuaCNoexcept` - uses Lua 5.1 in C mode without exceptions enabled
|
||||
* `LuaBridgeTests52` - uses Lua 5.2 in C++ mode
|
||||
* `LuaBridgeTests52Noexcept` - uses Lua 5.2 in C++ mode without exceptions enabled
|
||||
* `LuaBridgeTests52LuaC` - uses Lua 5.2 in C mode
|
||||
* `LuaBridgeTests52LuaCNoexcept` - uses Lua 5.2 in C mode without exceptions enabled
|
||||
* `LuaBridgeTests53` - uses Lua 5.3 in C++ mode
|
||||
* `LuaBridgeTests53Noexcept` - uses Lua 5.3 in C++ mode without exceptions enabled
|
||||
* `LuaBridgeTests53LuaC` - uses Lua 5.3 in C mode
|
||||
* `LuaBridgeTests53LuaCNoexcept` - uses Lua 5.3 in C mode without exceptions enabled
|
||||
* `LuaBridgeTests54` - uses Lua 5.4 in C++ mode
|
||||
* `LuaBridgeTests54Noexcept` - uses Lua 5.4 in C++ mode without exceptions enabled
|
||||
* `LuaBridgeTests54LuaC` - uses Lua 5.4 in C mode
|
||||
* `LuaBridgeTests54LuaCNoexcept` - uses Lua 5.4 in C mode without exceptions enabled
|
||||
* `LuaBridgeTests55` - uses Lua 5.5 in C++ mode
|
||||
* `LuaBridgeTests55Noexcept` - uses Lua 5.5 in C++ mode without exceptions enabled
|
||||
* `LuaBridgeTests55LuaC` - uses Lua 5.5 in C mode
|
||||
* `LuaBridgeTests55LuaCNoexcept` - uses Lua 5.5 in C mode without exceptions enabled
|
||||
* `LuaBridgeTestsLuaJIT` - uses LuaJIT 2.1
|
||||
* `LuaBridgeTestsLuaJITNoexcept` - uses LuaJIT 2.1 without exceptions enabled
|
||||
* `LuaBridgeTestsLuau` - uses Luau
|
||||
* `LuaBridgeTestsRavi` - uses Ravi
|
||||
|
||||
(Luau compiler needs exceptions, so there are no test targets on Luau without exceptions)
|
||||
(Ravi doesn't fully work without exceptions, so there are no test targets on Ravi without exceptions)
|
||||
|
||||
Generate Unix Makefiles and build on Linux:
|
||||
```bash
|
||||
git clone --recursive git@github.com:kunitoki/LuaBridge3.git
|
||||
|
||||
cmake -G "Unix Makefiles" -DCMAKE_CXX_STANDARD=20 -B Build . # Generates Unix Makefiles
|
||||
cmake --build Build -DCMAKE_BUILD_TYPE=Debug
|
||||
# or cmake --build Build -DCMAKE_BUILD_TYPE=Release
|
||||
# or cmake --build Build -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
popd
|
||||
```
|
||||
|
||||
Generate XCode project and build on MacOS:
|
||||
```bash
|
||||
git clone --recursive git@github.com:kunitoki/LuaBridge3.git
|
||||
|
||||
cmake -G Xcode -DCMAKE_CXX_STANDARD=20 -B Build . # Generates XCode project build/LuaBridge.xcodeproj
|
||||
cmake --build Build -DCMAKE_BUILD_TYPE=Debug
|
||||
# or cmake --build Build -DCMAKE_BUILD_TYPE=Release
|
||||
# or cmake --build Build -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
Generate VS2019 solution on Windows:
|
||||
```cmd
|
||||
git clone --recursive git@github.com:kunitoki/LuaBridge3.git
|
||||
|
||||
cmake -G "Visual Studio 16" -DCMAKE_CXX_STANDARD=20 -B Build . # Generates MSVS solution build/LuaBridge.sln
|
||||
cmake --build Build -DCMAKE_BUILD_TYPE=Debug
|
||||
# or cmake --build Build -DCMAKE_BUILD_TYPE=Release
|
||||
# or cmake --build Build -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
## Official Repository
|
||||
|
||||
LuaBridge3 is published under the terms of the [MIT License](https://www.opensource.org/licenses/mit-license.html).
|
||||
|
||||
The original version of LuaBridge3 was written by Nathan Reed. The project has
|
||||
been taken over by Vinnie Falco, who added new functionality, wrote the new
|
||||
documentation, and incorporated contributions from Nigel Atkinson. Then it has
|
||||
been forked from the original https://github.com/vinniefalco/LuaBridge into its
|
||||
own LuaBridge3 repository by kunitoki, and development continued there.
|
||||
|
||||
For questions, comments, or bug reports feel free to open a Github issue
|
||||
or contact kunitoki directly at the email address indicated below.
|
||||
|
||||
Copyright 2020, kunitoki (<kunitoki@gmail.com>)<br>
|
||||
Copyright 2019, Dmitry Tarakanov<br>
|
||||
Copyright 2012, Vinnie Falco (<vinnie.falco@gmail.com>)<br>
|
||||
Copyright 2008, Nigel Atkinson<br>
|
||||
Copyright 2007, Nathan Reed<br>
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
cmake_minimum_required (VERSION 3.10)
|
||||
|
||||
set (LUABRIDGE_HEADERS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/Array.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/Dump.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/List.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/LuaBridge.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/Map.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/Set.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/UnorderedMap.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/Vector.h)
|
||||
source_group ("LuaBridge" FILES ${LUABRIDGE_HEADERS})
|
||||
|
||||
set (LUABRIDGE_DETAIL_HEADERS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/CFunctions.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/ClassInfo.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Config.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Coroutine.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Enum.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Errors.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Expected.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/FlagSet.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/FuncTraits.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Globals.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Invoke.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Iterator.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/LuaException.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/LuaHelpers.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/LuaRef.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Namespace.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Options.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Overload.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Result.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/ScopeGuard.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Stack.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/TypeTraits.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/detail/Userdata.h)
|
||||
source_group ("LuaBridgeDetail" FILES ${LUABRIDGE_DETAIL_HEADERS})
|
||||
|
||||
add_library (LuaBridge INTERFACE)
|
||||
target_sources (LuaBridge INTERFACE
|
||||
${LUABRIDGE_HEADERS}
|
||||
${LUABRIDGE_DETAIL_HEADERS})
|
||||
target_include_directories (LuaBridge INTERFACE .)
|
||||
|
||||
#if (CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||
install(DIRECTORY LuaBridge DESTINATION "include")
|
||||
#endif ()
|
||||
|
||||
if (MSVC AND CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||
add_custom_target (LuaBridgeSources SOURCES
|
||||
${LUABRIDGE_HEADERS}
|
||||
${LUABRIDGE_DETAIL_HEADERS})
|
||||
endif ()
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
#include "detail/Config.h"
|
||||
|
||||
#if LUABRIDGE_HAS_CXX17_ANY
|
||||
|
||||
#include <any>
|
||||
#include <functional>
|
||||
#include <typeindex>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
namespace detail {
|
||||
|
||||
using AnyPushFn = std::function<Result(lua_State*, const std::any&)>;
|
||||
|
||||
inline std::unordered_map<std::type_index, AnyPushFn>& anyPushRegistry()
|
||||
{
|
||||
static std::unordered_map<std::type_index, AnyPushFn> registry;
|
||||
return registry;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Register a push handler for std::any holding type T.
|
||||
*/
|
||||
template <class T>
|
||||
void registerAnyPush(lua_State*)
|
||||
{
|
||||
detail::anyPushRegistry()[std::type_index(typeid(T))] =
|
||||
[](lua_State* L, const std::any& value) -> Result
|
||||
{
|
||||
return Stack<T>::push(L, std::any_cast<const T&>(value));
|
||||
};
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::any` (push-only).
|
||||
*/
|
||||
template <>
|
||||
struct Stack<std::any>
|
||||
{
|
||||
[[nodiscard]] static Result push(lua_State* L, const std::any& value)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 1))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
if (! value.has_value())
|
||||
{
|
||||
lua_pushnil(L);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto& registry = detail::anyPushRegistry();
|
||||
|
||||
auto it = registry.find(std::type_index(value.type()));
|
||||
if (it == registry.end())
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
return it->second(L, value);
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State*, int)
|
||||
{
|
||||
return false; // std::any cannot be detected from Lua side
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
|
||||
#endif // LUABRIDGE_HAS_CXX17_ANY
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2020, Dmitry Tarakanov
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::array`.
|
||||
*/
|
||||
template <class T, std::size_t Size>
|
||||
struct Stack<std::array<T, Size>>
|
||||
{
|
||||
using Type = std::array<T, Size>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& array)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, static_cast<int>(Size), 0);
|
||||
const int tableIndex = lua_gettop(L);
|
||||
|
||||
for (std::size_t i = 0; i < Size; ++i)
|
||||
{
|
||||
auto result = Stack<T>::push(L, array[i]);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_rawseti(L, tableIndex, static_cast<int>(i + 1));
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (!lua_istable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
if (get_length(L, index) != Size)
|
||||
return makeErrorCode(ErrorCode::InvalidTableSizeInCast);
|
||||
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
Type array;
|
||||
|
||||
int absIndex = lua_absindex(L, index);
|
||||
lua_pushnil(L);
|
||||
|
||||
int arrayIndex = 0;
|
||||
while (lua_next(L, absIndex) != 0)
|
||||
{
|
||||
auto item = Stack<T>::get(L, -1);
|
||||
if (!item)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
array[arrayIndex++] = *item;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index) && get_length(L, index) == Size;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// Copyright 2020, Dmitry Tarakanov
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::deque`.
|
||||
*/
|
||||
template <class T, class Allocator>
|
||||
struct Stack<std::deque<T, Allocator>>
|
||||
{
|
||||
using Type = std::deque<T, Allocator>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& deque)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, static_cast<int>(deque.size()), 0);
|
||||
const int tableIndex = lua_gettop(L);
|
||||
|
||||
auto it = deque.cbegin();
|
||||
for (std::size_t i = 1; it != deque.cend(); ++i, ++it)
|
||||
{
|
||||
auto result = Stack<T>::push(L, *it);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_rawseti(L, tableIndex, static_cast<int>(i));
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (!lua_istable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
Type deque;
|
||||
|
||||
int absIndex = lua_absindex(L, index);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, absIndex) != 0)
|
||||
{
|
||||
auto item = Stack<T>::get(L, -1);
|
||||
if (! item)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
deque.emplace_back(*item);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return deque;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2019, Dmitry Tarakanov
|
||||
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
// Copyright 2007, Nathan Reed
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/ClassInfo.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace luabridge {
|
||||
namespace detail {
|
||||
inline void putIndent(std::ostream& stream, unsigned level)
|
||||
{
|
||||
for (unsigned i = 0; i < level; ++i)
|
||||
stream << " ";
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Forward for dumpTable.
|
||||
*/
|
||||
inline void dumpTable(lua_State* L, int index, unsigned maxDepth = 1, unsigned level = 0, bool newLine = true, std::ostream& stream = std::cerr);
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Dump a lua value on the stack.
|
||||
*/
|
||||
inline void dumpValue(lua_State* L, int index, unsigned maxDepth = 1, unsigned level = 0, bool newLine = true, std::ostream& stream = std::cerr)
|
||||
{
|
||||
const int stackTop = lua_gettop(L);
|
||||
const int absIndex = (index > 0) ? index : (index < 0 ? stackTop + index + 1 : 0);
|
||||
const int type = (absIndex < 1 || absIndex > stackTop) ? LUA_TNONE : lua_type(L, index);
|
||||
switch (type)
|
||||
{
|
||||
case LUA_TNIL:
|
||||
stream << "nil";
|
||||
break;
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
stream << (lua_toboolean(L, index) ? "true" : "false");
|
||||
break;
|
||||
|
||||
case LUA_TNUMBER:
|
||||
stream << lua_tonumber(L, index);
|
||||
break;
|
||||
|
||||
case LUA_TSTRING:
|
||||
stream << '"' << lua_tostring(L, index) << '"';
|
||||
break;
|
||||
|
||||
case LUA_TFUNCTION:
|
||||
if (lua_iscfunction(L, index))
|
||||
stream << "cfunction@" << lua_topointer(L, index);
|
||||
else
|
||||
stream << "function@" << lua_topointer(L, index);
|
||||
break;
|
||||
|
||||
case LUA_TTHREAD:
|
||||
stream << "thread@" << lua_tothread(L, index);
|
||||
break;
|
||||
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
stream << "lightuserdata@" << lua_touserdata(L, index);
|
||||
break;
|
||||
|
||||
case LUA_TTABLE:
|
||||
dumpTable(L, index, maxDepth, level, false, stream);
|
||||
break;
|
||||
|
||||
case LUA_TUSERDATA:
|
||||
stream << "userdata@" << lua_touserdata(L, index);
|
||||
break;
|
||||
|
||||
default:
|
||||
stream << lua_typename(L, type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (newLine)
|
||||
stream << '\n';
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Dump a lua table on the stack.
|
||||
*/
|
||||
inline void dumpTable(lua_State* L, int index, unsigned maxDepth, unsigned level, bool newLine, std::ostream& stream)
|
||||
{
|
||||
stream << "table@" << lua_topointer(L, index);
|
||||
|
||||
if (level > maxDepth)
|
||||
{
|
||||
if (newLine)
|
||||
stream << '\n';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
index = lua_absindex(L, index);
|
||||
|
||||
stream << " {";
|
||||
|
||||
int valuesCount = 0;
|
||||
|
||||
lua_pushnil(L); // Initial key
|
||||
while (lua_next(L, index))
|
||||
{
|
||||
stream << '\n';
|
||||
detail::putIndent(stream, level + 1);
|
||||
|
||||
dumpValue(L, -2, maxDepth, level + 1, false, stream); // Key
|
||||
stream << ": ";
|
||||
dumpValue(L, -1, maxDepth, level + 1, false, stream); // Value
|
||||
stream << ",";
|
||||
|
||||
lua_pop(L, 1); // Value
|
||||
|
||||
++valuesCount;
|
||||
}
|
||||
|
||||
if (valuesCount > 0)
|
||||
{
|
||||
stream << '\n';
|
||||
detail::putIndent(stream, level);
|
||||
}
|
||||
|
||||
stream << "}";
|
||||
|
||||
if (newLine)
|
||||
stream << '\n';
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Dump the current stack, optionally recursively.
|
||||
*/
|
||||
inline void dumpState(lua_State* L, unsigned maxDepth = 1, std::ostream& stream = std::cerr)
|
||||
{
|
||||
stream << "----------------------------------------------" << '\n';
|
||||
|
||||
int top = lua_gettop(L);
|
||||
for (int i = 1; i <= top; ++i)
|
||||
{
|
||||
stream << "stack #" << i << " (" << -(top - i + 1) << "): ";
|
||||
|
||||
dumpValue(L, i, maxDepth, 0, true, stream);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace luabridge
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#if LUABRIDGE_HAS_CXX23_FLAT_CONTAINERS
|
||||
|
||||
#include <flat_map>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::flat_map`.
|
||||
*/
|
||||
template <class K, class V, class Compare, class KeyContainer, class MappedContainer>
|
||||
struct Stack<std::flat_map<K, V, Compare, KeyContainer, MappedContainer>>
|
||||
{
|
||||
using Type = std::flat_map<K, V, Compare, KeyContainer, MappedContainer>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& map)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, 0, static_cast<int>(map.size()));
|
||||
|
||||
for (auto it = map.begin(); it != map.end(); ++it)
|
||||
{
|
||||
auto result = Stack<K>::push(L, it->first);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
result = Stack<V>::push(L, it->second);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (!lua_istable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
Type map;
|
||||
|
||||
int absIndex = lua_absindex(L, index);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, absIndex) != 0)
|
||||
{
|
||||
auto value = Stack<V>::get(L, -1);
|
||||
if (! value)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
auto key = Stack<K>::get(L, -2);
|
||||
if (! key)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
map.emplace(*key, *value);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
|
||||
#endif // LUABRIDGE_HAS_CXX23_FLAT_CONTAINERS
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#if LUABRIDGE_HAS_CXX23_FLAT_CONTAINERS
|
||||
|
||||
#include <flat_set>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::flat_set`.
|
||||
*/
|
||||
template <class K, class Compare, class Container>
|
||||
struct Stack<std::flat_set<K, Compare, Container>>
|
||||
{
|
||||
using Type = std::flat_set<K, Compare, Container>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& set)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, 0, static_cast<int>(set.size()));
|
||||
|
||||
auto it = set.cbegin();
|
||||
for (lua_Integer tableIndex = 1; it != set.cend(); ++tableIndex, ++it)
|
||||
{
|
||||
lua_pushinteger(L, tableIndex);
|
||||
|
||||
auto result = Stack<K>::push(L, *it);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (!lua_istable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
Type set;
|
||||
|
||||
int absIndex = lua_absindex(L, index);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, absIndex) != 0)
|
||||
{
|
||||
auto item = Stack<K>::get(L, -1);
|
||||
if (! item)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
set.emplace(*item);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
|
||||
#endif // LUABRIDGE_HAS_CXX23_FLAT_CONTAINERS
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// Copyright 2020, Dmitry Tarakanov
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#include <forward_list>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::forward_list`.
|
||||
*/
|
||||
template <class T, class Allocator>
|
||||
struct Stack<std::forward_list<T, Allocator>>
|
||||
{
|
||||
using Type = std::forward_list<T, Allocator>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& list)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, 0, 0);
|
||||
|
||||
auto it = list.cbegin();
|
||||
for (std::size_t tableIndex = 1; it != list.cend(); ++tableIndex, ++it)
|
||||
{
|
||||
lua_pushinteger(L, static_cast<int>(tableIndex));
|
||||
|
||||
auto result = Stack<T>::push(L, *it);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (!lua_istable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
Type list;
|
||||
auto insertPos = list.before_begin();
|
||||
|
||||
int absIndex = lua_absindex(L, index);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, absIndex) != 0)
|
||||
{
|
||||
auto item = Stack<T>::get(L, -1);
|
||||
if (! item)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
insertPos = list.insert_after(insertPos, *item);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2020, Dmitry Tarakanov
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::array`.
|
||||
*/
|
||||
template <class T, class Allocator>
|
||||
struct Stack<std::list<T, Allocator>>
|
||||
{
|
||||
using Type = std::list<T, Allocator>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& list)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, static_cast<int>(list.size()), 0);
|
||||
const int tableIndex = lua_gettop(L);
|
||||
|
||||
auto it = list.cbegin();
|
||||
for (std::size_t i = 1; it != list.cend(); ++i, ++it)
|
||||
{
|
||||
auto result = Stack<T>::push(L, *it);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_rawseti(L, tableIndex, static_cast<int>(i));
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (!lua_istable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
Type list;
|
||||
|
||||
int absIndex = lua_absindex(L, index);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, absIndex) != 0)
|
||||
{
|
||||
auto item = Stack<T>::get(L, -1);
|
||||
if (! item)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
list.emplace_back(*item);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2020, Dmitry Tarakanov
|
||||
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
// Copyright 2007, Nathan Reed
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
// All #include dependencies are listed here
|
||||
// instead of in the individual header files.
|
||||
|
||||
#define LUABRIDGE_MAJOR_VERSION 3
|
||||
#define LUABRIDGE_MINOR_VERSION 1
|
||||
#define LUABRIDGE_VERSION 301
|
||||
|
||||
#include "detail/Config.h"
|
||||
|
||||
#include "detail/CFunctions.h"
|
||||
#include "detail/ClassInfo.h"
|
||||
#include "detail/Coroutine.h"
|
||||
#include "detail/Enum.h"
|
||||
#include "detail/Errors.h"
|
||||
#include "detail/Expected.h"
|
||||
#include "detail/FlagSet.h"
|
||||
#include "detail/FuncTraits.h"
|
||||
#include "detail/Globals.h"
|
||||
#include "detail/Invoke.h"
|
||||
#include "detail/Iterator.h"
|
||||
#include "detail/LuaException.h"
|
||||
#include "detail/LuaHelpers.h"
|
||||
#include "detail/LuaRef.h"
|
||||
#include "detail/Namespace.h"
|
||||
#include "detail/Options.h"
|
||||
#include "detail/Overload.h"
|
||||
#include "detail/Result.h"
|
||||
#include "detail/ScopeGuard.h"
|
||||
#include "detail/Stack.h"
|
||||
#include "detail/TypeTraits.h"
|
||||
#include "detail/Userdata.h"
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2018, Dmitry Tarakanov
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::map`.
|
||||
*/
|
||||
template <class K, class V, class Compare, class Allocator>
|
||||
struct Stack<std::map<K, V, Compare, Allocator>>
|
||||
{
|
||||
using Type = std::map<K, V, Compare, Allocator>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& map)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, 0, static_cast<int>(map.size()));
|
||||
|
||||
for (auto it = map.begin(); it != map.end(); ++it)
|
||||
{
|
||||
auto result = Stack<K>::push(L, it->first);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
result = Stack<V>::push(L, it->second);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (!lua_istable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
Type map;
|
||||
|
||||
int absIndex = lua_absindex(L, index);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, absIndex) != 0)
|
||||
{
|
||||
auto value = Stack<V>::get(L, -1);
|
||||
if (! value)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
auto key = Stack<K>::get(L, -2);
|
||||
if (! key)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
map.emplace(*key, *value);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::multimap`.
|
||||
*/
|
||||
template <class K, class V, class Compare, class Allocator>
|
||||
struct Stack<std::multimap<K, V, Compare, Allocator>>
|
||||
{
|
||||
using Type = std::multimap<K, V, Compare, Allocator>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& map)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, 0, 0);
|
||||
|
||||
auto it = map.begin();
|
||||
while (it != map.end())
|
||||
{
|
||||
auto result = Stack<K>::push(L, it->first);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
auto range = map.equal_range(it->first);
|
||||
lua_createtable(L, static_cast<int>(std::distance(range.first, range.second)), 0);
|
||||
|
||||
int innerIndex = 1;
|
||||
for (auto innerIt = range.first; innerIt != range.second; ++innerIt, ++innerIndex)
|
||||
{
|
||||
result = Stack<V>::push(L, innerIt->second);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_rawseti(L, -2, innerIndex);
|
||||
}
|
||||
|
||||
lua_settable(L, -3);
|
||||
it = range.second;
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (! lua_istable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
Type map;
|
||||
|
||||
int absIndex = lua_absindex(L, index);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, absIndex) != 0)
|
||||
{
|
||||
auto key = Stack<K>::get(L, -2);
|
||||
if (! key)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
if (! lua_istable(L, -1))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
int innerAbsIndex = lua_absindex(L, -1);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, innerAbsIndex) != 0)
|
||||
{
|
||||
auto value = Stack<V>::get(L, -1);
|
||||
if (! value)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
map.emplace(*key, *value);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::set`.
|
||||
*/
|
||||
template <class K, class Compare, class Allocator>
|
||||
struct Stack<std::set<K, Compare, Allocator>>
|
||||
{
|
||||
using Type = std::set<K, Compare, Allocator>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& set)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, 0, static_cast<int>(set.size()));
|
||||
|
||||
auto it = set.cbegin();
|
||||
for (lua_Integer tableIndex = 1; it != set.cend(); ++tableIndex, ++it)
|
||||
{
|
||||
lua_pushinteger(L, tableIndex);
|
||||
|
||||
auto result = Stack<K>::push(L, *it);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (!lua_istable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
Type set;
|
||||
|
||||
int absIndex = lua_absindex(L, index);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, absIndex) != 0)
|
||||
{
|
||||
auto item = Stack<K>::get(L, -1);
|
||||
if (! item)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
set.emplace(*item);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#if LUABRIDGE_HAS_CXX20_SPAN
|
||||
|
||||
#include <span>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::span` (push-only).
|
||||
*/
|
||||
template <class T, std::size_t Extent>
|
||||
struct Stack<std::span<T, Extent>>
|
||||
{
|
||||
using Type = std::span<T, Extent>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, Type span)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, static_cast<int>(span.size()), 0);
|
||||
const int tableIndex = lua_gettop(L);
|
||||
|
||||
int i = 1;
|
||||
for (const auto& element : span)
|
||||
{
|
||||
auto result = Stack<std::remove_cv_t<T>>::push(L, element);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_rawseti(L, tableIndex, i++);
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class U = T>
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State*, int)
|
||||
{
|
||||
static_assert(sizeof(U) == 0,
|
||||
"std::span cannot be retrieved from Lua — use std::vector<T> to retrieve sequences from Lua");
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
|
||||
#endif // LUABRIDGE_HAS_CXX20_SPAN
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#if LUABRIDGE_HAS_CXX23_EXPECTED
|
||||
|
||||
#include <expected>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::expected` (C++23).
|
||||
*/
|
||||
template <class T, class E>
|
||||
struct Stack<std::expected<T, E>>
|
||||
{
|
||||
using Type = std::expected<T, E>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& value)
|
||||
{
|
||||
if (value.has_value())
|
||||
{
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
auto result = Stack<T>::push(L, *value);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 1))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
lua_pushnil(L);
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
const auto type = lua_type(L, index);
|
||||
if (type == LUA_TNIL || type == LUA_TNONE)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
auto result = Stack<T>::get(L, index);
|
||||
if (! result)
|
||||
return result.error();
|
||||
|
||||
return Type(*result);
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
const auto type = lua_type(L, index);
|
||||
return (type != LUA_TNIL && type != LUA_TNONE) && Stack<T>::isInstance(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
|
||||
#endif // LUABRIDGE_HAS_CXX23_EXPECTED
|
||||
@@ -0,0 +1,86 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2019, Dmitry Tarakanov
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::unordered_map`.
|
||||
*/
|
||||
template <class K, class V, class Hash, class KeyEqual, class Allocator>
|
||||
struct Stack<std::unordered_map<K, V, Hash, KeyEqual, Allocator>>
|
||||
{
|
||||
using Type = std::unordered_map<K, V, Hash, KeyEqual, Allocator>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& map)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, 0, static_cast<int>(map.size()));
|
||||
|
||||
for (auto it = map.begin(); it != map.end(); ++it)
|
||||
{
|
||||
auto result = Stack<K>::push(L, it->first);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
result = Stack<V>::push(L, it->second);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (!lua_istable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
Type map;
|
||||
|
||||
int absIndex = lua_absindex(L, index);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, absIndex) != 0)
|
||||
{
|
||||
auto value = Stack<V>::get(L, -1);
|
||||
if (! value)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
auto key = Stack<K>::get(L, -2);
|
||||
if (! key)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
map.emplace(*key, *value);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
@@ -0,0 +1,107 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::unordered_multimap`.
|
||||
*/
|
||||
template <class K, class V, class Hash, class KeyEqual, class Allocator>
|
||||
struct Stack<std::unordered_multimap<K, V, Hash, KeyEqual, Allocator>>
|
||||
{
|
||||
using Type = std::unordered_multimap<K, V, Hash, KeyEqual, Allocator>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& map)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, 0, 0);
|
||||
|
||||
auto it = map.begin();
|
||||
while (it != map.end())
|
||||
{
|
||||
auto result = Stack<K>::push(L, it->first);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
auto range = map.equal_range(it->first);
|
||||
lua_createtable(L, static_cast<int>(std::distance(range.first, range.second)), 0);
|
||||
|
||||
int innerIndex = 1;
|
||||
for (auto innerIt = range.first; innerIt != range.second; ++innerIt, ++innerIndex)
|
||||
{
|
||||
result = Stack<V>::push(L, innerIt->second);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_rawseti(L, -2, innerIndex);
|
||||
}
|
||||
|
||||
lua_settable(L, -3);
|
||||
it = range.second;
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (! lua_istable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
Type map;
|
||||
|
||||
int absIndex = lua_absindex(L, index);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, absIndex) != 0)
|
||||
{
|
||||
auto key = Stack<K>::get(L, -2);
|
||||
if (! key)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
if (! lua_istable(L, -1))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
int innerAbsIndex = lua_absindex(L, -1);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, innerAbsIndex) != 0)
|
||||
{
|
||||
auto value = Stack<V>::get(L, -1);
|
||||
if (! value)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
map.emplace(*key, *value);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
@@ -0,0 +1,80 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::unordered_set`.
|
||||
*/
|
||||
template <class K, class Hash, class KeyEqual, class Allocator>
|
||||
struct Stack<std::unordered_set<K, Hash, KeyEqual, Allocator>>
|
||||
{
|
||||
using Type = std::unordered_set<K, Hash, KeyEqual, Allocator>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& set)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, 0, static_cast<int>(set.size()));
|
||||
|
||||
auto it = set.cbegin();
|
||||
for (lua_Integer tableIndex = 1; it != set.cend(); ++tableIndex, ++it)
|
||||
{
|
||||
lua_pushinteger(L, tableIndex);
|
||||
|
||||
auto result = Stack<K>::push(L, *it);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (!lua_istable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
Type set;
|
||||
|
||||
int absIndex = lua_absindex(L, index);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, absIndex) != 0)
|
||||
{
|
||||
auto item = Stack<K>::get(L, -1);
|
||||
if (! item)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
set.emplace(*item);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::variant`.
|
||||
*/
|
||||
template <class... Args>
|
||||
struct Stack<std::variant<Args...>>
|
||||
{
|
||||
using Type = std::variant<Args...>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& variant)
|
||||
{
|
||||
return std::visit([L](const auto& value) { return Stack<std::decay_t<decltype(value)>>::push(L, value); }, variant);
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
return tryGet<Args...>(L, index);
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return (Stack<Args>::isInstance(L, index) || ...);
|
||||
}
|
||||
|
||||
private:
|
||||
template <class T, class... Rest>
|
||||
[[nodiscard]] static TypeResult<Type> tryGet(lua_State* L, int index)
|
||||
{
|
||||
if (auto value = Stack<T>::get(L, index))
|
||||
{
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
return Type{ std::in_place_type<T>, std::move(*value) };
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
if constexpr (sizeof...(Rest) > 0)
|
||||
return tryGet<Rest...>(L, index);
|
||||
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Stack specialization for `std::monostate`.
|
||||
*/
|
||||
template <>
|
||||
struct Stack<std::monostate>
|
||||
{
|
||||
using Type = std::monostate;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type&)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 1))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
lua_pushnil(L);
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (lua_isnoneornil(L, index))
|
||||
return Type{};
|
||||
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_isnoneornil(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2018, Dmitry Tarakanov
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/Stack.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Stack specialization for `std::vector`.
|
||||
*/
|
||||
template <class T, class Allocator>
|
||||
struct Stack<std::vector<T, Allocator>>
|
||||
{
|
||||
using Type = std::vector<T, Allocator>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, const Type& vector)
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(L, 3))
|
||||
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
||||
#endif
|
||||
|
||||
StackRestore stackRestore(L);
|
||||
|
||||
lua_createtable(L, static_cast<int>(vector.size()), 0);
|
||||
const int tableIndex = lua_gettop(L);
|
||||
|
||||
for (std::size_t i = 0; i < vector.size(); ++i)
|
||||
{
|
||||
auto result = Stack<T>::push(L, vector[i]);
|
||||
if (! result)
|
||||
return result;
|
||||
|
||||
lua_rawseti(L, tableIndex, static_cast<int>(i + 1));
|
||||
}
|
||||
|
||||
stackRestore.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
||||
{
|
||||
if (!lua_istable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
Type vector;
|
||||
vector.reserve(static_cast<std::size_t>(get_length(L, index)));
|
||||
|
||||
int absIndex = lua_absindex(L, index);
|
||||
lua_pushnil(L);
|
||||
|
||||
while (lua_next(L, absIndex) != 0)
|
||||
{
|
||||
auto item = Stack<T>::get(L, -1);
|
||||
if (! item)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
vector.emplace_back(*item);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_istable(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
+3015
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,259 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2020, Dmitry Tarakanov
|
||||
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#if defined __clang__ || defined __GNUC__
|
||||
#define LUABRIDGE_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
#define LUABRIDGE_PRETTY_FUNCTION_PREFIX '='
|
||||
#define LUABRIDGE_PRETTY_FUNCTION_SUFFIX ']'
|
||||
#elif defined _MSC_VER
|
||||
#define LUABRIDGE_PRETTY_FUNCTION __FUNCSIG__
|
||||
#define LUABRIDGE_PRETTY_FUNCTION_PREFIX '<'
|
||||
#define LUABRIDGE_PRETTY_FUNCTION_SUFFIX '>'
|
||||
#endif
|
||||
|
||||
namespace luabridge {
|
||||
namespace detail {
|
||||
|
||||
[[nodiscard]] constexpr auto fnv1a(const char* s, std::size_t count) noexcept
|
||||
{
|
||||
uint32_t seed = 2166136261u;
|
||||
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
seed = static_cast<uint32_t>(static_cast<uint32_t>(seed ^ static_cast<uint8_t>(*s++)) * 16777619u);
|
||||
|
||||
if constexpr (sizeof(void*) == 8)
|
||||
return static_cast<uint64_t>(seed);
|
||||
else
|
||||
return seed;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
[[nodiscard]] static constexpr auto typeName(T* = nullptr) noexcept
|
||||
{
|
||||
constexpr std::string_view prettyName{ LUABRIDGE_PRETTY_FUNCTION };
|
||||
|
||||
constexpr auto first = prettyName.find_first_not_of(' ', prettyName.find_first_of(LUABRIDGE_PRETTY_FUNCTION_PREFIX) + 1);
|
||||
|
||||
return prettyName.substr(first, prettyName.find_last_of(LUABRIDGE_PRETTY_FUNCTION_SUFFIX) - first);
|
||||
}
|
||||
|
||||
template <class T, auto = typeName<T>().find_first_of('.')>
|
||||
[[nodiscard]] static constexpr auto typeHash(T* = nullptr) noexcept
|
||||
{
|
||||
constexpr auto stripped = typeName<T>();
|
||||
|
||||
return fnv1a(stripped.data(), stripped.size());
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief A unique key for the exceptions in the registry.
|
||||
*/
|
||||
[[nodiscard]] inline void* getExceptionsKey() noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(0xc7);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief A unique key for a type name in a metatable.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getTypeKey() noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(0x71);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief The key of a const table in another metatable.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getConstKey() noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(0xc07);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief The key of a class table in another metatable.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getClassKey() noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(0xc1a);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief The key of a class options table in another metatable.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getClassOptionsKey() noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(0xc2b);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief The key of a type identity tag in class/const metatables.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getTypeIdentityKey() noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(0xc2c);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief The key of a propget table in another metatable.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getPropgetKey() noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(0x6e7);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief The key of a propset table in another metatable.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getPropsetKey() noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(0x5e7);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief The key of a static table in another metatable.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getStaticKey() noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(0x57a);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief The key of a parent table in another metatable.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getParentKey() noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(0xdad);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief The key of a cast offset table in a derived class metatable.
|
||||
*
|
||||
* Maps base class registry keys to byte offsets for pointer adjustment when converting
|
||||
* a derived class pointer to a base class pointer in multiple inheritance scenarios.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getCastTableKey() noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(0xca57);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* The key of the index fall back in another metatable.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getIndexFallbackKey()
|
||||
{
|
||||
return reinterpret_cast<void*>(0x81ca);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const void* getIndexExtensibleKey()
|
||||
{
|
||||
return reinterpret_cast<void*>(0x81cb);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* The key of the new index fall back in another metatable.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getNewIndexFallbackKey()
|
||||
{
|
||||
return reinterpret_cast<void*>(0x8107);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const void* getNewIndexExtensibleKey()
|
||||
{
|
||||
return reinterpret_cast<void*>(0x8108);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief The key of a ConverterRegistry userdata in a class metatable.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getConvertersKey() noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(0xc0de);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* The key of the static index fall back in another metatable.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getStaticIndexFallbackKey()
|
||||
{
|
||||
return reinterpret_cast<void*>(0x81cc);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* The key of the static new index fall back in another metatable.
|
||||
*/
|
||||
[[nodiscard]] inline const void* getStaticNewIndexFallbackKey()
|
||||
{
|
||||
return reinterpret_cast<void*>(0x8109);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Get the key for the static table in the Lua registry.
|
||||
*
|
||||
* The static table holds the static data members, static properties, and static member functions for a class.
|
||||
*/
|
||||
template <class T>
|
||||
[[nodiscard]] const void* getStaticRegistryKey() noexcept
|
||||
{
|
||||
static auto value = typeHash<T>();
|
||||
|
||||
return reinterpret_cast<void*>(value);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Get the key for the class table in the Lua registry.
|
||||
*
|
||||
* The class table holds the data members, properties, and member functions of a class. Read-only data and properties, and const
|
||||
* member functions are also placed here (to save a lookup in the const table).
|
||||
*/
|
||||
template <class T>
|
||||
[[nodiscard]] const void* getClassRegistryKey() noexcept
|
||||
{
|
||||
static auto value = typeHash<T>() ^ 1;
|
||||
|
||||
return reinterpret_cast<void*>(value);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Get the key for the const table in the Lua registry.
|
||||
*
|
||||
* The const table holds read-only data members and properties, and const member functions of a class.
|
||||
*/
|
||||
template <class T>
|
||||
[[nodiscard]] const void* getConstRegistryKey() noexcept
|
||||
{
|
||||
static auto value = typeHash<T>() ^ 2;
|
||||
|
||||
return reinterpret_cast<void*>(value);
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace luabridge
|
||||
+258
@@ -0,0 +1,258 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2020, Dmitry Tarakanov
|
||||
// Copyright 2019, George Tokmaji
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#if __has_include(<version>)
|
||||
#include <version>
|
||||
#endif
|
||||
|
||||
#if !(__cplusplus >= 201703L || (defined(_MSC_VER) && _HAS_CXX17))
|
||||
#error LuaBridge 3 requires a compliant C++17 compiler, or C++17 has not been enabled !
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 202302L || (defined(_MSC_VER) && _HAS_CXX23)
|
||||
#define LUABRIDGE_CXX23_OR_GREATER 1
|
||||
#elif __cplusplus >= 202002L || (defined(_MSC_VER) && _HAS_CXX20)
|
||||
#define LUABRIDGE_CXX20_OR_GREATER 1
|
||||
#endif
|
||||
|
||||
#if defined(LUAU_FASTMATH_BEGIN)
|
||||
#define LUABRIDGE_ON_LUAU 1
|
||||
#elif defined(LUAJIT_VERSION)
|
||||
#define LUABRIDGE_ON_LUAJIT 1
|
||||
#elif defined(RAVI_OPTION_STRING2)
|
||||
#define LUABRIDGE_ON_RAVI 1
|
||||
#elif defined(LUA_VERSION_NUM)
|
||||
#define LUABRIDGE_ON_LUA 1
|
||||
#else
|
||||
#error "Lua headers must be included prior to LuaBridge ones"
|
||||
#endif
|
||||
|
||||
#if !defined(LUABRIDGE_HAS_EXCEPTIONS)
|
||||
#if defined(_MSC_VER)
|
||||
#if _CPPUNWIND || _HAS_EXCEPTIONS
|
||||
#define LUABRIDGE_HAS_EXCEPTIONS 1
|
||||
#else
|
||||
#define LUABRIDGE_HAS_EXCEPTIONS 0
|
||||
#endif
|
||||
#elif defined(__clang__)
|
||||
#if __EXCEPTIONS && __has_feature(cxx_exceptions)
|
||||
#define LUABRIDGE_HAS_EXCEPTIONS 1
|
||||
#else
|
||||
#define LUABRIDGE_HAS_EXCEPTIONS 0
|
||||
#endif
|
||||
#elif defined(__GNUC__)
|
||||
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS)
|
||||
#define LUABRIDGE_HAS_EXCEPTIONS 1
|
||||
#else
|
||||
#define LUABRIDGE_HAS_EXCEPTIONS 0
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
#define LUABRIDGE_IF_EXCEPTIONS(...) __VA_ARGS__
|
||||
#define LUABRIDGE_IF_NO_EXCEPTIONS(...)
|
||||
#else
|
||||
#define LUABRIDGE_IF_EXCEPTIONS(...)
|
||||
#define LUABRIDGE_IF_NO_EXCEPTIONS(...) __VA_ARGS__
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#define LUABRIDGE_NO_SANITIZE(x) __attribute__((no_sanitize(x)))
|
||||
#else
|
||||
#define LUABRIDGE_NO_SANITIZE(x)
|
||||
#endif
|
||||
|
||||
#if defined(__OBJC__)
|
||||
#define LUABRIDGE_ON_OBJECTIVE_C 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable safe stack checks to avoid lua stack overflow when pushing values on the stack.
|
||||
*
|
||||
* @note Default is enabled.
|
||||
*/
|
||||
#if !defined(LUABRIDGE_SAFE_STACK_CHECKS)
|
||||
#define LUABRIDGE_SAFE_STACK_CHECKS 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable strict stack conversions to enforce exact type matching when getting values from the stack.
|
||||
*
|
||||
* When enabled:
|
||||
* - `Stack<bool>::get` only accepts `LUA_TBOOLEAN` (nil is not convertible to bool).
|
||||
* - Integer `Stack` specializations only accept Lua integer values (not floats with integer representation, on Lua 5.3+).
|
||||
* - `Stack<std::string>::get` only accepts `LUA_TSTRING` (numbers are not coerced to strings).
|
||||
*
|
||||
* When disabled (default), a more permissive conversion is used:
|
||||
* - `Stack<bool>::get` accepts `LUA_TBOOLEAN` and `LUA_TNIL` (nil converts to false).
|
||||
* - Integer `Stack` specializations accept any `LUA_TNUMBER` that can be represented as the target integer type.
|
||||
* - `Stack<std::string>::get` accepts `LUA_TSTRING` and `LUA_TNUMBER` (numbers are coerced to strings).
|
||||
*
|
||||
* @note Default is disabled.
|
||||
*/
|
||||
#if !defined(LUABRIDGE_STRICT_STACK_CONVERSIONS)
|
||||
#define LUABRIDGE_STRICT_STACK_CONVERSIONS 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable safe exception handling when lua is compiled as `C` and exceptions raise during execution of registered `lua_CFunction`.
|
||||
*
|
||||
* This is a problem that manifests when exceptions are leaking a CFunction when lua is compiled as `C` because the library will then longjmp
|
||||
* instead of correctly unwinding the exception into C++ land. If you have exceptions enabled and are compiling lua as `C` and you are getting random
|
||||
* crashes when invoking CFunctions that throw, you have two options: or you catch exceptions in your CFunction and raise a `lua_error` instead
|
||||
* or you enable this macro, which will add a safe indirection doing exceptions catching and raising when invoking your registered CFunction.
|
||||
*
|
||||
* @warning When enabled, some performance degradation is to be expected when invoking registered `lua_CFunction` through the library.
|
||||
*
|
||||
* @note Default is disabled, can only be enabled when `LUABRIDGE_HAS_EXCEPTIONS` is 1.
|
||||
*/
|
||||
#if !defined(LUABRIDGE_SAFE_LUA_C_EXCEPTION_HANDLING)
|
||||
#define LUABRIDGE_SAFE_LUA_C_EXCEPTION_HANDLING 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Control raising when an unregistered class is used.
|
||||
*
|
||||
* @note Default is enabled when exceptions are enabled, disabled otherwise.
|
||||
*/
|
||||
#if !defined(LUABRIDGE_RAISE_UNREGISTERED_CLASS_USAGE)
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
#define LUABRIDGE_RAISE_UNREGISTERED_CLASS_USAGE 1
|
||||
#else
|
||||
#define LUABRIDGE_RAISE_UNREGISTERED_CLASS_USAGE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Control the assertion mechanism used by the library.
|
||||
*
|
||||
* @note By default, assertions are enabled in debug builds and disabled in release builds. Define LUABRIDGE_FORCE_ASSERT_RELEASE to enable assertions even in release builds.
|
||||
*/
|
||||
#if !defined(LUABRIDGE_ASSERT)
|
||||
#if defined(NDEBUG) && !defined(LUABRIDGE_FORCE_ASSERT_RELEASE)
|
||||
#define LUABRIDGE_ASSERT(expr) ((void)(expr))
|
||||
#else
|
||||
#define LUABRIDGE_ASSERT(expr) assert(expr)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable C++17 filesystem library support.
|
||||
*
|
||||
* Requires C++17 and the filesystem header to be available.
|
||||
* Define LUABRIDGE_DISABLE_CXX17_FILESYSTEM to force-disable even when available.
|
||||
*/
|
||||
#if !defined(LUABRIDGE_HAS_CXX17_FILESYSTEM)
|
||||
#if !defined(LUABRIDGE_DISABLE_CXX17_FILESYSTEM) && __has_include(<filesystem>) && defined(__cpp_lib_filesystem)
|
||||
#define LUABRIDGE_HAS_CXX17_FILESYSTEM 1
|
||||
#else
|
||||
#define LUABRIDGE_HAS_CXX17_FILESYSTEM 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable C++17 any library support.
|
||||
*
|
||||
* Requires C++17 and the any header to be available.
|
||||
* Define LUABRIDGE_DISABLE_CXX17_ANY to force-disable even when available.
|
||||
*/
|
||||
#if !defined(LUABRIDGE_HAS_CXX17_ANY)
|
||||
#if !defined(LUABRIDGE_DISABLE_CXX17_ANY) && __has_include(<any>) && defined(__cpp_lib_any)
|
||||
#define LUABRIDGE_HAS_CXX17_ANY 1
|
||||
#else
|
||||
#define LUABRIDGE_HAS_CXX17_ANY 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable C++20 span library support.
|
||||
*
|
||||
* Requires C++20 and the span header to be available.
|
||||
* Define LUABRIDGE_DISABLE_CXX20_SPAN to force-disable even when available.
|
||||
*/
|
||||
#if !defined(LUABRIDGE_HAS_CXX20_SPAN)
|
||||
#if !defined(LUABRIDGE_DISABLE_CXX20_SPAN) && LUABRIDGE_CXX20_OR_GREATER && __has_include(<span>) && defined(__cpp_lib_span)
|
||||
#define LUABRIDGE_HAS_CXX20_SPAN 1
|
||||
#else
|
||||
#define LUABRIDGE_HAS_CXX20_SPAN 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable C++20 ranges library support.
|
||||
*
|
||||
* Requires C++20 and the ranges header to be available.
|
||||
* Define LUABRIDGE_DISABLE_CXX20_RANGES to force-disable even when available.
|
||||
*/
|
||||
#if !defined(LUABRIDGE_HAS_CXX20_RANGES)
|
||||
#if !defined(LUABRIDGE_DISABLE_CXX20_RANGES) && LUABRIDGE_CXX20_OR_GREATER && defined(__cpp_lib_ranges)
|
||||
#define LUABRIDGE_HAS_CXX20_RANGES 1
|
||||
#else
|
||||
#define LUABRIDGE_HAS_CXX20_RANGES 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable C++20 coroutine integration with Lua coroutines.
|
||||
*
|
||||
* Requires C++20 and Lua 5.2+ (lua_yieldk). Not supported on Lua 5.1, LuaJIT, or Luau.
|
||||
* Define LUABRIDGE_DISABLE_CXX20_COROUTINES to force-disable even when C++20 is available.
|
||||
*/
|
||||
#if !defined(LUABRIDGE_HAS_CXX20_COROUTINES)
|
||||
#if !defined(LUABRIDGE_DISABLE_CXX20_COROUTINES) && LUABRIDGE_CXX20_OR_GREATER && !(LUABRIDGE_ON_LUAU || LUABRIDGE_ON_LUAJIT || LUABRIDGE_ON_RAVI || LUA_VERSION_NUM < 502)
|
||||
#define LUABRIDGE_HAS_CXX20_COROUTINES 1
|
||||
#else
|
||||
#define LUABRIDGE_HAS_CXX20_COROUTINES 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable C++23 expected library support.
|
||||
*
|
||||
* Requires C++23 and the expected header to be available.
|
||||
* Define LUABRIDGE_DISABLE_CXX23_EXPECTED to force-disable even when available.
|
||||
*/
|
||||
#if !defined(LUABRIDGE_HAS_CXX23_EXPECTED)
|
||||
#if !defined(LUABRIDGE_DISABLE_CXX23_EXPECTED) && LUABRIDGE_CXX23_OR_GREATER && __has_include(<expected>) && defined(__cpp_lib_expected)
|
||||
#define LUABRIDGE_HAS_CXX23_EXPECTED 1
|
||||
#else
|
||||
#define LUABRIDGE_HAS_CXX23_EXPECTED 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable C++23 flat containers library support.
|
||||
*
|
||||
* Requires C++23 and the flat_map header to be available.
|
||||
* Define LUABRIDGE_DISABLE_CXX23_FLAT_CONTAINERS to force-disable even when available.
|
||||
*/
|
||||
#if !defined(LUABRIDGE_HAS_CXX23_FLAT_CONTAINERS)
|
||||
#if !defined(LUABRIDGE_DISABLE_CXX23_FLAT_CONTAINERS) && LUABRIDGE_CXX23_OR_GREATER && __has_include(<flat_map>) && __has_include(<flat_set>) && defined(__cpp_lib_flat_map)
|
||||
#define LUABRIDGE_HAS_CXX23_FLAT_CONTAINERS 1
|
||||
#else
|
||||
#define LUABRIDGE_HAS_CXX23_FLAT_CONTAINERS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable C++23 move_only_function library support.
|
||||
*
|
||||
* Requires C++23 and move_only_function to be available.
|
||||
* Define LUABRIDGE_DISABLE_CXX23_MOVE_ONLY_FUNCTION to force-disable even when available.
|
||||
*/
|
||||
#if !defined(LUABRIDGE_HAS_CXX23_MOVE_ONLY_FUNCTION)
|
||||
#if !defined(LUABRIDGE_DISABLE_CXX23_MOVE_ONLY_FUNCTION) && LUABRIDGE_CXX23_OR_GREATER && defined(__cpp_lib_move_only_function)
|
||||
#define LUABRIDGE_HAS_CXX23_MOVE_ONLY_FUNCTION 1
|
||||
#else
|
||||
#define LUABRIDGE_HAS_CXX23_MOVE_ONLY_FUNCTION 0
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,183 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ClassInfo.h"
|
||||
#include "Errors.h"
|
||||
#include "LuaHelpers.h"
|
||||
#include "Result.h"
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
// Forward declaration.
|
||||
template <class T, class>
|
||||
struct Stack;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Opt-in trait for enabling custom type converters for type T.
|
||||
*
|
||||
* Specialize with enabled = true so that Stack<T>::get consults the metatable
|
||||
* converter registry as a Phase 3 fallback after Phase 1 (exact match) and
|
||||
* Phase 2 (inheritance) both fail.
|
||||
*
|
||||
* Example:
|
||||
* template <> struct luabridge::StackConversion<MyType> { static constexpr bool enabled = true; };
|
||||
*/
|
||||
template <class T>
|
||||
struct StackConversion
|
||||
{
|
||||
static constexpr bool enabled = false;
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief User-defined conversion hook from source type From to target type To.
|
||||
*
|
||||
* Specialize this template for each (To, From) pair and provide:
|
||||
* static To convert(const From& from);
|
||||
*
|
||||
* Example:
|
||||
* template <>
|
||||
* struct luabridge::StackConverter<Vec3, glm::vec3> {
|
||||
* static Vec3 convert(const glm::vec3& v) { return {v.x, v.y, v.z}; }
|
||||
* };
|
||||
*/
|
||||
template <class To, class From>
|
||||
struct StackConverter;
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct ConverterRegistry
|
||||
{
|
||||
std::unordered_map<const void*, const void*> converters;
|
||||
};
|
||||
|
||||
inline ConverterRegistry* getOrCreateConverterRegistry(lua_State* L, int metatableIdx)
|
||||
{
|
||||
const int absIdx = lua_absindex(L, metatableIdx);
|
||||
|
||||
lua_rawgetp_x(L, absIdx, getConvertersKey());
|
||||
if (lua_isuserdata(L, -1) && !lua_islightuserdata(L, -1))
|
||||
{
|
||||
auto* reg = align<ConverterRegistry>(lua_touserdata(L, -1));
|
||||
lua_pop(L, 1);
|
||||
return reg;
|
||||
}
|
||||
lua_pop(L, 1); // pop nil or unexpected value
|
||||
|
||||
// Create ConverterRegistry as an aligned Lua full userdata with automatic __gc
|
||||
lua_newuserdata_aligned<ConverterRegistry>(L);
|
||||
auto* reg = align<ConverterRegistry>(lua_touserdata(L, -1));
|
||||
|
||||
// Store the userdata in the class metatable
|
||||
lua_pushvalue(L, -1); // dup userdata
|
||||
lua_rawsetp_x(L, absIdx, getConvertersKey()); // store, pops dup
|
||||
lua_pop(L, 1); // pop the original userdata
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class ConverterConstRef
|
||||
{
|
||||
public:
|
||||
explicit ConverterConstRef(const T& value) noexcept
|
||||
: m_ref(std::addressof(value))
|
||||
{
|
||||
}
|
||||
|
||||
explicit ConverterConstRef(T&& value) noexcept(std::is_nothrow_move_constructible_v<T>)
|
||||
: m_value(std::move(value))
|
||||
, m_ref(std::addressof(*m_value))
|
||||
{
|
||||
}
|
||||
|
||||
ConverterConstRef(ConverterConstRef&& other) noexcept(std::is_nothrow_move_constructible_v<T>)
|
||||
: m_value(std::move(other.m_value))
|
||||
, m_ref(m_value.has_value() ? std::addressof(*m_value) : other.m_ref)
|
||||
{
|
||||
}
|
||||
|
||||
ConverterConstRef(const ConverterConstRef& other)
|
||||
: m_value(other.m_value)
|
||||
, m_ref(m_value.has_value() ? std::addressof(*m_value) : other.m_ref)
|
||||
{
|
||||
}
|
||||
|
||||
ConverterConstRef& operator=(ConverterConstRef&& other) noexcept(std::is_nothrow_move_assignable_v<T>)
|
||||
{
|
||||
m_value = std::move(other.m_value);
|
||||
m_ref = m_value.has_value() ? std::addressof(*m_value) : other.m_ref;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConverterConstRef& operator=(const ConverterConstRef& other)
|
||||
{
|
||||
m_value = other.m_value;
|
||||
m_ref = m_value.has_value() ? std::addressof(*m_value) : other.m_ref;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator const T&() const noexcept
|
||||
{
|
||||
return *m_ref;
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<T> m_value;
|
||||
const T* m_ref = nullptr;
|
||||
};
|
||||
|
||||
template <class To>
|
||||
TypeResult<To> tryConvertFromRegisteredConverter(lua_State* L, int index)
|
||||
{
|
||||
using FnType = TypeResult<To>(*)(lua_State*, int);
|
||||
|
||||
if (! lua_getmetatable(L, index))
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
lua_rawgetp_x(L, -1, detail::getConvertersKey());
|
||||
if (lua_isuserdata(L, -1) && !lua_islightuserdata(L, -1))
|
||||
{
|
||||
auto* reg = align<detail::ConverterRegistry>(lua_touserdata(L, -1));
|
||||
lua_pop(L, 2); // registry userdata + metatable
|
||||
|
||||
auto it = reg->converters.find(detail::getClassRegistryKey<To>());
|
||||
if (it != reg->converters.end() && it->second)
|
||||
{
|
||||
const auto* fn = static_cast<const FnType*>(it->second);
|
||||
return (*fn)(L, index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pop(L, 2); // nil/other + metatable
|
||||
}
|
||||
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
TypeResult<To> convertFromStack(lua_State* L, int index)
|
||||
{
|
||||
auto result = detail::Userdata::get<From>(L, index, true);
|
||||
|
||||
if (!result || !*result)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
return StackConverter<To, From>::convert(**result);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace luabridge
|
||||
@@ -0,0 +1,492 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2026, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
#include "CFunctions.h"
|
||||
#include "Errors.h"
|
||||
#include "LuaHelpers.h"
|
||||
#include "Stack.h"
|
||||
|
||||
#if LUABRIDGE_HAS_CXX20_COROUTINES
|
||||
|
||||
#if LUABRIDGE_ON_LUAJIT || LUA_VERSION_NUM == 501 || LUABRIDGE_ON_LUAU
|
||||
#ifndef LUABRIDGE_DISABLE_COROUTINE_INTEGRATION
|
||||
#error "C++20 coroutine integration requires Lua 5.2+ with lua_yieldk support. Define LUABRIDGE_DISABLE_COROUTINE_INTEGRATION to suppress this error."
|
||||
#endif
|
||||
#else
|
||||
|
||||
#include <coroutine>
|
||||
#include <exception>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief A C++20 coroutine type callable from Lua.
|
||||
*
|
||||
* Register instances via Namespace::addCoroutine(). When called from Lua, the coroutine body
|
||||
* runs until the first co_yield (which yields a value back to Lua) or co_return (which
|
||||
* returns a final value). Subsequent Lua resumes continue the body from the last suspension point.
|
||||
*
|
||||
* @tparam R The type yielded/returned by the coroutine. May be void.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* luabridge::getGlobalNamespace(L)
|
||||
* .addCoroutine("range", [](int start, int stop) -> luabridge::CppCoroutine<int> {
|
||||
* for (int i = start; i < stop; ++i)
|
||||
* co_yield i;
|
||||
* co_return -1;
|
||||
* });
|
||||
* @endcode
|
||||
*
|
||||
* @note Requires Lua 5.2+ (lua_yieldk). Not supported on Lua 5.1, LuaJIT, or Luau.
|
||||
* @note Not thread-safe. Must be driven from a single OS thread.
|
||||
*/
|
||||
template <class R>
|
||||
struct CppCoroutine
|
||||
{
|
||||
struct promise_type
|
||||
{
|
||||
lua_State* L = nullptr;
|
||||
int nresults = 0;
|
||||
bool is_done = false;
|
||||
std::exception_ptr exception;
|
||||
|
||||
std::suspend_always initial_suspend() noexcept { return {}; }
|
||||
std::suspend_always final_suspend() noexcept { return {}; }
|
||||
|
||||
void unhandled_exception() noexcept
|
||||
{
|
||||
exception = std::current_exception();
|
||||
}
|
||||
|
||||
std::suspend_always yield_value(const R& value)
|
||||
{
|
||||
nresults = 0;
|
||||
if (L)
|
||||
{
|
||||
auto result = Stack<R>::push(L, value);
|
||||
if (result)
|
||||
nresults = 1;
|
||||
else
|
||||
exception = std::make_exception_ptr(std::system_error(result.error()));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::suspend_always yield_value(R&& value)
|
||||
{
|
||||
nresults = 0;
|
||||
if (L)
|
||||
{
|
||||
auto result = Stack<R>::push(L, std::move(value));
|
||||
if (result)
|
||||
nresults = 1;
|
||||
else
|
||||
exception = std::make_exception_ptr(std::system_error(result.error()));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void return_value(const R& value)
|
||||
{
|
||||
nresults = 0;
|
||||
if (L)
|
||||
{
|
||||
auto result = Stack<R>::push(L, value);
|
||||
if (result)
|
||||
nresults = 1;
|
||||
else
|
||||
exception = std::make_exception_ptr(std::system_error(result.error()));
|
||||
}
|
||||
is_done = true;
|
||||
}
|
||||
|
||||
void return_value(R&& value)
|
||||
{
|
||||
nresults = 0;
|
||||
if (L)
|
||||
{
|
||||
auto result = Stack<R>::push(L, std::move(value));
|
||||
if (result)
|
||||
nresults = 1;
|
||||
else
|
||||
exception = std::make_exception_ptr(std::system_error(result.error()));
|
||||
}
|
||||
is_done = true;
|
||||
}
|
||||
|
||||
CppCoroutine get_return_object()
|
||||
{
|
||||
return CppCoroutine{ std::coroutine_handle<promise_type>::from_promise(*this) };
|
||||
}
|
||||
};
|
||||
|
||||
std::coroutine_handle<promise_type> handle;
|
||||
|
||||
explicit CppCoroutine(std::coroutine_handle<promise_type> h) noexcept
|
||||
: handle(h)
|
||||
{
|
||||
}
|
||||
|
||||
CppCoroutine(CppCoroutine&& other) noexcept
|
||||
: handle(std::exchange(other.handle, {}))
|
||||
{
|
||||
}
|
||||
|
||||
CppCoroutine(const CppCoroutine&) = delete;
|
||||
CppCoroutine& operator=(const CppCoroutine&) = delete;
|
||||
~CppCoroutine() = default;
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Specialisation for void-returning coroutines.
|
||||
*/
|
||||
template <>
|
||||
struct CppCoroutine<void>
|
||||
{
|
||||
struct promise_type
|
||||
{
|
||||
lua_State* L = nullptr;
|
||||
int nresults = 0;
|
||||
bool is_done = false;
|
||||
std::exception_ptr exception;
|
||||
|
||||
std::suspend_always initial_suspend() noexcept { return {}; }
|
||||
std::suspend_always final_suspend() noexcept { return {}; }
|
||||
|
||||
void unhandled_exception() noexcept
|
||||
{
|
||||
exception = std::current_exception();
|
||||
}
|
||||
|
||||
void return_void()
|
||||
{
|
||||
nresults = 0;
|
||||
is_done = true;
|
||||
}
|
||||
|
||||
CppCoroutine get_return_object()
|
||||
{
|
||||
return CppCoroutine{ std::coroutine_handle<promise_type>::from_promise(*this) };
|
||||
}
|
||||
};
|
||||
|
||||
std::coroutine_handle<promise_type> handle;
|
||||
|
||||
explicit CppCoroutine(std::coroutine_handle<promise_type> h) noexcept
|
||||
: handle(h)
|
||||
{
|
||||
}
|
||||
|
||||
CppCoroutine(CppCoroutine&& other) noexcept
|
||||
: handle(std::exchange(other.handle, {}))
|
||||
{
|
||||
}
|
||||
|
||||
CppCoroutine(const CppCoroutine&) = delete;
|
||||
CppCoroutine& operator=(const CppCoroutine&) = delete;
|
||||
~CppCoroutine() = default;
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief An awaitable wrapper around a Lua coroutine thread.
|
||||
*
|
||||
* Use inside a CppCoroutine body to synchronously resume a child Lua thread and obtain
|
||||
* the number of values it left on its stack (either from yield or return).
|
||||
*
|
||||
* @note Runs the Lua thread synchronously (no external event loop required).
|
||||
*/
|
||||
class LuaCoroutine
|
||||
{
|
||||
public:
|
||||
LuaCoroutine(lua_State* thread, lua_State* from = nullptr) noexcept
|
||||
: m_thread(thread)
|
||||
, m_from(from)
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() noexcept
|
||||
{
|
||||
m_status = lua_resume_x(m_thread, m_from, 0, &m_nresults);
|
||||
return true; // Always ready: runs synchronously
|
||||
}
|
||||
|
||||
void await_suspend(std::coroutine_handle<>) noexcept
|
||||
{
|
||||
// Never called because await_ready always returns true
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {status, nresults} where status is LUA_OK or LUA_YIELD,
|
||||
* and nresults is the number of values on the thread's stack.
|
||||
*/
|
||||
std::pair<int, int> await_resume() noexcept
|
||||
{
|
||||
return { m_status, m_nresults };
|
||||
}
|
||||
|
||||
private:
|
||||
lua_State* m_thread;
|
||||
lua_State* m_from;
|
||||
int m_status = LUABRIDGE_LUA_OK;
|
||||
int m_nresults = 0;
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* @brief Trait: is T a CppCoroutine<R> specialisation?
|
||||
*/
|
||||
template <class T>
|
||||
struct is_cpp_coroutine : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class R>
|
||||
struct is_cpp_coroutine<CppCoroutine<R>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Trait: does callable F return a CppCoroutine<R>?
|
||||
*/
|
||||
template <class F, class = void>
|
||||
struct is_cpp_coroutine_factory : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class F>
|
||||
struct is_cpp_coroutine_factory<F, std::void_t<typename function_traits<std::remove_reference_t<F>>::result_type>>
|
||||
: is_cpp_coroutine<typename function_traits<std::remove_reference_t<F>>::result_type>
|
||||
{
|
||||
};
|
||||
|
||||
template <class F>
|
||||
inline constexpr bool is_cpp_coroutine_factory_v = is_cpp_coroutine_factory<F>::value;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief RAII frame for a suspended CppCoroutine, stored as a Lua full userdata.
|
||||
*
|
||||
* Kept alive on the Lua thread's own stack (not in the registry) so that abandoning the
|
||||
* coroutine — i.e. letting the Lua thread be collected by the GC — automatically triggers
|
||||
* the __gc metamethod, which calls the destructor and destroys the coroutine handle.
|
||||
*/
|
||||
template <class CoroType>
|
||||
struct CppCoroutineFrame
|
||||
{
|
||||
using HandleType = std::coroutine_handle<typename CoroType::promise_type>;
|
||||
|
||||
HandleType handle;
|
||||
|
||||
explicit CppCoroutineFrame(HandleType h) noexcept
|
||||
: handle(h)
|
||||
{
|
||||
}
|
||||
|
||||
CppCoroutineFrame(const CppCoroutineFrame&) = delete;
|
||||
CppCoroutineFrame& operator=(const CppCoroutineFrame&) = delete;
|
||||
|
||||
~CppCoroutineFrame()
|
||||
{
|
||||
if (handle && !handle.done())
|
||||
handle.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
// Version-portable yield helpers.
|
||||
//
|
||||
// Lua 5.2: lua_yieldk ctx is int; continuation signature is (lua_State*, int) — ctx
|
||||
// retrieved inside via lua_getctx().
|
||||
// Lua 5.3+: lua_yieldk ctx is lua_KContext; continuation signature is
|
||||
// (lua_State*, int, lua_KContext) — ctx passed directly.
|
||||
|
||||
// Forward declarations
|
||||
template <class F> int coroutine_continuation_body(lua_State* L, int frame_abs_idx);
|
||||
|
||||
#if LUA_VERSION_NUM < 503
|
||||
// Lua 5.2: lua_yieldk takes lua_CFunction (int(*)(lua_State*)) as continuation.
|
||||
// The context is recovered inside via lua_getctx().
|
||||
template <class F>
|
||||
int coroutine_continuation(lua_State* L)
|
||||
{
|
||||
int frame_abs_idx = 0;
|
||||
lua_getctx(L, &frame_abs_idx);
|
||||
return coroutine_continuation_body<F>(L, frame_abs_idx);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
int do_yield(lua_State* L, int nresults, int frame_abs_idx)
|
||||
{
|
||||
return lua_yieldk(L, nresults, frame_abs_idx, &coroutine_continuation<F>);
|
||||
}
|
||||
#else
|
||||
// Lua 5.3+: continuation receives lua_KContext directly.
|
||||
template <class F>
|
||||
int coroutine_continuation(lua_State* L, int /*status*/, lua_KContext ctx)
|
||||
{
|
||||
return coroutine_continuation_body<F>(L, static_cast<int>(ctx));
|
||||
}
|
||||
|
||||
template <class F>
|
||||
int do_yield(lua_State* L, int nresults, int frame_abs_idx)
|
||||
{
|
||||
return lua_yieldk(L, nresults, static_cast<lua_KContext>(frame_abs_idx), &coroutine_continuation<F>);
|
||||
}
|
||||
#endif
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Raises a Lua error from a stored C++ exception (or a generic message).
|
||||
* Removes the frame userdata from the stack before raising so GC can collect it.
|
||||
*/
|
||||
[[noreturn]] inline void raise_from_exception(lua_State* L, int frame_abs_idx, std::exception_ptr ex)
|
||||
{
|
||||
lua_settop(L, frame_abs_idx - 1); // pop frame (and any value above it) — GC will collect it
|
||||
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(ex);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
raise_lua_error(L, "%s", e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
#endif
|
||||
|
||||
raise_lua_error(L, "unknown exception in C++ coroutine");
|
||||
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Common body for the coroutine continuation: resumes the C++ coroutine handle
|
||||
* and either yields again or returns the final result.
|
||||
*
|
||||
* @param frame_abs_idx Absolute stack index where the CppCoroutineFrame userdata lives.
|
||||
* Any resume arguments pushed above it are discarded first.
|
||||
*/
|
||||
template <class F>
|
||||
int coroutine_continuation_body(lua_State* L, int frame_abs_idx)
|
||||
{
|
||||
using CoroType = typename function_traits<std::remove_reference_t<F>>::result_type;
|
||||
using FrameType = CppCoroutineFrame<CoroType>;
|
||||
|
||||
// Discard resume arguments pushed above the frame (we don't expose them to C++ yet)
|
||||
lua_settop(L, frame_abs_idx);
|
||||
|
||||
// Recover the frame from its stable stack position
|
||||
auto* frame = align<FrameType>(lua_touserdata(L, frame_abs_idx));
|
||||
|
||||
// Resume the C++ coroutine body; yield_value/return_value will push at frame_abs_idx+1
|
||||
frame->handle.resume();
|
||||
|
||||
auto& promise = frame->handle.promise();
|
||||
|
||||
if (promise.exception)
|
||||
raise_from_exception(L, frame_abs_idx, promise.exception);
|
||||
|
||||
if (promise.is_done)
|
||||
{
|
||||
if (promise.nresults == 1)
|
||||
lua_replace(L, frame_abs_idx); // swap return value into frame slot; pops frame userdata
|
||||
else
|
||||
lua_settop(L, frame_abs_idx - 1); // void: remove frame entirely
|
||||
return promise.nresults;
|
||||
}
|
||||
|
||||
// yield_value pushed one value above the frame; yield it, keeping frame below
|
||||
return do_yield<F>(L, promise.nresults, frame_abs_idx);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief lua_CFunction entry point for a registered CppCoroutine factory.
|
||||
*
|
||||
* Upvalue 1: the factory functor F (as aligned full userdata).
|
||||
*
|
||||
* The CppCoroutineFrame userdata is left on the Lua thread's own stack (not in the registry).
|
||||
* This means an abandoned coroutine is naturally cleaned up when the Lua thread is GC'd.
|
||||
*/
|
||||
template <class F>
|
||||
int invoke_coroutine_entry(lua_State* L)
|
||||
{
|
||||
using FnTraits = function_traits<std::remove_reference_t<F>>;
|
||||
using ArgsPack = typename FnTraits::argument_types;
|
||||
using CoroType = typename FnTraits::result_type;
|
||||
using FrameType = CppCoroutineFrame<CoroType>;
|
||||
|
||||
LUABRIDGE_ASSERT(isfulluserdata(L, lua_upvalueindex(1)));
|
||||
auto& factory = *align<F>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
|
||||
// Invoke the factory to create the coroutine object.
|
||||
// The coroutine body does not run yet (initial_suspend returns suspend_always).
|
||||
auto coro = invoke_callable_from_stack<ArgsPack, 1>(L, factory);
|
||||
|
||||
// Push the frame as a Lua full userdata and remember its absolute stack position.
|
||||
// It is NOT pinned in the registry; keeping it on the thread's stack means GC will
|
||||
// collect it (via __gc) when the Lua thread is abandoned.
|
||||
lua_newuserdata_aligned<FrameType>(L, std::move(coro.handle));
|
||||
coro.handle = {}; // ownership transferred to frame
|
||||
|
||||
int frame_abs_idx = lua_gettop(L);
|
||||
auto* frame = align<FrameType>(lua_touserdata(L, frame_abs_idx));
|
||||
|
||||
// Give the promise access to the Lua state so yield_value/return_value can push values
|
||||
frame->handle.promise().L = L;
|
||||
|
||||
// First resume: runs the body to the first co_yield or co_return
|
||||
frame->handle.resume();
|
||||
|
||||
auto& promise = frame->handle.promise();
|
||||
|
||||
if (promise.exception)
|
||||
raise_from_exception(L, frame_abs_idx, promise.exception);
|
||||
|
||||
if (promise.is_done)
|
||||
{
|
||||
if (promise.nresults == 1)
|
||||
lua_replace(L, frame_abs_idx); // swap return value into frame slot
|
||||
else
|
||||
lua_settop(L, frame_abs_idx - 1); // void: remove frame
|
||||
return promise.nresults;
|
||||
}
|
||||
|
||||
// yield_value pushed one value above the frame; yield it, keeping frame below
|
||||
return do_yield<F>(L, promise.nresults, frame_abs_idx);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Pushes a CppCoroutine factory as a Lua closure onto the stack.
|
||||
*/
|
||||
template <class F, class = std::enable_if_t<is_cpp_coroutine_factory_v<F>>>
|
||||
inline void push_coroutine_function(lua_State* L, F&& f, const char* debugname)
|
||||
{
|
||||
using FDecay = std::decay_t<F>;
|
||||
lua_newuserdata_aligned<FDecay>(L, std::forward<F>(f));
|
||||
lua_pushcclosure_x(L, &invoke_coroutine_entry<FDecay>, debugname, 1);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace luabridge
|
||||
|
||||
#endif // !Lua 5.1 / LuaJIT / Luau
|
||||
#endif // LUABRIDGE_HAS_CXX20_COROUTINES
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2023, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
#include "Errors.h"
|
||||
#include "LuaHelpers.h"
|
||||
#include "Stack.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief LuaBridge enum wrapper for enums as integers.
|
||||
*
|
||||
* An enum exposed with this class will just be decayed to lua as integer. It's responsibility of
|
||||
* the developer to make sure that a lua integer could be converted back to C++. Failing to validate a lua
|
||||
* integer before converting to the corresponding C++ enum value could lead to a C++ enum that has no defined value.
|
||||
*
|
||||
* For improved security, specify which values the enum will have, so runtime validation could be performed.
|
||||
*/
|
||||
template <class T, T... Values>
|
||||
struct Enum
|
||||
{
|
||||
static_assert(std::is_enum_v<T>);
|
||||
|
||||
using Type = std::underlying_type_t<T>;
|
||||
|
||||
[[nodiscard]] static Result push(lua_State* L, T value)
|
||||
{
|
||||
return Stack<Type>::push(L, static_cast<Type>(value));
|
||||
}
|
||||
|
||||
[[nodiscard]] static TypeResult<T> get(lua_State* L, int index)
|
||||
{
|
||||
const auto result = Stack<Type>::get(L, index);
|
||||
if (! result)
|
||||
return result.error();
|
||||
|
||||
if constexpr (sizeof...(Values) > 0)
|
||||
{
|
||||
constexpr Type values[] = { static_cast<Type>(Values)... };
|
||||
for (std::size_t i = 0; i < sizeof...(Values); ++i)
|
||||
{
|
||||
if (values[i] == *result)
|
||||
return static_cast<T>(*result);
|
||||
}
|
||||
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<T>(*result);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
||||
{
|
||||
return lua_type(L, index) == LUA_TNUMBER;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2021, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
namespace detail {
|
||||
|
||||
static inline constexpr char error_lua_stack_overflow[] = "stack overflow";
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief LuaBridge error codes.
|
||||
*/
|
||||
enum class ErrorCode
|
||||
{
|
||||
ClassNotRegistered = 1,
|
||||
|
||||
LuaStackOverflow,
|
||||
|
||||
LuaFunctionCallFailed,
|
||||
|
||||
IntegerDoesntFitIntoLuaInteger,
|
||||
|
||||
FloatingPointDoesntFitIntoLuaNumber,
|
||||
|
||||
InvalidTypeCast,
|
||||
|
||||
InvalidTableSizeInCast,
|
||||
|
||||
CoroutineYieldFromNonCoroutine,
|
||||
|
||||
CoroutineAlreadyDone
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
namespace detail {
|
||||
struct ErrorCategory : std::error_category
|
||||
{
|
||||
const char* name() const noexcept override
|
||||
{
|
||||
return "luabridge";
|
||||
}
|
||||
|
||||
std::string message(int ev) const override
|
||||
{
|
||||
return errorString(ev);
|
||||
}
|
||||
|
||||
static const char* errorString(int ev) noexcept
|
||||
{
|
||||
switch (static_cast<ErrorCode>(ev))
|
||||
{
|
||||
case ErrorCode::ClassNotRegistered:
|
||||
return "The class is not registered in LuaBridge";
|
||||
|
||||
case ErrorCode::LuaStackOverflow:
|
||||
return "The lua stack has overflow";
|
||||
|
||||
case ErrorCode::LuaFunctionCallFailed:
|
||||
return "The lua function invocation raised an error";
|
||||
|
||||
case ErrorCode::IntegerDoesntFitIntoLuaInteger:
|
||||
return "The native integer can't fit inside a lua integer";
|
||||
|
||||
case ErrorCode::FloatingPointDoesntFitIntoLuaNumber:
|
||||
return "The native floating point can't fit inside a lua number";
|
||||
|
||||
case ErrorCode::InvalidTypeCast:
|
||||
return "The lua object can't be cast to desired type";
|
||||
|
||||
case ErrorCode::InvalidTableSizeInCast:
|
||||
return "The lua table has different size than expected";
|
||||
|
||||
case ErrorCode::CoroutineYieldFromNonCoroutine:
|
||||
return "Cannot yield from a non-coroutine Lua state";
|
||||
|
||||
case ErrorCode::CoroutineAlreadyDone:
|
||||
return "The Lua coroutine has already finished execution";
|
||||
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
static const ErrorCategory& getInstance() noexcept
|
||||
{
|
||||
static ErrorCategory category;
|
||||
return category;
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Construct an error code from the error enum.
|
||||
*/
|
||||
inline std::error_code makeErrorCode(ErrorCode e)
|
||||
{
|
||||
return { static_cast<int>(e), detail::ErrorCategory::getInstance() };
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Supports std::error_code construction.
|
||||
*/
|
||||
inline std::error_code make_error_code(ErrorCode e)
|
||||
{
|
||||
return { static_cast<int>(e), detail::ErrorCategory::getInstance() };
|
||||
}
|
||||
} // namespace luabridge
|
||||
|
||||
namespace std {
|
||||
template <> struct is_error_code_enum<luabridge::ErrorCode> : true_type {};
|
||||
} // namespace std
|
||||
+1632
File diff suppressed because it is too large
Load Diff
+124
@@ -0,0 +1,124 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2023, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include <type_traits>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
template <class T, class... Ts>
|
||||
class FlagSet
|
||||
{
|
||||
static_assert(std::is_integral_v<T>);
|
||||
|
||||
public:
|
||||
constexpr FlagSet() noexcept = default;
|
||||
|
||||
constexpr void set(FlagSet other) noexcept
|
||||
{
|
||||
flags |= other.flags;
|
||||
}
|
||||
|
||||
constexpr FlagSet withSet(FlagSet other) const noexcept
|
||||
{
|
||||
FlagSet result { flags };
|
||||
result.flags |= other.flags;
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr void unset(FlagSet other) noexcept
|
||||
{
|
||||
flags &= ~other.flags;
|
||||
}
|
||||
|
||||
constexpr FlagSet withUnset(FlagSet other) const noexcept
|
||||
{
|
||||
FlagSet result { flags };
|
||||
result.flags &= ~other.flags;
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr bool test(FlagSet other) const noexcept
|
||||
{
|
||||
return (flags & other.flags) != 0;
|
||||
}
|
||||
|
||||
constexpr FlagSet operator|(FlagSet other) const noexcept
|
||||
{
|
||||
return FlagSet(flags | other.flags);
|
||||
}
|
||||
|
||||
constexpr FlagSet operator&(FlagSet other) const noexcept
|
||||
{
|
||||
return FlagSet(flags & other.flags);
|
||||
}
|
||||
|
||||
constexpr FlagSet operator~() const noexcept
|
||||
{
|
||||
return FlagSet(~flags);
|
||||
}
|
||||
|
||||
constexpr T toUnderlying() const noexcept
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
|
||||
std::string toString() const
|
||||
{
|
||||
std::string result;
|
||||
result.reserve(sizeof(T) * std::numeric_limits<uint8_t>::digits);
|
||||
|
||||
(result.append((mask<Ts>() & flags) ? "1" : "0"), ...);
|
||||
|
||||
for (std::size_t i = sizeof...(Ts); i < sizeof(T) * std::numeric_limits<uint8_t>::digits; ++i)
|
||||
result.append("0");
|
||||
|
||||
std::reverse(result.begin(), result.end());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class... Us>
|
||||
static constexpr FlagSet Value() noexcept
|
||||
{
|
||||
return FlagSet{ mask<Us...>() };
|
||||
}
|
||||
|
||||
template <class U>
|
||||
static constexpr auto fromUnderlying(U newFlags) noexcept
|
||||
-> std::enable_if_t<std::is_integral_v<U> && std::is_convertible_v<U, T>, FlagSet>
|
||||
{
|
||||
return { static_cast<T>(newFlags) };
|
||||
}
|
||||
|
||||
private:
|
||||
template <class U, class V, class... Us>
|
||||
static constexpr T indexOf() noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<U, V>)
|
||||
return static_cast<T>(0);
|
||||
else
|
||||
return static_cast<T>(1) + indexOf<U, Us...>();
|
||||
}
|
||||
|
||||
template <class... Us>
|
||||
static constexpr T mask() noexcept
|
||||
{
|
||||
return ((static_cast<T>(1) << indexOf<Us, Ts...>()) | ...);
|
||||
}
|
||||
|
||||
constexpr FlagSet(T flags) noexcept
|
||||
: flags(flags)
|
||||
{
|
||||
}
|
||||
|
||||
T flags = 0;
|
||||
};
|
||||
|
||||
} // namespace luabridge
|
||||
@@ -0,0 +1,872 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2020, Dmitry Tarakanov
|
||||
// Copyright 2019, George Tokmaji
|
||||
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
|
||||
namespace luabridge {
|
||||
namespace detail {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Invokes undefined behavior when an unreachable part of the code is reached.
|
||||
*
|
||||
* An implementation may use this to optimize impossible code branches away (typically, in optimized builds) or to trap them to prevent
|
||||
* further execution (typically, in debug builds).
|
||||
*/
|
||||
[[noreturn]] inline void unreachable()
|
||||
{
|
||||
#if defined(__GNUC__) // GCC, Clang, ICC
|
||||
__builtin_unreachable();
|
||||
#elif defined(_MSC_VER) // MSVC
|
||||
__assume(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Provides the member typedef type which is the type referred to by T with its topmost cv-qualifiers removed.
|
||||
*/
|
||||
template< class T >
|
||||
struct remove_cvref
|
||||
{
|
||||
typedef std::remove_cv_t<std::remove_reference_t<T>> type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using remove_cvref_t = typename remove_cvref<T>::type;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Generic function traits.
|
||||
*
|
||||
* @tparam IsMember True if the function is a member function pointer.
|
||||
* @tparam IsConst True if the function is const.
|
||||
* @tparam R Return type of the function.
|
||||
* @tparam Args Arguments types as variadic parameter pack.
|
||||
*/
|
||||
template <bool IsMember, bool IsConst, class R, class... Args>
|
||||
struct function_traits_base
|
||||
{
|
||||
using result_type = R;
|
||||
|
||||
using argument_types = std::tuple<Args...>;
|
||||
|
||||
static constexpr auto arity = sizeof...(Args);
|
||||
|
||||
static constexpr auto is_member = IsMember;
|
||||
|
||||
static constexpr auto is_const = IsConst;
|
||||
};
|
||||
|
||||
template <class, bool Enable>
|
||||
struct function_traits_impl;
|
||||
|
||||
template <class R, class... Args>
|
||||
struct function_traits_impl<R(Args...), true> : function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
struct function_traits_impl<R (*)(Args...), true> : function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct function_traits_impl<R (C::*)(Args...), true> : function_traits_base<true, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct function_traits_impl<R (C::*)(Args...) const, true> : function_traits_base<true, true, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
struct function_traits_impl<R(Args...) noexcept, true> : function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
struct function_traits_impl<R (*)(Args...) noexcept, true> : function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct function_traits_impl<R (C::*)(Args...) noexcept, true> : function_traits_base<true, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct function_traits_impl<R (C::*)(Args...) const noexcept, true> : function_traits_base<true, true, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_IX86) // Windows: WINAPI (a.k.a. __stdcall) function pointers (32bit only).
|
||||
inline static constexpr bool is_stdcall_default_calling_convention = std::is_same_v<void __stdcall(), void()>;
|
||||
inline static constexpr bool is_fastcall_default_calling_convention = std::is_same_v<void __fastcall(), void()>;
|
||||
|
||||
template <class R, class... Args>
|
||||
struct function_traits_impl<R __stdcall(Args...), !is_stdcall_default_calling_convention> : function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
struct function_traits_impl<R (__stdcall *)(Args...), !is_stdcall_default_calling_convention> : function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct function_traits_impl<R (__stdcall C::*)(Args...), true> : function_traits_base<true, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct function_traits_impl<R (__stdcall C::*)(Args...) const, true> : function_traits_base<true, true, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
struct function_traits_impl<R __stdcall(Args...) noexcept, !is_stdcall_default_calling_convention> : function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
struct function_traits_impl<R (__stdcall *)(Args...) noexcept, !is_stdcall_default_calling_convention> : function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct function_traits_impl<R (__stdcall C::*)(Args...) noexcept, true> : function_traits_base<true, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct function_traits_impl<R (__stdcall C::*)(Args...) const noexcept, true> : function_traits_base<true, true, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
struct function_traits_impl<R __fastcall(Args...), !is_fastcall_default_calling_convention> : function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
struct function_traits_impl<R (__fastcall *)(Args...), !is_fastcall_default_calling_convention> : function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct function_traits_impl<R (__fastcall C::*)(Args...), true> : function_traits_base<true, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct function_traits_impl<R (__fastcall C::*)(Args...) const, true> : function_traits_base<true, true, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
struct function_traits_impl<R __fastcall(Args...) noexcept, !is_fastcall_default_calling_convention> : function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
struct function_traits_impl<R (__fastcall *)(Args...) noexcept, !is_fastcall_default_calling_convention> : function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct function_traits_impl<R (__fastcall C::*)(Args...) noexcept, true> : function_traits_base<true, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct function_traits_impl<R (__fastcall C::*)(Args...) const noexcept, true> : function_traits_base<true, true, R, Args...>
|
||||
{
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class F, class = void>
|
||||
struct has_call_operator : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class F>
|
||||
struct has_call_operator<F, std::void_t<decltype(&F::operator())>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class F>
|
||||
inline static constexpr bool has_call_operator_v = has_call_operator<F>::value;
|
||||
|
||||
template <class F>
|
||||
struct is_move_only_function : std::false_type {};
|
||||
|
||||
#if LUABRIDGE_HAS_CXX23_MOVE_ONLY_FUNCTION
|
||||
template <class R, class... Args> struct is_move_only_function<std::move_only_function<R(Args...)>> : std::true_type {};
|
||||
template <class R, class... Args> struct is_move_only_function<std::move_only_function<R(Args...) noexcept>> : std::true_type {};
|
||||
template <class R, class... Args> struct is_move_only_function<std::move_only_function<R(Args...) const>> : std::true_type {};
|
||||
template <class R, class... Args> struct is_move_only_function<std::move_only_function<R(Args...) const noexcept>> : std::true_type {};
|
||||
#endif
|
||||
|
||||
template <class F>
|
||||
inline static constexpr bool is_move_only_function_v = is_move_only_function<F>::value;
|
||||
|
||||
template <class F, class = void>
|
||||
struct functor_traits_impl
|
||||
{
|
||||
};
|
||||
|
||||
template <class F>
|
||||
struct functor_traits_impl<F, std::enable_if_t<has_call_operator_v<F>>> : function_traits_impl<decltype(&F::operator()), true>
|
||||
{
|
||||
};
|
||||
|
||||
template <class F>
|
||||
struct functor_traits_impl<F, std::enable_if_t<!has_call_operator_v<F> && std::is_invocable_v<F&> && !is_move_only_function_v<F>>>
|
||||
: function_traits_base<false, false, std::invoke_result_t<F&>>
|
||||
{
|
||||
};
|
||||
|
||||
#if LUABRIDGE_HAS_CXX23_MOVE_ONLY_FUNCTION
|
||||
|
||||
template <class R, class... Args>
|
||||
struct functor_traits_impl<std::move_only_function<R(Args...)>>
|
||||
: function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
struct functor_traits_impl<std::move_only_function<R(Args...) noexcept>>
|
||||
: function_traits_base<false, false, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
struct functor_traits_impl<std::move_only_function<R(Args...) const>>
|
||||
: function_traits_base<false, true, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
struct functor_traits_impl<std::move_only_function<R(Args...) const noexcept>>
|
||||
: function_traits_base<false, true, R, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
#endif // LUABRIDGE_HAS_CXX23_MOVE_ONLY_FUNCTION
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Traits class for callable objects (e.g. function pointers, lambdas)
|
||||
*
|
||||
* @tparam F Callable object.
|
||||
*/
|
||||
template <class F>
|
||||
struct function_traits : std::conditional_t<std::is_class_v<F>,
|
||||
detail::functor_traits_impl<F>,
|
||||
detail::function_traits_impl<F, true>>
|
||||
{
|
||||
};
|
||||
|
||||
template <class T, bool IsClass = std::is_class_v<T>, class = void>
|
||||
struct has_function_traits : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct has_function_traits<T, true, std::void_t<typename function_traits<T>::result_type, typename function_traits<T>::argument_types>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline static constexpr bool has_function_traits_v = has_function_traits<T>::value;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Deduces the argument type of a callble object or void in case it has no argument.
|
||||
*
|
||||
* @tparam I Argument index.
|
||||
* @tparam F Callable object.
|
||||
*/
|
||||
template <std::size_t I, class F, class = void>
|
||||
struct function_argument_or_void
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template <std::size_t I, class F>
|
||||
struct function_argument_or_void<I, F, std::enable_if_t<I < std::tuple_size_v<typename function_traits<F>::argument_types>>>
|
||||
{
|
||||
using type = std::tuple_element_t<I, typename function_traits<F>::argument_types>;
|
||||
};
|
||||
|
||||
template <std::size_t I, class F>
|
||||
using function_argument_or_void_t = typename function_argument_or_void<I, F>::type;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Deduces the return type of a callble object.
|
||||
*
|
||||
* @tparam F Callable object.
|
||||
*/
|
||||
template <class F>
|
||||
using function_result_t = typename function_traits<F>::result_type;
|
||||
|
||||
/**
|
||||
* @brief Deduces the argument type of a callble object.
|
||||
*
|
||||
* @tparam I Argument index.
|
||||
* @tparam F Callable object.
|
||||
*/
|
||||
template <std::size_t I, class F>
|
||||
using function_argument_t = std::tuple_element_t<I, typename function_traits<F>::argument_types>;
|
||||
|
||||
/**
|
||||
* @brief Deduces the arguments type of a callble object.
|
||||
*
|
||||
* @tparam F Callable object.
|
||||
*/
|
||||
template <class F>
|
||||
using function_arguments_t = typename function_traits<F>::argument_types;
|
||||
|
||||
/**
|
||||
* @brief An integral constant expression that gives the number of arguments accepted by the callable object.
|
||||
*
|
||||
* @tparam F Callable object.
|
||||
*/
|
||||
template <class F>
|
||||
static constexpr std::size_t function_arity_v = function_traits<F>::arity;
|
||||
|
||||
/**
|
||||
* @brief An boolean constant expression that checks if the callable object is a member function.
|
||||
*
|
||||
* @tparam F Callable object.
|
||||
*/
|
||||
template <class F>
|
||||
static constexpr bool function_is_member_v = function_traits<F>::is_member;
|
||||
|
||||
/**
|
||||
* @brief An boolean constant expression that checks if the callable object is const.
|
||||
*
|
||||
* @tparam F Callable object.
|
||||
*/
|
||||
template <class F>
|
||||
static constexpr bool function_is_const_v = function_traits<F>::is_const;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Detect if we T is a callable object.
|
||||
*
|
||||
* @tparam T Potentially callable object.
|
||||
*/
|
||||
template <class T, class = void>
|
||||
struct is_callable
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_callable<T, std::void_t<decltype(&T::operator())>>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_callable<T, std::enable_if_t<std::is_class_v<T> && !has_call_operator_v<T> && has_function_traits_v<T>>>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_callable<T, std::enable_if_t<std::is_pointer_v<T> && std::is_function_v<std::remove_pointer_t<T>>>>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_callable<T, std::enable_if_t<std::is_member_function_pointer_v<T>>>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline static constexpr bool is_callable_v = is_callable<T>::value;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Detect if we T is a const member function pointer.
|
||||
*
|
||||
* @tparam T Potentially const member function pointer.
|
||||
*/
|
||||
template <class T>
|
||||
struct is_const_member_function_pointer
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <class T, class R, class... Args>
|
||||
struct is_const_member_function_pointer<R (T::*)(Args...)>
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <class T, class R, class... Args>
|
||||
struct is_const_member_function_pointer<R (T::*)(Args...) const>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template <class T, class R, class... Args>
|
||||
struct is_const_member_function_pointer<R (T::*)(Args...) noexcept>
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <class T, class R, class... Args>
|
||||
struct is_const_member_function_pointer<R (T::*)(Args...) const noexcept>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline static constexpr bool is_const_member_function_pointer_v = is_const_member_function_pointer<T>::value;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Detect if T is a lua cfunction pointer.
|
||||
*
|
||||
* @tparam T Potentially lua cfunction pointer.
|
||||
*/
|
||||
template <class T>
|
||||
struct is_cfunction_pointer
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_cfunction_pointer<int (*)(lua_State*)>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline static constexpr bool is_cfunction_pointer_v = is_cfunction_pointer<T>::value;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Detect if T is a member lua cfunction pointer.
|
||||
*
|
||||
* @tparam T Potentially member lua cfunction pointer.
|
||||
*/
|
||||
template <class T>
|
||||
struct is_member_cfunction_pointer
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_member_cfunction_pointer<int (T::*)(lua_State*)>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_member_cfunction_pointer<int (T::*)(lua_State*) const>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline static constexpr bool is_member_cfunction_pointer_v = is_member_cfunction_pointer<T>::value;
|
||||
|
||||
/**
|
||||
* @brief Detect if T is a const member lua cfunction pointer.
|
||||
*
|
||||
* @tparam T Potentially const member lua cfunction pointer.
|
||||
*/
|
||||
template <class T>
|
||||
struct is_const_member_cfunction_pointer
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_const_member_cfunction_pointer<int (T::*)(lua_State*)>
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_const_member_cfunction_pointer<int (T::*)(lua_State*) const>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline static constexpr bool is_const_member_cfunction_pointer_v = is_const_member_cfunction_pointer<T>::value;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Detect if T is a member or non member lua cfunction pointer.
|
||||
*
|
||||
* @tparam T Potentially member or non member lua cfunction pointer.
|
||||
*/
|
||||
template <class T>
|
||||
inline static constexpr bool is_any_cfunction_pointer_v = is_cfunction_pointer_v<T> || is_member_cfunction_pointer_v<T>;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief A constexpr check for proxy_member functions.
|
||||
*
|
||||
* @tparam T Type where the callable should be able to operate.
|
||||
* @tparam F Callable object.
|
||||
*/
|
||||
template <class T, class F>
|
||||
inline static constexpr bool is_proxy_member_function_v =
|
||||
!std::is_member_function_pointer_v<F> &&
|
||||
std::is_same_v<T, remove_cvref_t<std::remove_pointer_t<function_argument_or_void_t<0, F>>>>;
|
||||
|
||||
template <class T, class F>
|
||||
inline static constexpr bool is_const_proxy_function_v =
|
||||
is_proxy_member_function_v<T, F> &&
|
||||
std::is_const_v<std::remove_reference_t<std::remove_pointer_t<function_argument_or_void_t<0, F>>>>;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief An integral constant expression that gives the number of arguments excluding one type (usually used with lua_State*) accepted by the callable object.
|
||||
*
|
||||
* @tparam F Callable object.
|
||||
*/
|
||||
template <class, class>
|
||||
struct function_arity_excluding
|
||||
{
|
||||
};
|
||||
|
||||
template < class... Ts, class ExclusionType>
|
||||
struct function_arity_excluding<std::tuple<Ts...>, ExclusionType>
|
||||
: std::integral_constant<std::size_t, (0 + ... + (std::is_same_v<std::decay_t<Ts>, ExclusionType> ? 0 : 1))>
|
||||
{
|
||||
};
|
||||
|
||||
template <class F, class ExclusionType>
|
||||
inline static constexpr std::size_t function_arity_excluding_v = function_arity_excluding<function_arguments_t<F>, ExclusionType>::value;
|
||||
|
||||
/**
|
||||
* @brief An integral constant expression that gives the number of arguments excluding one type (usually used with lua_State*) accepted by the callable object.
|
||||
*
|
||||
* @tparam F Callable object.
|
||||
*/
|
||||
template <class, class, class, class, class = void>
|
||||
struct member_function_arity_excluding
|
||||
{
|
||||
};
|
||||
|
||||
template <class T, class F, class... Ts, class ExclusionType>
|
||||
struct member_function_arity_excluding<T, F, std::tuple<Ts...>, ExclusionType, std::enable_if_t<!is_proxy_member_function_v<T, F>>>
|
||||
: std::integral_constant<std::size_t, (0 + ... + (std::is_same_v<std::decay_t<Ts>, ExclusionType> ? 0 : 1))>
|
||||
{
|
||||
};
|
||||
|
||||
template <class T, class F, class... Ts, class ExclusionType>
|
||||
struct member_function_arity_excluding<T, F, std::tuple<Ts...>, ExclusionType, std::enable_if_t<is_proxy_member_function_v<T, F>>>
|
||||
: std::integral_constant<std::size_t, (0 + ... + (std::is_same_v<std::decay_t<Ts>, ExclusionType> ? 0 : 1)) - 1>
|
||||
{
|
||||
};
|
||||
|
||||
template <class T, class F, class ExclusionType>
|
||||
inline static constexpr std::size_t member_function_arity_excluding_v = member_function_arity_excluding<T, F, function_arguments_t<F>, ExclusionType>::value;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Detectors for const and non const functions in packs and counting them.
|
||||
*/
|
||||
template <class T, class F>
|
||||
static constexpr bool is_const_function =
|
||||
detail::is_const_member_function_pointer_v<F> ||
|
||||
(detail::function_arity_v<F> > 0 && detail::is_const_proxy_function_v<T, F>);
|
||||
|
||||
template <class T, class... Fs>
|
||||
inline static constexpr std::size_t const_functions_count = (0 + ... + (is_const_function<T, Fs> ? 1 : 0));
|
||||
|
||||
template <class T, class... Fs>
|
||||
inline static constexpr std::size_t non_const_functions_count = (0 + ... + (is_const_function<T, Fs> ? 0 : 1));
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Simple make_tuple alternative that doesn't decay the types.
|
||||
*
|
||||
* @tparam Types Argument types that will compose the tuple.
|
||||
*/
|
||||
template <class... Types>
|
||||
constexpr auto tupleize(Types&&... types)
|
||||
{
|
||||
return std::tuple<Types...>(std::forward<Types>(types)...);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Remove first type from tuple.
|
||||
*/
|
||||
template <class T>
|
||||
struct remove_first_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T, class... Ts>
|
||||
struct remove_first_type<std::tuple<T, Ts...>>
|
||||
{
|
||||
using type = std::tuple<Ts...>;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using remove_first_type_t = typename remove_first_type<T>::type;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Drop the first N types from a tuple.
|
||||
*/
|
||||
template <std::size_t N, class Tuple>
|
||||
struct tuple_drop_first
|
||||
{
|
||||
using type = typename tuple_drop_first<N - 1, remove_first_type_t<Tuple>>::type;
|
||||
};
|
||||
|
||||
template <class Tuple>
|
||||
struct tuple_drop_first<0, Tuple>
|
||||
{
|
||||
using type = Tuple;
|
||||
};
|
||||
|
||||
template <std::size_t N, class Tuple>
|
||||
using tuple_drop_first_t = typename tuple_drop_first<N, Tuple>::type;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Prepend a type to a tuple.
|
||||
*/
|
||||
template <class T, class Tuple>
|
||||
struct tuple_prepend;
|
||||
|
||||
template <class T, class... Ts>
|
||||
struct tuple_prepend<T, std::tuple<Ts...>>
|
||||
{
|
||||
using type = std::tuple<T, Ts...>;
|
||||
};
|
||||
|
||||
template <class T, class Tuple>
|
||||
using tuple_prepend_t = typename tuple_prepend<T, Tuple>::type;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Take only the first N types from a tuple (uses an accumulator to avoid ambiguity).
|
||||
*/
|
||||
template <std::size_t N, class Tuple, class Accum = std::tuple<>>
|
||||
struct tuple_take_first_impl
|
||||
{
|
||||
using type = Accum;
|
||||
};
|
||||
|
||||
template <std::size_t N, class T, class... Ts, class... Acc>
|
||||
struct tuple_take_first_impl<N, std::tuple<T, Ts...>, std::tuple<Acc...>>
|
||||
{
|
||||
using type = typename tuple_take_first_impl<N - 1, std::tuple<Ts...>, std::tuple<Acc..., T>>::type;
|
||||
};
|
||||
|
||||
template <class T, class... Ts, class... Acc>
|
||||
struct tuple_take_first_impl<0, std::tuple<T, Ts...>, std::tuple<Acc...>>
|
||||
{
|
||||
using type = std::tuple<Acc...>;
|
||||
};
|
||||
|
||||
template <std::size_t N, class Tuple>
|
||||
using tuple_take_first_t = typename tuple_take_first_impl<N, Tuple>::type;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Extracts the class type from a member function pointer.
|
||||
*/
|
||||
template <class F>
|
||||
struct member_function_class;
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct member_function_class<R (C::*)(Args...)> { using type = C; };
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct member_function_class<R (C::*)(Args...) const> { using type = const C; };
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct member_function_class<R (C::*)(Args...) noexcept> { using type = C; };
|
||||
|
||||
template <class C, class R, class... Args>
|
||||
struct member_function_class<R (C::*)(Args...) const noexcept> { using type = const C; };
|
||||
|
||||
template <class F>
|
||||
using member_function_class_t = typename member_function_class<F>::type;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Computes the leading argument tuple for bind_back: for member function pointers,
|
||||
* prepends ClassType* to the explicit remaining args; for all other callables, returns
|
||||
* the explicit remaining args unchanged.
|
||||
*/
|
||||
template <class Fn, class ExplicitRemaining, bool IsMember>
|
||||
struct bind_back_leading_impl
|
||||
{
|
||||
using type = ExplicitRemaining;
|
||||
};
|
||||
|
||||
template <class Fn, class ExplicitRemaining>
|
||||
struct bind_back_leading_impl<Fn, ExplicitRemaining, true>
|
||||
{
|
||||
using type = tuple_prepend_t<member_function_class_t<Fn>*, ExplicitRemaining>;
|
||||
};
|
||||
|
||||
template <class Fn, class ExplicitRemaining>
|
||||
using bind_back_leading_t =
|
||||
typename bind_back_leading_impl<Fn, ExplicitRemaining, std::is_member_function_pointer_v<Fn>>::type;
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Internal storage for luabridge::bind_front — exposes a non-template operator() so that
|
||||
* function_traits can statically resolve result_type and argument_types.
|
||||
*/
|
||||
template <class R, class RemainingArgsTuple, class Fn, class... BoundArgs>
|
||||
struct bind_front_wrapper;
|
||||
|
||||
template <class R, class... Remaining, class Fn, class... BoundArgs>
|
||||
struct bind_front_wrapper<R, std::tuple<Remaining...>, Fn, BoundArgs...>
|
||||
{
|
||||
Fn fn_;
|
||||
std::tuple<BoundArgs...> bound_;
|
||||
|
||||
template <class F, class... BA>
|
||||
bind_front_wrapper(F&& f, BA&&... ba)
|
||||
: fn_(std::forward<F>(f)), bound_(std::forward<BA>(ba)...)
|
||||
{
|
||||
}
|
||||
|
||||
R operator()(Remaining... args) const
|
||||
{
|
||||
return std::apply([&](const auto&... ba) { return std::invoke(fn_, ba..., args...); }, bound_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Drop-in replacement for std::bind_front with statically introspectable argument types.
|
||||
*
|
||||
* std::bind_front returns an object whose operator() is a template, so its argument and result
|
||||
* types cannot be resolved at compile time without an explicit std::function<Sig> cast. This
|
||||
* wrapper stores the callable and its leading bound arguments, then exposes a concrete
|
||||
* non-template operator() whose parameter types are derived directly from the underlying
|
||||
* callable's signature.
|
||||
*
|
||||
* For member function pointers the implicit object argument consumed by std::invoke is not
|
||||
* counted as part of the remaining (Lua-visible) parameter list, matching std::bind_front
|
||||
* semantics.
|
||||
*
|
||||
* @tparam F Callable type (function pointer, member function pointer, functor).
|
||||
* @tparam BoundArgs Leading argument types to bind.
|
||||
* @param f The callable to wrap.
|
||||
* @param args Leading arguments forwarded into the wrapper by value.
|
||||
* @return A callable object whose operator() accepts the remaining (unbound) arguments.
|
||||
*/
|
||||
template <class F, class... BoundArgs>
|
||||
auto bind_front(F&& f, BoundArgs&&... args)
|
||||
{
|
||||
using Fn = std::decay_t<F>;
|
||||
using FnTraits = detail::function_traits<Fn>;
|
||||
|
||||
static constexpr std::size_t skip = std::is_member_function_pointer_v<Fn> ? 1u : 0u;
|
||||
static constexpr std::size_t num_effective_bound = sizeof...(BoundArgs) - skip;
|
||||
|
||||
using remaining = detail::tuple_drop_first_t<num_effective_bound, typename FnTraits::argument_types>;
|
||||
using R = typename FnTraits::result_type;
|
||||
|
||||
return detail::bind_front_wrapper<R, remaining, Fn, std::decay_t<BoundArgs>...>(
|
||||
std::forward<F>(f), std::forward<BoundArgs>(args)...);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* @brief Internal storage for luabridge::bind_back — exposes a non-template operator() so that
|
||||
* function_traits can statically resolve result_type and argument_types.
|
||||
*
|
||||
* LeadingArgsTuple is the tuple of arguments that the caller must provide; BoundArgs are
|
||||
* the trailing arguments captured at bind time. For member function pointers, the class
|
||||
* pointer is included as the first element of LeadingArgsTuple.
|
||||
*/
|
||||
template <class R, class LeadingArgsTuple, class Fn, class... BoundArgs>
|
||||
struct bind_back_wrapper;
|
||||
|
||||
template <class R, class... Leading, class Fn, class... BoundArgs>
|
||||
struct bind_back_wrapper<R, std::tuple<Leading...>, Fn, BoundArgs...>
|
||||
{
|
||||
Fn fn_;
|
||||
std::tuple<BoundArgs...> bound_;
|
||||
|
||||
template <class F, class... BA>
|
||||
bind_back_wrapper(F&& f, BA&&... ba)
|
||||
: fn_(std::forward<F>(f)), bound_(std::forward<BA>(ba)...)
|
||||
{
|
||||
}
|
||||
|
||||
R operator()(Leading... args) const
|
||||
{
|
||||
return std::apply([&](const auto&... ba) { return std::invoke(fn_, args..., ba...); }, bound_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Drop-in replacement for std::bind_back with statically introspectable argument types.
|
||||
*
|
||||
* Stores the callable and its trailing bound arguments, then exposes a concrete non-template
|
||||
* operator() whose parameter types are derived directly from the underlying callable's signature.
|
||||
* This lets LuaBridge register the result with addFunction / addStaticFunction without any extra
|
||||
* annotation.
|
||||
*
|
||||
* For member function pointers the class pointer is automatically prepended to the remaining
|
||||
* (Lua-visible) parameter list so that LuaBridge can dispatch it as a proxy member function.
|
||||
*
|
||||
* @tparam F Callable type (function pointer, member function pointer, functor).
|
||||
* @tparam BoundArgs Trailing argument types to bind.
|
||||
* @param f The callable to wrap.
|
||||
* @param args Trailing arguments forwarded into the wrapper by value.
|
||||
* @return A callable object whose operator() accepts the remaining (leading) arguments.
|
||||
*/
|
||||
template <class F, class... BoundArgs>
|
||||
auto bind_back(F&& f, BoundArgs&&... args)
|
||||
{
|
||||
using Fn = std::decay_t<F>;
|
||||
using FnTraits = detail::function_traits<Fn>;
|
||||
|
||||
static constexpr std::size_t num_explicit = FnTraits::arity;
|
||||
static constexpr std::size_t num_bound = sizeof...(BoundArgs);
|
||||
static constexpr std::size_t num_remaining = num_explicit - num_bound;
|
||||
|
||||
using explicit_remaining = detail::tuple_take_first_t<num_remaining, typename FnTraits::argument_types>;
|
||||
using leading = detail::bind_back_leading_t<Fn, explicit_remaining>;
|
||||
using R = typename FnTraits::result_type;
|
||||
|
||||
return detail::bind_back_wrapper<R, leading, Fn, std::decay_t<BoundArgs>...>(
|
||||
std::forward<F>(f), std::forward<BoundArgs>(args)...);
|
||||
}
|
||||
|
||||
} // namespace luabridge
|
||||
@@ -0,0 +1,77 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2023, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
#include "Stack.h"
|
||||
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Get a global value from the lua_State.
|
||||
*
|
||||
* @note This works on any type specialized by `Stack`, including `LuaRef` and its table proxies.
|
||||
*/
|
||||
template <class T>
|
||||
TypeResult<T> getGlobal(lua_State* L, const char* name)
|
||||
{
|
||||
lua_getglobal(L, name);
|
||||
|
||||
auto result = luabridge::Stack<T>::get(L, -1);
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Try to get a field from a global table without creating a LuaRef.
|
||||
*
|
||||
* This is a fast-path helper for optional lookup patterns. It invokes normal Lua field access
|
||||
* on the table, including metamethods, and returns std::nullopt when the global is not a table
|
||||
* or the field cannot be converted to the requested type.
|
||||
*/
|
||||
template <class T>
|
||||
std::optional<T> tryGetGlobalField(lua_State* L, const char* globalName, const char* fieldName)
|
||||
{
|
||||
const StackRestore stackRestore(L);
|
||||
|
||||
lua_getglobal(L, globalName);
|
||||
if (! lua_istable(L, -1))
|
||||
return std::nullopt;
|
||||
|
||||
lua_getfield(L, -1, fieldName);
|
||||
|
||||
auto result = Stack<std::decay_t<T>>::get(L, -1);
|
||||
if (! result)
|
||||
return std::nullopt;
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Set a global value in the lua_State.
|
||||
*
|
||||
* @note This works on any type specialized by `Stack`, including `LuaRef` and its table proxies.
|
||||
*/
|
||||
template <class T>
|
||||
bool setGlobal(lua_State* L, T&& t, const char* name)
|
||||
{
|
||||
if (auto result = push(L, std::forward<T>(t)))
|
||||
{
|
||||
lua_setglobal(L, name);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace luabridge
|
||||
+263
@@ -0,0 +1,263 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2021, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
#include "Errors.h"
|
||||
#include "Stack.h"
|
||||
#include "LuaRef.h"
|
||||
#include "LuaException.h"
|
||||
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
namespace detail {
|
||||
|
||||
template <class F>
|
||||
bool is_handler_valid(const F& f) noexcept
|
||||
{
|
||||
if constexpr (std::is_pointer_v<remove_cvref_t<F>>)
|
||||
return f != nullptr;
|
||||
else if constexpr (std::is_constructible_v<bool, remove_cvref_t<F>>)
|
||||
return static_cast<bool>(f);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Tuple, std::size_t... Indices>
|
||||
TypeResult<Tuple> decode_tuple_result(lua_State* L, int first_result_index, std::index_sequence<Indices...>)
|
||||
{
|
||||
auto results = std::make_tuple(
|
||||
Stack<std::tuple_element_t<Indices, Tuple>>::get(L, first_result_index + static_cast<int>(Indices))...);
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
const bool ok =
|
||||
(([&]()
|
||||
{
|
||||
const auto& element = std::get<Indices>(results);
|
||||
if (! element)
|
||||
{
|
||||
ec = element.error();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}())
|
||||
&& ...);
|
||||
|
||||
if (! ok)
|
||||
return ec;
|
||||
|
||||
return Tuple{ std::move(*std::get<Indices>(results))... };
|
||||
}
|
||||
|
||||
template <class R>
|
||||
TypeResult<R> decode_call_result(lua_State* L, int first_result_index, int num_returned_values)
|
||||
{
|
||||
if constexpr (std::is_same_v<R, void> || std::is_same_v<R, std::tuple<>>)
|
||||
{
|
||||
if (num_returned_values != 0)
|
||||
return makeErrorCode(ErrorCode::InvalidTableSizeInCast);
|
||||
|
||||
return {};
|
||||
}
|
||||
else if constexpr (is_tuple_v<R>)
|
||||
{
|
||||
constexpr auto expected_size = static_cast<int>(std::tuple_size_v<R>);
|
||||
if (num_returned_values != expected_size)
|
||||
return makeErrorCode(ErrorCode::InvalidTableSizeInCast);
|
||||
|
||||
return decode_tuple_result<R>(L, first_result_index, std::make_index_sequence<expected_size>{});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num_returned_values < 1)
|
||||
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
||||
|
||||
return Stack<R>::get(L, first_result_index);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Safely call Lua code and decode the return values to R.
|
||||
*/
|
||||
template <class R, class Ref, class F, class... Args>
|
||||
TypeResult<R> callWithHandler(const Ref& object, F&& errorHandler, Args&&... args)
|
||||
{
|
||||
static_assert(std::is_same_v<detail::remove_cvref_t<F>, detail::remove_cvref_t<decltype(std::ignore)>> || std::is_invocable_r_v<int, F, lua_State*>);
|
||||
|
||||
static constexpr bool isValidHandler =
|
||||
!std::is_same_v<detail::remove_cvref_t<F>, detail::remove_cvref_t<decltype(std::ignore)>>;
|
||||
|
||||
lua_State* L = object.state();
|
||||
const StackRestore stackRestore(L);
|
||||
const int initialTop = lua_gettop(L);
|
||||
|
||||
bool hasHandler = false;
|
||||
if constexpr (isValidHandler)
|
||||
{
|
||||
hasHandler = detail::is_handler_valid(errorHandler);
|
||||
if (hasHandler)
|
||||
detail::push_function(L, std::forward<F>(errorHandler), "");
|
||||
}
|
||||
|
||||
object.push();
|
||||
|
||||
{
|
||||
const auto [result, index] = detail::push_arguments(L, std::forward_as_tuple(args...));
|
||||
if (! result)
|
||||
return result.error();
|
||||
}
|
||||
|
||||
const int messageHandlerIndex = hasHandler ? (initialTop + 1) : 0;
|
||||
const int code = lua_pcall(L, sizeof...(Args), LUA_MULTRET, messageHandlerIndex);
|
||||
if (code != LUABRIDGE_LUA_OK)
|
||||
{
|
||||
auto ec = makeErrorCode(ErrorCode::LuaFunctionCallFailed);
|
||||
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
if constexpr (! isValidHandler)
|
||||
{
|
||||
if (LuaException::areExceptionsEnabled(L))
|
||||
LuaException::raise(L, ec);
|
||||
}
|
||||
#endif
|
||||
|
||||
lua_pop(L, 1);
|
||||
return ec;
|
||||
}
|
||||
|
||||
if (hasHandler)
|
||||
lua_remove(L, initialTop + 1);
|
||||
|
||||
const int firstResultIndex = initialTop + 1;
|
||||
const int numReturnedValues = lua_gettop(L) - initialTop;
|
||||
return detail::decode_call_result<R>(L, firstResultIndex, numReturnedValues);
|
||||
}
|
||||
|
||||
template <class Ref, class F, class... Args>
|
||||
TypeResult<void> callWithHandler(const Ref& object, F&& errorHandler, Args&&... args)
|
||||
{
|
||||
return callWithHandler<void, Ref, F, Args...>(object, std::forward<F>(errorHandler), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class R = void, class Ref, class... Args>
|
||||
TypeResult<R> call(const Ref& object, Args&&... args)
|
||||
{
|
||||
return callWithHandler<R>(object, std::ignore, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Signature>
|
||||
class LuaFunction;
|
||||
|
||||
template <class R, class... Args>
|
||||
class LuaFunction<R(Args...)>
|
||||
{
|
||||
public:
|
||||
LuaFunction() = default;
|
||||
|
||||
explicit LuaFunction(const LuaRef& function)
|
||||
: m_function(function)
|
||||
{
|
||||
}
|
||||
|
||||
explicit LuaFunction(LuaRef&& function)
|
||||
: m_function(std::move(function))
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] TypeResult<R> operator()(Args... args) const
|
||||
{
|
||||
return call(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
[[nodiscard]] TypeResult<R> call(Args... args) const
|
||||
{
|
||||
return luabridge::call<R>(m_function, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
[[nodiscard]] TypeResult<R> callWithHandler(F&& errorHandler, Args... args) const
|
||||
{
|
||||
return luabridge::callWithHandler<R>(m_function, std::forward<F>(errorHandler), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isValid() const
|
||||
{
|
||||
return m_function.isCallable();
|
||||
}
|
||||
|
||||
[[nodiscard]] const LuaRef& ref() const
|
||||
{
|
||||
return m_function;
|
||||
}
|
||||
|
||||
private:
|
||||
LuaRef m_function;
|
||||
};
|
||||
|
||||
//=============================================================================================
|
||||
/**
|
||||
* @brief Wrapper for `lua_pcall` that throws if exceptions are enabled.
|
||||
*/
|
||||
inline int pcall(lua_State* L, int nargs = 0, int nresults = 0, int msgh = 0)
|
||||
{
|
||||
const int code = lua_pcall(L, nargs, nresults, msgh);
|
||||
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
if (code != LUABRIDGE_LUA_OK && LuaException::areExceptionsEnabled(L))
|
||||
LuaException::raise(L, makeErrorCode(ErrorCode::LuaFunctionCallFailed));
|
||||
#endif
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
//=============================================================================================
|
||||
template <class Impl, class LuaRef>
|
||||
template <class R, class... Args>
|
||||
TypeResult<R> LuaRefBase<Impl, LuaRef>::call(Args&&... args) const
|
||||
{
|
||||
return luabridge::call<R>(impl(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Impl, class LuaRef>
|
||||
template <class... Args>
|
||||
TypeResult<void> LuaRefBase<Impl, LuaRef>::operator()(Args&&... args) const
|
||||
{
|
||||
return call<void>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Impl, class LuaRef>
|
||||
template <class R, class F, class... Args>
|
||||
TypeResult<R> LuaRefBase<Impl, LuaRef>::callWithHandler(F&& errorHandler, Args&&... args) const
|
||||
{
|
||||
return luabridge::callWithHandler<R>(impl(), std::forward<F>(errorHandler), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Impl, class LuaRef>
|
||||
template <class F, class... Args>
|
||||
TypeResult<void> LuaRefBase<Impl, LuaRef>::callWithHandler(F&& errorHandler, Args&&... args) const
|
||||
{
|
||||
return callWithHandler<void>(std::forward<F>(errorHandler), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Impl, class LuaRef>
|
||||
template <class Signature>
|
||||
LuaFunction<Signature> LuaRefBase<Impl, LuaRef>::callable() const
|
||||
{
|
||||
const StackRestore stackRestore(m_L);
|
||||
impl().push(m_L);
|
||||
return LuaFunction<Signature>(LuaRef::fromStack(m_L));
|
||||
}
|
||||
|
||||
} // namespace luabridge
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2018, Dmitry Tarakanov
|
||||
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "LuaRef.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#if LUABRIDGE_HAS_CXX20_RANGES
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
#endif
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Iterator class to allow table iteration.
|
||||
*
|
||||
* @see Range class.
|
||||
*/
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
explicit Iterator(const LuaRef& table, bool isEnd = false)
|
||||
: m_L(table.state())
|
||||
, m_table(table)
|
||||
, m_key(table.state()) // m_key is nil
|
||||
, m_value(table.state()) // m_value is nil
|
||||
{
|
||||
if (! isEnd)
|
||||
{
|
||||
next(); // get the first (key, value) pair from table
|
||||
}
|
||||
}
|
||||
|
||||
#if LUABRIDGE_HAS_CXX20_RANGES
|
||||
using value_type = std::pair<LuaRef, LuaRef>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_concept = std::input_iterator_tag;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Return an associated Lua state.
|
||||
*
|
||||
* @return A Lua state.
|
||||
*/
|
||||
lua_State* state() const noexcept
|
||||
{
|
||||
return m_L;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dereference the iterator.
|
||||
*
|
||||
* @return A key-value pair for a current table entry.
|
||||
*/
|
||||
std::pair<LuaRef, LuaRef> operator*() const
|
||||
{
|
||||
return std::make_pair(m_key, m_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the value referred by the iterator.
|
||||
*
|
||||
* @return A value for the current table entry.
|
||||
*/
|
||||
LuaRef operator->() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare two iterators.
|
||||
*
|
||||
* @param rhs Another iterator.
|
||||
*
|
||||
* @return True if iterators point to the same entry of the same table, false otherwise.
|
||||
*/
|
||||
bool operator!=(const Iterator& rhs) const
|
||||
{
|
||||
LUABRIDGE_ASSERT(m_L == rhs.m_L);
|
||||
|
||||
return ! m_table.rawequal(rhs.m_table) || ! m_key.rawequal(rhs.m_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move the iterator to the next table entry.
|
||||
*
|
||||
* @return This iterator.
|
||||
*/
|
||||
Iterator& operator++()
|
||||
{
|
||||
if (isNil())
|
||||
{
|
||||
// if the iterator reaches the end, do nothing
|
||||
return *this;
|
||||
}
|
||||
else
|
||||
{
|
||||
next();
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the iterator points after the last table entry.
|
||||
*
|
||||
* @return True if there are no more table entries to iterate, false otherwise.
|
||||
*/
|
||||
bool isNil() const noexcept
|
||||
{
|
||||
return m_key.isNil();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the key for the current table entry.
|
||||
*
|
||||
* @return A reference to the entry key.
|
||||
*/
|
||||
LuaRef key() const
|
||||
{
|
||||
return m_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the key for the current table entry.
|
||||
*
|
||||
* @return A reference to the entry value.
|
||||
*/
|
||||
LuaRef value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
// Don't use postfix increment, it is less efficient
|
||||
Iterator operator++(int);
|
||||
|
||||
void next()
|
||||
{
|
||||
#if LUABRIDGE_SAFE_STACK_CHECKS
|
||||
if (! lua_checkstack(m_L, 2))
|
||||
{
|
||||
m_key = LuaNil();
|
||||
m_value = LuaNil();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_table.push();
|
||||
m_key.push();
|
||||
|
||||
if (lua_next(m_L, -2))
|
||||
{
|
||||
m_value.pop();
|
||||
m_key.pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_key = LuaNil();
|
||||
m_value = LuaNil();
|
||||
}
|
||||
|
||||
lua_pop(m_L, 1);
|
||||
}
|
||||
|
||||
lua_State* m_L = nullptr;
|
||||
LuaRef m_table;
|
||||
LuaRef m_key;
|
||||
LuaRef m_value;
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Range class taking two table iterators.
|
||||
*/
|
||||
class Range
|
||||
{
|
||||
public:
|
||||
Range(const Iterator& begin, const Iterator& end)
|
||||
: m_begin(begin)
|
||||
, m_end(end)
|
||||
{
|
||||
}
|
||||
|
||||
const Iterator& begin() const noexcept
|
||||
{
|
||||
return m_begin;
|
||||
}
|
||||
|
||||
const Iterator& end() const noexcept
|
||||
{
|
||||
return m_end;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator m_begin;
|
||||
Iterator m_end;
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Return a range for the Lua table reference.
|
||||
*
|
||||
* @return A range suitable for range-based for statement.
|
||||
*/
|
||||
inline Range pairs(const LuaRef& table)
|
||||
{
|
||||
return Range{ Iterator(table, false), Iterator(table, true) };
|
||||
}
|
||||
|
||||
#if LUABRIDGE_HAS_CXX20_RANGES
|
||||
|
||||
/**
|
||||
* @brief Equality comparison for Iterator.
|
||||
*/
|
||||
inline bool operator==(const Iterator& lhs, const Iterator& rhs)
|
||||
{
|
||||
if (lhs.isNil() && rhs.isNil())
|
||||
return true;
|
||||
if (lhs.isNil() != rhs.isNil())
|
||||
return false;
|
||||
return lhs.key().rawequal(rhs.key()) && lhs.value().rawequal(rhs.value());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sentinel type for Iterator end detection.
|
||||
*/
|
||||
struct IteratorSentinel {};
|
||||
|
||||
/**
|
||||
* @brief Sentinel equality: Iterator is at end when isNil().
|
||||
*/
|
||||
inline bool operator==(const Iterator& it, IteratorSentinel)
|
||||
{
|
||||
return it.isNil();
|
||||
}
|
||||
|
||||
inline bool operator==(IteratorSentinel, const Iterator& it)
|
||||
{
|
||||
return it.isNil();
|
||||
}
|
||||
|
||||
#endif // LUABRIDGE_HAS_CXX20_RANGES
|
||||
|
||||
} // namespace luabridge
|
||||
|
||||
#if LUABRIDGE_HAS_CXX20_RANGES
|
||||
template <>
|
||||
inline constexpr bool std::ranges::enable_borrowed_range<luabridge::Range> = false;
|
||||
#endif
|
||||
@@ -0,0 +1,189 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2021, kunitoki
|
||||
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
// Copyright 2008, Nigel Atkinson <suprapilot+LuaCode@gmail.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include "ClassInfo.h"
|
||||
#include "LuaHelpers.h"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <exception>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//================================================================================================
|
||||
class LuaException : public std::exception
|
||||
{
|
||||
public:
|
||||
//=============================================================================================
|
||||
/**
|
||||
* @brief Construct a LuaException after a lua_pcall().
|
||||
*
|
||||
* Assumes the error string is on top of the stack, but provides a generic error message otherwise.
|
||||
*/
|
||||
LuaException(lua_State* L, std::error_code code)
|
||||
: m_L(L)
|
||||
, m_code(code)
|
||||
{
|
||||
}
|
||||
|
||||
~LuaException() noexcept override
|
||||
{
|
||||
}
|
||||
|
||||
//=============================================================================================
|
||||
/**
|
||||
* @brief Return the error message.
|
||||
*/
|
||||
const char* what() const noexcept override
|
||||
{
|
||||
return m_what.c_str();
|
||||
}
|
||||
|
||||
//=============================================================================================
|
||||
/**
|
||||
* @brief Throw an exception or raises a luaerror when exceptions are disabled.
|
||||
*/
|
||||
static void raise(lua_State* L, std::error_code code)
|
||||
{
|
||||
LUABRIDGE_ASSERT(areExceptionsEnabled(L));
|
||||
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
throw LuaException(L, code, FromLua{});
|
||||
#else
|
||||
unused(L, code);
|
||||
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
//=============================================================================================
|
||||
/**
|
||||
* @brief Check if exceptions are enabled.
|
||||
*/
|
||||
static bool areExceptionsEnabled(lua_State* L) noexcept
|
||||
{
|
||||
lua_pushlightuserdata(L, detail::getExceptionsKey());
|
||||
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||
|
||||
const bool enabled = lua_isboolean(L, -1) ? static_cast<bool>(lua_toboolean(L, -1)) : false;
|
||||
lua_pop(L, 1);
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes error handling.
|
||||
*
|
||||
* Subsequent Lua errors are translated to C++ exceptions, or logging and abort if exceptions are disabled.
|
||||
*/
|
||||
static void enableExceptions(lua_State* L) noexcept
|
||||
{
|
||||
lua_pushlightuserdata(L, detail::getExceptionsKey());
|
||||
lua_pushboolean(L, true);
|
||||
lua_settable(L, LUA_REGISTRYINDEX);
|
||||
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS && LUABRIDGE_ON_LUAJIT
|
||||
lua_pushlightuserdata(L, (void*)luajitWrapperCallback);
|
||||
luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON);
|
||||
lua_pop(L, 1);
|
||||
#endif
|
||||
|
||||
#if LUABRIDGE_ON_LUAU
|
||||
auto callbacks = lua_callbacks(L);
|
||||
callbacks->panic = +[](lua_State* L, int) { panicHandlerCallback(L); };
|
||||
#else
|
||||
lua_atpanic(L, panicHandlerCallback);
|
||||
#endif
|
||||
}
|
||||
|
||||
//=============================================================================================
|
||||
/**
|
||||
* @brief Retrieve the lua_State associated with the exception.
|
||||
*
|
||||
* @return A Lua state.
|
||||
*/
|
||||
lua_State* state() const { return m_L; }
|
||||
|
||||
private:
|
||||
struct FromLua {};
|
||||
|
||||
LuaException(lua_State* L, std::error_code code, FromLua)
|
||||
: m_L(L)
|
||||
, m_code(code)
|
||||
{
|
||||
whatFromStack();
|
||||
}
|
||||
|
||||
void whatFromStack()
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
const char* errorText = nullptr;
|
||||
|
||||
if (lua_gettop(m_L) > 0)
|
||||
{
|
||||
errorText = lua_tostring(m_L, -1);
|
||||
lua_pop(m_L, 1);
|
||||
}
|
||||
|
||||
ss << (errorText ? errorText : "Unknown error") << " (code=" << m_code.message() << ")";
|
||||
|
||||
m_what = std::move(ss).str();
|
||||
}
|
||||
|
||||
static int panicHandlerCallback(lua_State* L)
|
||||
{
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
throw LuaException(L, makeErrorCode(ErrorCode::LuaFunctionCallFailed), FromLua{});
|
||||
#else
|
||||
unused(L);
|
||||
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS && LUABRIDGE_ON_LUAJIT
|
||||
static int luajitWrapperCallback(lua_State* L, lua_CFunction f)
|
||||
{
|
||||
try
|
||||
{
|
||||
return f(L);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
lua_pushstring(L, e.what());
|
||||
lua_error_x(L);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
lua_State* m_L = nullptr;
|
||||
std::error_code m_code;
|
||||
std::string m_what;
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Initializes error handling using C++ exceptions.
|
||||
*
|
||||
* Subsequent Lua errors are translated to C++ exceptions. It aborts the application if called when no exceptions.
|
||||
*/
|
||||
inline void enableExceptions(lua_State* L) noexcept
|
||||
{
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
LuaException::enableExceptions(L);
|
||||
#else
|
||||
unused(L);
|
||||
|
||||
LUABRIDGE_ASSERT(false); // Never call this function when exceptions are not enabled.
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace luabridge
|
||||
@@ -0,0 +1,756 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
// Copyright 2007, Nathan Reed
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FuncTraits.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
/**
|
||||
* @brief Helper for unused vars.
|
||||
*/
|
||||
template <class... Args>
|
||||
constexpr void unused(Args&&...)
|
||||
{
|
||||
}
|
||||
|
||||
// These are for Lua versions prior to 5.2.0.
|
||||
#if LUA_VERSION_NUM < 502
|
||||
using lua_Unsigned = std::make_unsigned_t<lua_Integer>;
|
||||
|
||||
#if ! LUABRIDGE_ON_LUAU
|
||||
inline int lua_absindex(lua_State* L, int idx)
|
||||
{
|
||||
if (idx > LUA_REGISTRYINDEX && idx < 0)
|
||||
return lua_gettop(L) + idx + 1;
|
||||
else
|
||||
return idx;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define LUA_OPEQ 1
|
||||
#define LUA_OPLT 2
|
||||
#define LUA_OPLE 3
|
||||
|
||||
inline int lua_compare(lua_State* L, int idx1, int idx2, int op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case LUA_OPEQ:
|
||||
return lua_equal(L, idx1, idx2);
|
||||
|
||||
case LUA_OPLT:
|
||||
return lua_lessthan(L, idx1, idx2);
|
||||
|
||||
case LUA_OPLE:
|
||||
return lua_equal(L, idx1, idx2) || lua_lessthan(L, idx1, idx2);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if ! LUABRIDGE_ON_LUAJIT
|
||||
inline void* luaL_testudata(lua_State* L, int ud, const char* tname)
|
||||
{
|
||||
void* p = lua_touserdata(L, ud);
|
||||
if (p == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if (! lua_getmetatable(L, ud))
|
||||
return nullptr;
|
||||
|
||||
luaL_getmetatable(L, tname);
|
||||
if (! lua_rawequal(L, -1, -2))
|
||||
p = nullptr;
|
||||
|
||||
lua_pop(L, 2);
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline int get_length(lua_State* L, int idx)
|
||||
{
|
||||
return static_cast<int>(lua_objlen(L, idx));
|
||||
}
|
||||
#else // LUA_VERSION_NUM >= 502
|
||||
inline int get_length(lua_State* L, int idx)
|
||||
{
|
||||
return static_cast<int>(lua_rawlen(L, idx));
|
||||
}
|
||||
#endif // LUA_VERSION_NUM < 502
|
||||
|
||||
// These functions and defines are for Luau.
|
||||
#if LUABRIDGE_ON_LUAU
|
||||
inline int luaL_ref(lua_State* L, int idx)
|
||||
{
|
||||
LUABRIDGE_ASSERT(idx == LUA_REGISTRYINDEX);
|
||||
|
||||
const int ref = lua_ref(L, -1);
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
inline void luaL_unref(lua_State* L, int idx, int ref)
|
||||
{
|
||||
unused(idx);
|
||||
|
||||
lua_unref(L, ref);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void* lua_newuserdata_x(lua_State* L, size_t sz)
|
||||
{
|
||||
return lua_newuserdatadtor(L, sz, [](void* x)
|
||||
{
|
||||
T* object = static_cast<T*>(x);
|
||||
object->~T();
|
||||
});
|
||||
}
|
||||
|
||||
inline void lua_pushcfunction_x(lua_State *L, lua_CFunction fn, const char* debugname)
|
||||
{
|
||||
lua_pushcfunction(L, fn, debugname);
|
||||
}
|
||||
|
||||
inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debugname, int n)
|
||||
{
|
||||
lua_pushcclosure(L, fn, debugname, n);
|
||||
}
|
||||
|
||||
[[noreturn]] inline void lua_error_x(lua_State* L)
|
||||
{
|
||||
lua_error(L);
|
||||
}
|
||||
|
||||
inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar)
|
||||
{
|
||||
return lua_getinfo(L, level, "nlS", ar);
|
||||
}
|
||||
|
||||
inline int lua_getstack_info_x(lua_State* L, int level, const char* what, lua_Debug* ar)
|
||||
{
|
||||
return lua_getinfo(L, level, what, ar);
|
||||
}
|
||||
|
||||
inline int lua_rawgetp_x(lua_State* L, int idx, void* p)
|
||||
{
|
||||
return lua_rawgetp(L, idx, p);
|
||||
}
|
||||
|
||||
inline void lua_rawsetp_x(lua_State* L, int idx, void* p)
|
||||
{
|
||||
lua_rawsetp(L, idx, p);
|
||||
}
|
||||
|
||||
#else
|
||||
using ::luaL_ref;
|
||||
using ::luaL_unref;
|
||||
|
||||
template <class T>
|
||||
inline void* lua_newuserdata_x(lua_State* L, size_t sz)
|
||||
{
|
||||
return lua_newuserdata(L, sz);
|
||||
}
|
||||
|
||||
inline void lua_pushcfunction_x(lua_State *L, lua_CFunction fn, const char* debugname)
|
||||
{
|
||||
unused(debugname);
|
||||
|
||||
lua_pushcfunction(L, fn);
|
||||
}
|
||||
|
||||
inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debugname, int n)
|
||||
{
|
||||
unused(debugname);
|
||||
|
||||
lua_pushcclosure(L, fn, n);
|
||||
}
|
||||
|
||||
[[noreturn]] inline void lua_error_x(lua_State* L)
|
||||
{
|
||||
lua_error(L);
|
||||
|
||||
detail::unreachable();
|
||||
}
|
||||
|
||||
inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar)
|
||||
{
|
||||
return lua_getstack(L, level, ar);
|
||||
}
|
||||
|
||||
inline int lua_getstack_info_x(lua_State* L, int level, const char* what, lua_Debug* ar)
|
||||
{
|
||||
lua_getstack(L, level, ar);
|
||||
return lua_getinfo(L, what, ar);
|
||||
}
|
||||
|
||||
inline int lua_rawgetp_x(lua_State* L, int idx, void* p)
|
||||
{
|
||||
#if LUA_VERSION_NUM < 503
|
||||
idx = lua_absindex(L, idx);
|
||||
luaL_checkstack(L, 1, "not enough stack slots");
|
||||
lua_pushlightuserdata(L, p);
|
||||
lua_rawget(L, idx);
|
||||
return lua_type(L, -1);
|
||||
#else
|
||||
return lua_rawgetp(L, idx, p);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void lua_rawsetp_x(lua_State* L, int idx, void* p)
|
||||
{
|
||||
#if LUA_VERSION_NUM < 503
|
||||
idx = lua_absindex(L, idx);
|
||||
luaL_checkstack(L, 1, "not enough stack slots");
|
||||
lua_pushlightuserdata(L, p);
|
||||
lua_insert(L, -2);
|
||||
lua_rawset(L, idx);
|
||||
#else
|
||||
lua_rawsetp(L, idx, p);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // LUABRIDGE_ON_LUAU
|
||||
|
||||
// These are for Lua versions prior to 5.5.0.
|
||||
#if LUA_VERSION_NUM < 505
|
||||
inline lua_State* lua_newstate_x(lua_Alloc f, void* ud, [[maybe_unused]] unsigned seed)
|
||||
{
|
||||
return lua_newstate(f, ud);
|
||||
}
|
||||
#else
|
||||
inline lua_State* lua_newstate_x(lua_Alloc f, void* ud, unsigned seed)
|
||||
{
|
||||
return lua_newstate(f, ud, seed);
|
||||
}
|
||||
#endif
|
||||
|
||||
// These are for Lua versions prior to 5.3.0.
|
||||
#if LUA_VERSION_NUM < 503
|
||||
inline lua_Number to_numberx(lua_State* L, int idx, int* isnum)
|
||||
{
|
||||
lua_Number n = lua_tonumber(L, idx);
|
||||
|
||||
if (isnum)
|
||||
*isnum = (n != 0 || lua_isnumber(L, idx));
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
inline lua_Integer to_integerx(lua_State* L, int idx, int* isnum)
|
||||
{
|
||||
int ok = 0;
|
||||
lua_Number n = to_numberx(L, idx, &ok);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
if (n < static_cast<lua_Number>(std::numeric_limits<lua_Integer>::min()) ||
|
||||
n >= -static_cast<lua_Number>(std::numeric_limits<lua_Integer>::min()))
|
||||
{
|
||||
if (isnum)
|
||||
*isnum = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto int_n = static_cast<lua_Integer>(n);
|
||||
if (n == static_cast<lua_Number>(int_n))
|
||||
{
|
||||
if (isnum)
|
||||
*isnum = 1;
|
||||
|
||||
return int_n;
|
||||
}
|
||||
}
|
||||
|
||||
if (isnum)
|
||||
*isnum = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif // LUA_VERSION_NUM < 503
|
||||
|
||||
inline int lua_rawgetp_x(lua_State* L, int idx, const void* p)
|
||||
{
|
||||
return lua_rawgetp_x(L, idx, const_cast<void*>(p));
|
||||
}
|
||||
|
||||
inline void lua_rawsetp_x(lua_State* L, int idx, const void* p)
|
||||
{
|
||||
lua_rawsetp_x(L, idx, const_cast<void*>(p));
|
||||
}
|
||||
|
||||
#ifndef LUA_OK
|
||||
#define LUABRIDGE_LUA_OK 0
|
||||
#else
|
||||
#define LUABRIDGE_LUA_OK LUA_OK
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Helper to throw or return an error code.
|
||||
*/
|
||||
template <class T, class ErrorType>
|
||||
std::error_code throw_or_error_code(ErrorType error)
|
||||
{
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
throw T(makeErrorCode(error).message().c_str());
|
||||
#else
|
||||
return makeErrorCode(error);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T, class ErrorType>
|
||||
std::error_code throw_or_error_code(lua_State* L, ErrorType error)
|
||||
{
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
throw T(L, makeErrorCode(error));
|
||||
#else
|
||||
return unused(L), makeErrorCode(error);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper to throw or LUABRIDGE_ASSERT.
|
||||
*/
|
||||
template <class T, class... Args>
|
||||
void throw_or_assert(Args&&... args)
|
||||
{
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
throw T(std::forward<Args>(args)...);
|
||||
#else
|
||||
unused(std::forward<Args>(args)...);
|
||||
LUABRIDGE_ASSERT(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper to set unsigned.
|
||||
*/
|
||||
template <class T>
|
||||
void pushunsigned(lua_State* L, T value)
|
||||
{
|
||||
static_assert(std::is_unsigned_v<T>);
|
||||
|
||||
lua_pushinteger(L, static_cast<lua_Integer>(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper to convert to integer.
|
||||
*/
|
||||
inline lua_Number tonumber(lua_State* L, int idx, int* isnum)
|
||||
{
|
||||
#if ! LUABRIDGE_ON_LUAU && LUA_VERSION_NUM > 502
|
||||
return lua_tonumberx(L, idx, isnum);
|
||||
#else
|
||||
return to_numberx(L, idx, isnum);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper to convert to integer.
|
||||
*/
|
||||
inline lua_Integer tointeger(lua_State* L, int idx, int* isnum)
|
||||
{
|
||||
#if ! LUABRIDGE_ON_LUAU && LUA_VERSION_NUM > 502
|
||||
return lua_tointegerx(L, idx, isnum);
|
||||
#else
|
||||
return to_integerx(L, idx, isnum);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Register main thread, only supported on 5.1.
|
||||
*/
|
||||
inline constexpr char main_thread_name[] = "__luabridge_main_thread";
|
||||
|
||||
inline void register_main_thread(lua_State* threadL)
|
||||
{
|
||||
#if LUA_VERSION_NUM < 502
|
||||
if (threadL == nullptr)
|
||||
lua_pushnil(threadL);
|
||||
else
|
||||
lua_pushthread(threadL);
|
||||
|
||||
lua_setglobal(threadL, main_thread_name);
|
||||
#else
|
||||
unused(threadL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get main thread, not supported on 5.1.
|
||||
*/
|
||||
inline lua_State* main_thread(lua_State* threadL)
|
||||
{
|
||||
#if LUA_VERSION_NUM < 502
|
||||
lua_getglobal(threadL, main_thread_name);
|
||||
if (lua_isthread(threadL, -1))
|
||||
{
|
||||
auto L = lua_tothread(threadL, -1);
|
||||
lua_pop(threadL, 1);
|
||||
return L;
|
||||
}
|
||||
LUABRIDGE_ASSERT(false); // Have you forgot to call luabridge::registerMainThread ?
|
||||
lua_pop(threadL, 1);
|
||||
return threadL;
|
||||
#else
|
||||
lua_rawgeti(threadL, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);
|
||||
lua_State* L = lua_tothread(threadL, -1);
|
||||
lua_pop(threadL, 1);
|
||||
return L;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a table value, bypassing metamethods.
|
||||
*/
|
||||
inline int rawgetfield(lua_State* L, int index, const char* key)
|
||||
{
|
||||
LUABRIDGE_ASSERT(lua_istable(L, index));
|
||||
index = lua_absindex(L, index);
|
||||
lua_pushstring(L, key);
|
||||
#if LUA_VERSION_NUM <= 502
|
||||
lua_rawget(L, index);
|
||||
return lua_type(L, -1);
|
||||
#else
|
||||
return lua_rawget(L, index);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a table value, bypassing metamethods.
|
||||
*/
|
||||
inline void rawsetfield(lua_State* L, int index, const char* key)
|
||||
{
|
||||
LUABRIDGE_ASSERT(lua_istable(L, index));
|
||||
index = lua_absindex(L, index);
|
||||
lua_pushstring(L, key);
|
||||
lua_insert(L, -2);
|
||||
lua_rawset(L, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if the value is a full userdata (not light).
|
||||
*/
|
||||
[[nodiscard]] inline bool isfulluserdata(lua_State* L, int index)
|
||||
{
|
||||
return lua_isuserdata(L, index) && !lua_islightuserdata(L, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test lua_State objects for global equality.
|
||||
*
|
||||
* This can determine if two different lua_State objects really point
|
||||
* to the same global state, such as when using coroutines.
|
||||
*
|
||||
* @note This is used for assertions.
|
||||
*/
|
||||
[[nodiscard]] inline bool equalstates(lua_State* L1, lua_State* L2)
|
||||
{
|
||||
return lua_topointer(L1, LUA_REGISTRYINDEX) == lua_topointer(L2, LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the size of lua table, even if not a sequence { 1=x, 2=y, 3=... }.
|
||||
*/
|
||||
[[nodiscard]] inline int table_length(lua_State* L, int index)
|
||||
{
|
||||
LUABRIDGE_ASSERT(lua_istable(L, index));
|
||||
|
||||
int items_count = 0;
|
||||
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, index) != 0)
|
||||
{
|
||||
++items_count;
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return items_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return an aligned pointer of type T.
|
||||
*/
|
||||
template <class T>
|
||||
[[nodiscard]] T* align(void* ptr) noexcept
|
||||
{
|
||||
const auto address = reinterpret_cast<size_t>(ptr);
|
||||
|
||||
const auto offset = address % alignof(T);
|
||||
const auto aligned_address = (offset == 0) ? address : (address + alignof(T) - offset);
|
||||
|
||||
return reinterpret_cast<T*>(aligned_address);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return if a pointer of type T is aligned.
|
||||
*/
|
||||
template <std::size_t Alignment, class T, std::enable_if_t<std::is_pointer_v<T>, int> = 0>
|
||||
[[nodiscard]] bool is_aligned(T address) noexcept
|
||||
{
|
||||
static_assert(Alignment > 0u);
|
||||
|
||||
return (reinterpret_cast<std::uintptr_t>(address) & (Alignment - 1u)) == 0u;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the space needed to align the type T on an unaligned address.
|
||||
*/
|
||||
template <class T>
|
||||
[[nodiscard]] constexpr size_t maximum_space_needed_to_align() noexcept
|
||||
{
|
||||
return sizeof(T) + alignof(T) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deallocate lua userdata taking into account alignment.
|
||||
*/
|
||||
template <class T>
|
||||
int lua_deleteuserdata_aligned(lua_State* L)
|
||||
{
|
||||
LUABRIDGE_ASSERT(isfulluserdata(L, 1));
|
||||
|
||||
T* aligned = align<T>(lua_touserdata(L, 1));
|
||||
aligned->~T();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate lua userdata taking into account alignment.
|
||||
*
|
||||
* Using this instead of lua_newuserdata directly prevents alignment warnings on 64bits platforms.
|
||||
*/
|
||||
template <class T, class... Args>
|
||||
void* lua_newuserdata_aligned(lua_State* L, Args&&... args)
|
||||
{
|
||||
using U = std::remove_reference_t<T>;
|
||||
|
||||
#if LUABRIDGE_ON_LUAU
|
||||
void* pointer = lua_newuserdatadtor(L, maximum_space_needed_to_align<U>(), [](void* x)
|
||||
{
|
||||
U* aligned = align<U>(x);
|
||||
aligned->~U();
|
||||
});
|
||||
#else
|
||||
void* pointer = lua_newuserdata_x<U>(L, maximum_space_needed_to_align<U>());
|
||||
|
||||
lua_newtable(L);
|
||||
lua_pushcfunction_x(L, &lua_deleteuserdata_aligned<U>, "");
|
||||
rawsetfield(L, -2, "__gc");
|
||||
lua_setmetatable(L, -2);
|
||||
#endif
|
||||
|
||||
U* aligned = align<U>(pointer);
|
||||
|
||||
new (aligned) U(std::forward<Args>(args)...);
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Safe error able to walk backwards for error reporting correctly.
|
||||
*/
|
||||
[[noreturn]] inline void raise_lua_error(lua_State* L, const char* fmt, ...)
|
||||
{
|
||||
va_list argp;
|
||||
va_start(argp, fmt);
|
||||
lua_pushvfstring(L, fmt, argp);
|
||||
va_end(argp);
|
||||
|
||||
const char* message = lua_tostring(L, -1);
|
||||
if (message != nullptr)
|
||||
{
|
||||
if (auto str = std::string_view(message); !str.empty() && str[0] == '[')
|
||||
lua_error_x(L);
|
||||
}
|
||||
|
||||
bool pushed_error = false;
|
||||
for (int level = 1; level <= 2; ++level)
|
||||
{
|
||||
lua_Debug ar;
|
||||
|
||||
#if LUABRIDGE_ON_LUAU
|
||||
if (lua_getinfo(L, level, "sl", &ar) == 0)
|
||||
continue;
|
||||
#else
|
||||
if (lua_getstack(L, level, &ar) == 0 || lua_getinfo(L, "Sl", &ar) == 0)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if (ar.currentline <= 0)
|
||||
continue;
|
||||
|
||||
lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
|
||||
pushed_error = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (! pushed_error)
|
||||
lua_pushliteral(L, "");
|
||||
|
||||
lua_pushvalue(L, -2);
|
||||
lua_remove(L, -3);
|
||||
lua_concat(L, 2);
|
||||
|
||||
lua_error_x(L);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the value on the stack is a number type and can fit into the corresponding c++ integral type..
|
||||
*/
|
||||
template <class U = lua_Integer, class T>
|
||||
constexpr bool is_integral_representable_by(T value)
|
||||
{
|
||||
constexpr bool same_signedness = (std::is_unsigned_v<T> && std::is_unsigned_v<U>)
|
||||
|| (!std::is_unsigned_v<T> && !std::is_unsigned_v<U>);
|
||||
|
||||
if constexpr (sizeof(T) == sizeof(U))
|
||||
{
|
||||
if constexpr (same_signedness)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if constexpr (std::is_unsigned_v<T>)
|
||||
{
|
||||
return value <= static_cast<T>((std::numeric_limits<U>::max)());
|
||||
}
|
||||
else
|
||||
{
|
||||
return value >= static_cast<T>((std::numeric_limits<U>::min)())
|
||||
&& static_cast<U>(value) <= (std::numeric_limits<U>::max)();
|
||||
}
|
||||
}
|
||||
else if constexpr (sizeof(T) < sizeof(U))
|
||||
{
|
||||
return static_cast<U>(value) >= (std::numeric_limits<U>::min)()
|
||||
&& static_cast<U>(value) <= (std::numeric_limits<U>::max)();
|
||||
}
|
||||
else if constexpr (std::is_unsigned_v<T>)
|
||||
{
|
||||
return value <= static_cast<T>((std::numeric_limits<U>::max)());
|
||||
}
|
||||
else
|
||||
{
|
||||
return value >= static_cast<T>((std::numeric_limits<U>::min)())
|
||||
&& value <= static_cast<T>((std::numeric_limits<U>::max)());
|
||||
}
|
||||
}
|
||||
|
||||
template <class U = lua_Integer>
|
||||
bool is_integral_representable_by(lua_State* L, int index)
|
||||
{
|
||||
int isValid = 0;
|
||||
|
||||
const auto value = tointeger(L, index, &isValid);
|
||||
|
||||
return isValid ? is_integral_representable_by<U>(value) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the value on the stack is a number type and can fit into the corresponding c++ numerical type..
|
||||
*/
|
||||
template <class U = lua_Number, class T>
|
||||
bool is_floating_point_representable_by(T value)
|
||||
{
|
||||
if constexpr (sizeof(T) == sizeof(U))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if constexpr (sizeof(T) < sizeof(U))
|
||||
{
|
||||
if (std::isnan(value) || std::isinf(value))
|
||||
return true;
|
||||
|
||||
return static_cast<U>(value) >= -(std::numeric_limits<U>::max)()
|
||||
&& static_cast<U>(value) <= (std::numeric_limits<U>::max)();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::isnan(value) || std::isinf(value))
|
||||
return true;
|
||||
|
||||
return value >= static_cast<T>(-(std::numeric_limits<U>::max)())
|
||||
&& value <= static_cast<T>((std::numeric_limits<U>::max)());
|
||||
}
|
||||
}
|
||||
|
||||
template <class U = lua_Number>
|
||||
bool is_floating_point_representable_by(lua_State* L, int index)
|
||||
{
|
||||
int isValid = 0;
|
||||
|
||||
const auto value = tonumber(L, index, &isValid);
|
||||
|
||||
return isValid ? is_floating_point_representable_by<U>(value) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Portable wrapper for lua_resume that normalises calling convention differences
|
||||
* across Lua 5.1/LuaJIT (no from, no nresults), 5.2-5.3 (from but no nresults), and 5.4+ (from + nresults).
|
||||
*
|
||||
* @param L The coroutine thread to resume.
|
||||
* @param from The thread doing the resuming (may be nullptr on older Lua).
|
||||
* @param nargs Number of arguments on L's stack to pass to the resumed function.
|
||||
* @param nresults Output: number of values on L's stack after resume (yielded or returned).
|
||||
* For Lua 5.4+, filled directly by lua_resume. For older versions, computed via lua_gettop.
|
||||
* @returns LUA_OK, LUA_YIELD, or an error code.
|
||||
*/
|
||||
inline int lua_resume_x(lua_State* L, lua_State* from, int nargs, int* nresults = nullptr)
|
||||
{
|
||||
#if LUABRIDGE_ON_LUAJIT || LUA_VERSION_NUM == 501
|
||||
unused(from);
|
||||
int status = lua_resume(L, nargs);
|
||||
if (nresults)
|
||||
*nresults = lua_gettop(L);
|
||||
return status;
|
||||
#elif LUABRIDGE_ON_LUAU || LUABRIDGE_ON_RAVI || LUA_VERSION_NUM < 504
|
||||
int status = lua_resume(L, from, nargs);
|
||||
if (nresults)
|
||||
*nresults = lua_gettop(L);
|
||||
return status;
|
||||
#else
|
||||
int nr = 0;
|
||||
int status = lua_resume(L, from, nargs, &nr);
|
||||
if (nresults)
|
||||
*nresults = nr;
|
||||
return status;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if the currently running C function can yield via lua_yieldk.
|
||||
*
|
||||
* Returns false on Lua 5.1, LuaJIT, and Luau where lua_yieldk is unavailable.
|
||||
*/
|
||||
inline bool lua_isyieldable_x(lua_State* L)
|
||||
{
|
||||
#if LUABRIDGE_ON_LUAJIT || LUA_VERSION_NUM == 501 || LUABRIDGE_ON_LUAU
|
||||
unused(L);
|
||||
return false;
|
||||
#elif LUA_VERSION_NUM < 503
|
||||
unused(L);
|
||||
return true; // lua_yieldk exists in 5.2; assume yieldable when reached
|
||||
#else
|
||||
return lua_isyieldable(L) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace luabridge
|
||||
+1920
File diff suppressed because it is too large
Load Diff
+2173
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2023, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FlagSet.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
namespace detail {
|
||||
struct OptionExtensibleClass;
|
||||
struct OptionAllowOverridingMethods;
|
||||
struct OptionVisibleMetatables;
|
||||
} // namespace Detail
|
||||
|
||||
/**
|
||||
* @brief Options for the library.
|
||||
*/
|
||||
using Options = FlagSet<uint32_t,
|
||||
detail::OptionExtensibleClass,
|
||||
detail::OptionAllowOverridingMethods,
|
||||
detail::OptionVisibleMetatables>;
|
||||
|
||||
/**
|
||||
* @brief Set of default options.
|
||||
*
|
||||
* This setting means all options are not enabled.
|
||||
*/
|
||||
static inline constexpr Options defaultOptions = Options();
|
||||
|
||||
/**
|
||||
* @brief Enable extensible C++ classes when registering them.
|
||||
*/
|
||||
static inline constexpr Options extensibleClass = Options::Value<detail::OptionExtensibleClass>();
|
||||
|
||||
/**
|
||||
* @brief Allow to be able to override methods from lua in extensible C++ classes.
|
||||
*/
|
||||
static inline constexpr Options allowOverridingMethods = Options::Value<detail::OptionAllowOverridingMethods>();
|
||||
|
||||
/**
|
||||
* @brief Specify if metatables are visible for namespaces and classes.
|
||||
*/
|
||||
static inline constexpr Options visibleMetatables = Options::Value<detail::OptionVisibleMetatables>();
|
||||
|
||||
} // namespace luabridge
|
||||
@@ -0,0 +1,84 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2020, Dmitry Tarakanov
|
||||
// Copyright 2019, George Tokmaji
|
||||
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
#include "Errors.h"
|
||||
#include "Stack.h"
|
||||
#include "TypeTraits.h"
|
||||
#include "Userdata.h"
|
||||
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Overloaded objects.
|
||||
*/
|
||||
template <class... Args>
|
||||
struct NonConstOverload
|
||||
{
|
||||
template <class R, class T>
|
||||
constexpr auto operator()(R (T::*ptr)(Args...)) const noexcept -> decltype(ptr)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <class R, class T>
|
||||
static constexpr auto with(R (T::*ptr)(Args...)) noexcept -> decltype(ptr)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <class... Args>
|
||||
struct ConstOverload
|
||||
{
|
||||
template <class R, class T>
|
||||
constexpr auto operator()(R (T::*ptr)(Args...) const) const noexcept -> decltype(ptr)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <class R, class T>
|
||||
static constexpr auto with(R (T::*ptr)(Args...) const) noexcept -> decltype(ptr)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <class... Args>
|
||||
struct Overload : ConstOverload<Args...>, NonConstOverload<Args...>
|
||||
{
|
||||
using ConstOverload<Args...>::operator();
|
||||
using NonConstOverload<Args...>::operator();
|
||||
|
||||
template <class R>
|
||||
constexpr auto operator()(R (*ptr)(Args...)) const noexcept -> decltype(ptr)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <class R, class T>
|
||||
static constexpr auto with(R (T::*ptr)(Args...)) noexcept -> decltype(ptr)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Overload resolution.
|
||||
*/
|
||||
template <class... Args> [[maybe_unused]] constexpr Overload<Args...> overload = {};
|
||||
template <class... Args> [[maybe_unused]] constexpr ConstOverload<Args...> constOverload = {};
|
||||
template <class... Args> [[maybe_unused]] constexpr NonConstOverload<Args...> nonConstOverload = {};
|
||||
|
||||
} // namespace luabridge
|
||||
+257
@@ -0,0 +1,257 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2022, kunitoki
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Errors.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Simple result class containing a result.
|
||||
*/
|
||||
struct Result
|
||||
{
|
||||
Result() noexcept = default;
|
||||
|
||||
Result(std::error_code ec) noexcept
|
||||
: m_ec(ec)
|
||||
{
|
||||
}
|
||||
|
||||
Result(const Result&) noexcept = default;
|
||||
Result(Result&&) noexcept = default;
|
||||
Result& operator=(const Result&) noexcept = default;
|
||||
Result& operator=(Result&&) noexcept = default;
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return !m_ec;
|
||||
}
|
||||
|
||||
std::error_code error() const noexcept
|
||||
{
|
||||
return m_ec;
|
||||
}
|
||||
|
||||
const char* error_cstr() const noexcept
|
||||
{
|
||||
return detail::ErrorCategory::errorString(m_ec.value());
|
||||
}
|
||||
|
||||
operator std::error_code() const noexcept
|
||||
{
|
||||
return m_ec;
|
||||
}
|
||||
|
||||
std::string message() const
|
||||
{
|
||||
return m_ec.message();
|
||||
}
|
||||
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
void throw_on_error() const
|
||||
{
|
||||
if (m_ec)
|
||||
throw std::system_error(m_ec);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
std::error_code m_ec;
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Simple result class containing or a type T or an error code.
|
||||
*/
|
||||
template <class T>
|
||||
struct TypeResult
|
||||
{
|
||||
TypeResult() noexcept = default;
|
||||
|
||||
template <class U, class = std::enable_if_t<std::is_convertible_v<U, T> && !std::is_same_v<std::decay_t<U>, std::error_code>>>
|
||||
TypeResult(U&& value) noexcept
|
||||
: m_value(std::in_place, std::forward<U>(value))
|
||||
{
|
||||
}
|
||||
|
||||
TypeResult(std::error_code ec) noexcept
|
||||
: m_value(makeUnexpected(ec))
|
||||
{
|
||||
}
|
||||
|
||||
TypeResult(const TypeResult&) = default;
|
||||
TypeResult(TypeResult&&) = default;
|
||||
TypeResult& operator=(const TypeResult&) = default;
|
||||
TypeResult& operator=(TypeResult&&) = default;
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return m_value.hasValue();
|
||||
}
|
||||
|
||||
const T& value() const
|
||||
{
|
||||
return m_value.value();
|
||||
}
|
||||
|
||||
T& operator*() &
|
||||
{
|
||||
return m_value.value();
|
||||
}
|
||||
|
||||
T operator*() &&
|
||||
{
|
||||
return std::move(m_value.value());
|
||||
}
|
||||
|
||||
const T& operator*() const&
|
||||
{
|
||||
return m_value.value();
|
||||
}
|
||||
|
||||
T operator*() const&&
|
||||
{
|
||||
return std::move(m_value.value());
|
||||
}
|
||||
|
||||
T* operator->()
|
||||
{
|
||||
return &m_value.value();
|
||||
}
|
||||
|
||||
const T* operator->() const
|
||||
{
|
||||
return &m_value.value();
|
||||
}
|
||||
|
||||
template <class U>
|
||||
T valueOr(U&& defaultValue) const&
|
||||
{
|
||||
return m_value.valueOr(std::forward<U>(defaultValue));
|
||||
}
|
||||
|
||||
template <class U>
|
||||
T valueOr(U&& defaultValue) &&
|
||||
{
|
||||
return m_value.valueOr(std::forward<U>(defaultValue));
|
||||
}
|
||||
|
||||
std::error_code error() const
|
||||
{
|
||||
return m_value.error();
|
||||
}
|
||||
|
||||
const char* error_cstr() const noexcept
|
||||
{
|
||||
return detail::ErrorCategory::errorString(m_value.error().value());
|
||||
}
|
||||
|
||||
operator std::error_code() const
|
||||
{
|
||||
return m_value.error();
|
||||
}
|
||||
|
||||
std::string message() const
|
||||
{
|
||||
return m_value.error().message();
|
||||
}
|
||||
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
void throw_on_error() const
|
||||
{
|
||||
if (! m_value.hasValue())
|
||||
throw std::system_error(m_value.error());
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
Expected<T, std::error_code> m_value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TypeResult<void>
|
||||
{
|
||||
TypeResult() noexcept = default;
|
||||
|
||||
TypeResult(std::error_code ec) noexcept
|
||||
: m_ec(ec)
|
||||
{
|
||||
}
|
||||
|
||||
TypeResult(const TypeResult&) noexcept = default;
|
||||
TypeResult(TypeResult&&) noexcept = default;
|
||||
TypeResult& operator=(const TypeResult&) noexcept = default;
|
||||
TypeResult& operator=(TypeResult&&) noexcept = default;
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return ! m_ec;
|
||||
}
|
||||
|
||||
void value() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
std::error_code error() const noexcept
|
||||
{
|
||||
return m_ec;
|
||||
}
|
||||
|
||||
const char* error_cstr() const noexcept
|
||||
{
|
||||
return detail::ErrorCategory::errorString(m_ec.value());
|
||||
}
|
||||
|
||||
operator std::error_code() const noexcept
|
||||
{
|
||||
return m_ec;
|
||||
}
|
||||
|
||||
std::string message() const
|
||||
{
|
||||
return m_ec.message();
|
||||
}
|
||||
|
||||
#if LUABRIDGE_HAS_EXCEPTIONS
|
||||
void throw_on_error() const
|
||||
{
|
||||
if (m_ec)
|
||||
throw std::system_error(m_ec);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
std::error_code m_ec;
|
||||
};
|
||||
|
||||
template <class U>
|
||||
inline bool operator==(const TypeResult<U>& lhs, const U& rhs) noexcept
|
||||
{
|
||||
return lhs ? *lhs == rhs : false;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
inline bool operator==(const U& lhs, const TypeResult<U>& rhs) noexcept
|
||||
{
|
||||
return rhs == lhs;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
inline bool operator!=(const TypeResult<U>& lhs, const U& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
inline bool operator!=(const U& lhs, const TypeResult<U>& rhs) noexcept
|
||||
{
|
||||
return !(rhs == lhs);
|
||||
}
|
||||
|
||||
} // namespace luabridge
|
||||
@@ -0,0 +1,47 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2021, kunitoki
|
||||
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
#include "Stack.h"
|
||||
|
||||
namespace luabridge::detail {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Scope guard.
|
||||
*/
|
||||
template <class F>
|
||||
class ScopeGuard
|
||||
{
|
||||
public:
|
||||
template <class V>
|
||||
explicit ScopeGuard(V&& v)
|
||||
: m_func(std::forward<V>(v))
|
||||
, m_shouldRun(true)
|
||||
{
|
||||
}
|
||||
|
||||
~ScopeGuard()
|
||||
{
|
||||
if (m_shouldRun)
|
||||
m_func();
|
||||
}
|
||||
|
||||
void reset() noexcept
|
||||
{
|
||||
m_shouldRun = false;
|
||||
}
|
||||
|
||||
private:
|
||||
F m_func;
|
||||
bool m_shouldRun;
|
||||
};
|
||||
|
||||
template <class F>
|
||||
ScopeGuard(F&&) -> ScopeGuard<F>;
|
||||
|
||||
} // namespace luabridge::detail
|
||||
+1722
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,159 @@
|
||||
// https://github.com/kunitoki/LuaBridge3
|
||||
// Copyright 2020, kunitoki
|
||||
// Copyright 2019, Dmitry Tarakanov
|
||||
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
namespace luabridge {
|
||||
namespace detail {
|
||||
template <template <class...> class C, class... Ts>
|
||||
std::true_type is_base_of_template_impl(const C<Ts...>*);
|
||||
|
||||
template <template <class...> class C>
|
||||
std::false_type is_base_of_template_impl(...);
|
||||
|
||||
template <class T, template <class...> class C>
|
||||
using is_base_of_template = decltype(is_base_of_template_impl<C>(std::declval<T*>()));
|
||||
|
||||
template <class T, template <class...> class C>
|
||||
static inline constexpr bool is_base_of_template_v = is_base_of_template<T, C>::value;
|
||||
|
||||
template <class... Args>
|
||||
constexpr bool dependent_false = false;
|
||||
|
||||
template <class T>
|
||||
struct is_tuple : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class... Ts>
|
||||
struct is_tuple<std::tuple<Ts...>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr bool is_tuple_v = is_tuple<T>::value;
|
||||
} // namespace detail
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Container traits.
|
||||
*
|
||||
* Unspecialized ContainerTraits has the isNotContainer typedef for SFINAE. All user defined containers must supply an appropriate
|
||||
* specialization for ContinerTraits (without the alias isNotContainer). The containers that come with LuaBridge also come with the
|
||||
* appropriate ContainerTraits specialization.
|
||||
*
|
||||
* @note See the corresponding declaration for details.
|
||||
*
|
||||
* A specialization of ContainerTraits for some generic type ContainerType looks like this:
|
||||
*
|
||||
* @code
|
||||
*
|
||||
* template <class T>
|
||||
* struct ContainerTraits<ContainerType<T>>
|
||||
* {
|
||||
* using Type = T;
|
||||
*
|
||||
* static ContainerType<T> construct(T* c)
|
||||
* {
|
||||
* return c; // Implementation-dependent on ContainerType
|
||||
* }
|
||||
*
|
||||
* static T* get(const ContainerType<T>& c)
|
||||
* {
|
||||
* return c.get(); // Implementation-dependent on ContainerType
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* @endcode
|
||||
*/
|
||||
template <class T>
|
||||
struct ContainerTraits
|
||||
{
|
||||
using IsNotContainer = bool;
|
||||
|
||||
using Type = T;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Register shared_ptr support as container.
|
||||
*
|
||||
* @tparam T Class that is hold by the shared_ptr, must inherit from std::enable_shared_from_this to support Stack::get to reconstruct it from lua.
|
||||
*/
|
||||
template <class T>
|
||||
struct ContainerTraits<std::shared_ptr<T>>
|
||||
{
|
||||
using Type = T;
|
||||
|
||||
template <class U = T>
|
||||
static std::shared_ptr<U> construct(U* t)
|
||||
{
|
||||
if constexpr (detail::is_base_of_template_v<U, std::enable_shared_from_this>)
|
||||
{
|
||||
return std::static_pointer_cast<U>(t->shared_from_this());
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(detail::dependent_false<U>,
|
||||
"Failed reconstructing the reference count of the object instance, class must inherit from std::enable_shared_from_this");
|
||||
}
|
||||
}
|
||||
|
||||
static T* get(const std::shared_ptr<T>& c)
|
||||
{
|
||||
return c.get();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Register unique_ptr support as container.
|
||||
*
|
||||
* @note Lua gets a non-owning view of the object. The C++ owner must outlive any Lua reference.
|
||||
*
|
||||
* @tparam T Class that is held by the unique_ptr.
|
||||
*/
|
||||
template <class T>
|
||||
struct ContainerTraits<std::unique_ptr<T>>
|
||||
{
|
||||
using Type = T;
|
||||
|
||||
static T* get(const std::unique_ptr<T>& c)
|
||||
{
|
||||
return c.get();
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
//=================================================================================================
|
||||
/**
|
||||
* @brief Determine if type T is a container.
|
||||
*
|
||||
* To be considered a container, there must be a specialization of ContainerTraits with the required fields.
|
||||
*/
|
||||
template <class T>
|
||||
class IsContainer
|
||||
{
|
||||
private:
|
||||
typedef char yes[1]; // sizeof (yes) == 1
|
||||
typedef char no[2]; // sizeof (no) == 2
|
||||
|
||||
template <class C>
|
||||
static constexpr no& test(typename C::IsNotContainer*);
|
||||
|
||||
template <class>
|
||||
static constexpr yes& test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = sizeof(test<ContainerTraits<T>>(nullptr)) == sizeof(yes);
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace luabridge
|
||||
+1157
File diff suppressed because it is too large
Load Diff
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
theme: jekyll-theme-cayman
|
||||
exclude: ThirdParty
|
||||
Vendored
+249
@@ -0,0 +1,249 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import re
|
||||
import argparse
|
||||
import datetime
|
||||
from collections import deque
|
||||
|
||||
PARSE_FILE = 0
|
||||
EXTERNAL_FILE = 1
|
||||
ALREADY_SCANNED = 2
|
||||
|
||||
CPP_HEADER_FILE_EXT = set([".hpp" , ".h" , ".hxx" , ".hh" , ".inl"])
|
||||
|
||||
PRAGMA_ONCE_MATCHER = re.compile(r'#pragma once')
|
||||
INCLUDE_FILE_MATCHER = re.compile(r'#include\s*[<\"]([\w.\\/]*)[>\"]')
|
||||
LOCAL_INCLUDE_FILE_MATCHER = re.compile(r'#include\s*\"([\w.\\/]*)\"')
|
||||
|
||||
GUARDED_INCLUDES = [
|
||||
{ "header": "version" },
|
||||
{ "header": "coroutine", "condition": "(__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L))" },
|
||||
{ "header": "ranges", "condition": "(__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L))" },
|
||||
{ "header": "span", "condition": "(__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L))" },
|
||||
{ "header": "flat_map", "condition": "(__cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L))" },
|
||||
{ "header": "flat_set", "condition": "(__cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L))" },
|
||||
{ "header": "expected", "condition": "(__cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L))" },
|
||||
{ "header": "move_only_function", "condition": "(__cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L))" },
|
||||
]
|
||||
|
||||
def GetGuardedInclude(header):
|
||||
for guarded in GUARDED_INCLUDES:
|
||||
if guarded["header"] == header:
|
||||
return guarded
|
||||
return None
|
||||
|
||||
def IsCppHeaderFile(ext):
|
||||
return ext in CPP_HEADER_FILE_EXT
|
||||
|
||||
def AdjustFileExtension(ext):
|
||||
if ext[0] != '.':
|
||||
ext = '.' + ext
|
||||
|
||||
def RemoveComments(text):
|
||||
def BlotOutNonNewlines(strIn):
|
||||
if strIn.startswith("/*"):
|
||||
return "\n"
|
||||
else:
|
||||
return ""
|
||||
|
||||
def Replacer(match):
|
||||
s = match.group(0)
|
||||
if s.startswith('/'):
|
||||
return BlotOutNonNewlines(s)
|
||||
else:
|
||||
return s
|
||||
|
||||
pattern = re.compile(
|
||||
r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
|
||||
re.DOTALL | re.MULTILINE
|
||||
)
|
||||
|
||||
return re.sub(pattern, Replacer, text)
|
||||
|
||||
class SourceInfo:
|
||||
def __init__(self, baseDir , outputDir, outputName):
|
||||
self.includeDirs = list()
|
||||
self.headerQueue = deque()
|
||||
self.systemHeaders = set()
|
||||
self.scannedFiles = set()
|
||||
|
||||
self.baseDir = baseDir
|
||||
self.outputDir = outputDir
|
||||
|
||||
self.outputName = outputName
|
||||
self.headerFileExt = ".h"
|
||||
|
||||
self.AddIncludeDirectory(self.baseDir)
|
||||
self.AddIncludeDirectory(os.path.join(self.baseDir, "detail"))
|
||||
|
||||
def LogMessage(self, message):
|
||||
print(message)
|
||||
|
||||
def AddIncludeDirectory(self, path):
|
||||
if not os.path.exists(path):
|
||||
return False
|
||||
|
||||
self.LogMessage(f"Include Directory Added: {path}")
|
||||
|
||||
self.includeDirs.append(path)
|
||||
return True
|
||||
|
||||
def GetAbsoluteSourcePath(self, pwd, include):
|
||||
if os.path.isabs(include):
|
||||
return include
|
||||
|
||||
for includeDir in self.includeDirs:
|
||||
absPath = os.path.normpath(os.path.join(includeDir, include))
|
||||
if os.path.exists(absPath):
|
||||
return absPath
|
||||
|
||||
return None
|
||||
|
||||
def ShouldParseFile(self , path , ext):
|
||||
if (path in self.scannedFiles): return ALREADY_SCANNED
|
||||
|
||||
if not IsCppHeaderFile(ext) or not os.path.exists(path):
|
||||
return EXTERNAL_FILE
|
||||
|
||||
return PARSE_FILE
|
||||
|
||||
def ScanSourceFile(self, path , depth):
|
||||
dirpath, filename = os.path.split(path)
|
||||
ext = os.path.splitext(filename)[1]
|
||||
|
||||
info = self.ShouldParseFile(path, ext)
|
||||
if info != PARSE_FILE:
|
||||
return info
|
||||
|
||||
self.LogMessage(f"Scan file: {path}")
|
||||
self.scannedFiles.add(path)
|
||||
|
||||
with open (path , "r") as src:
|
||||
lines = src.readlines()
|
||||
|
||||
for line in lines:
|
||||
includeResult = INCLUDE_FILE_MATCHER.findall(line)
|
||||
if not includeResult:
|
||||
continue
|
||||
|
||||
localResult = LOCAL_INCLUDE_FILE_MATCHER.findall(line)
|
||||
if localResult:
|
||||
includeFile = self.GetAbsoluteSourcePath(dirpath, localResult[0])
|
||||
if includeFile is None:
|
||||
continue
|
||||
|
||||
call = self.ScanSourceFile(includeFile , depth + 1)
|
||||
if call == EXTERNAL_FILE:
|
||||
self.scannedFiles.add(includeFile)
|
||||
else:
|
||||
self.systemHeaders.add(includeResult[0])
|
||||
|
||||
self.AddFileToQueue(path, ext)
|
||||
|
||||
return info
|
||||
|
||||
def ParseDirectories(self):
|
||||
all_files = []
|
||||
|
||||
for sourceDirectory in self.includeDirs:
|
||||
for root, _, files in os.walk(sourceDirectory):
|
||||
for filename in files:
|
||||
all_files.append(os.path.join(root, filename))
|
||||
|
||||
for path in sorted(all_files):
|
||||
self.ScanSourceFile(path, 0)
|
||||
|
||||
|
||||
def WriteBeginFileHeader(self, filename, stream):
|
||||
stream.write(f"\n// Begin File: {filename}\n")
|
||||
|
||||
def WriteEndFileHeader(self, filename, stream):
|
||||
stream.write(f"\n// End File: {filename}\n")
|
||||
|
||||
def AddFileToQueue(self, filename, ext):
|
||||
if IsCppHeaderFile(ext):
|
||||
self.LogMessage(f"Enqueue header file: {filename}")
|
||||
self.headerQueue.append(filename)
|
||||
|
||||
def AmalgamateQueue(self, queue, stream):
|
||||
while (len(queue) > 0):
|
||||
path = queue.popleft()
|
||||
self.WriteFileToStream(path, stream)
|
||||
|
||||
def WriteFileToStream(self, path, stream):
|
||||
self.LogMessage(f"Write File: {path}")
|
||||
|
||||
with open (path, 'r') as source:
|
||||
self.WriteBeginFileHeader(path, stream)
|
||||
|
||||
lastLineWasEmpty = False
|
||||
|
||||
text = RemoveComments(source.read())
|
||||
lines = text.replace("\r", "\n").split("\n")
|
||||
|
||||
for line in lines:
|
||||
result = INCLUDE_FILE_MATCHER.findall(line)
|
||||
if result:
|
||||
continue
|
||||
|
||||
result = PRAGMA_ONCE_MATCHER.findall(line)
|
||||
if result:
|
||||
continue
|
||||
|
||||
stripped_line = line.strip()
|
||||
if stripped_line or not lastLineWasEmpty:
|
||||
stream.write(f"{line}\n")
|
||||
|
||||
lastLineWasEmpty = not stripped_line
|
||||
|
||||
self.WriteEndFileHeader(path, stream)
|
||||
|
||||
def WriteAlgamationFiles(self):
|
||||
headerPath = os.path.join(self.outputDir, self.outputName + self.headerFileExt)
|
||||
|
||||
self.LogMessage(f"Creating source Amalgamation: {headerPath}")
|
||||
|
||||
with open (headerPath , 'w') as headerAmalgamation:
|
||||
current_year = datetime.date.today().year
|
||||
headerAmalgamation.write(f"// https://github.com/kunitoki/LuaBridge3\n")
|
||||
headerAmalgamation.write(f"// Copyright {current_year}, kunitoki\n")
|
||||
headerAmalgamation.write(f"// SPDX-License-Identifier: MIT\n\n")
|
||||
headerAmalgamation.write(f"// clang-format off\n\n")
|
||||
headerAmalgamation.write(f"#pragma once\n\n")
|
||||
|
||||
systemHeaders = list(self.systemHeaders)
|
||||
for header in sorted(systemHeaders):
|
||||
if GetGuardedInclude(header) is None:
|
||||
headerAmalgamation.write(f"#include <{header}>\n")
|
||||
headerAmalgamation.write("\n")
|
||||
|
||||
for header in reversed(sorted(systemHeaders)):
|
||||
guard = GetGuardedInclude(header)
|
||||
if guard is not None:
|
||||
headerAmalgamation.write(f"#if defined(__has_include) && __has_include(<{header}>)")
|
||||
if "condition" in guard and guard["condition"] is not None:
|
||||
headerAmalgamation.write(f" && {guard['condition']}\n")
|
||||
else:
|
||||
headerAmalgamation.write("\n")
|
||||
headerAmalgamation.write(f"#include <{header}>\n")
|
||||
headerAmalgamation.write(f"#endif\n\n")
|
||||
headerAmalgamation.write("\n")
|
||||
|
||||
self.AmalgamateQueue(self.headerQueue, headerAmalgamation)
|
||||
|
||||
headerAmalgamation.write("// clang-format on\n\n")
|
||||
|
||||
return headerPath
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Amalgamate LuaBridge.')
|
||||
parser.add_argument('--base', action='store', default="Source/LuaBridge/")
|
||||
parser.add_argument('--output', action='store', default="Distribution/LuaBridge/")
|
||||
parser.add_argument('--name', action='store', default="LuaBridge")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
sourceInfo = SourceInfo(args.base, args.output, args.name)
|
||||
sourceInfo.ParseDirectories()
|
||||
sourceInfo.WriteAlgamationFiles()
|
||||
Vendored
+88
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
def extract_uncovered(root):
|
||||
"""
|
||||
Returns:
|
||||
dict[str, list[int]] -> filename -> uncovered line numbers
|
||||
"""
|
||||
result = defaultdict(list)
|
||||
|
||||
for cls in root.findall(".//class"):
|
||||
filename = cls.attrib.get("filename", "unknown")
|
||||
lines = cls.find("lines")
|
||||
if lines is None:
|
||||
continue
|
||||
|
||||
for line in lines.findall("line"):
|
||||
if line.attrib.get("hits") == "0":
|
||||
result[filename].append(int(line.attrib["number"]))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def compress_ranges(numbers):
|
||||
"""
|
||||
Converts sorted list like [1,2,3,5,6,10] -> ["1-3","5-6","10"]
|
||||
"""
|
||||
if not numbers:
|
||||
return []
|
||||
|
||||
numbers = sorted(set(numbers))
|
||||
ranges = []
|
||||
|
||||
start = prev = numbers[0]
|
||||
|
||||
for n in numbers[1:]:
|
||||
if n == prev + 1:
|
||||
prev = n
|
||||
else:
|
||||
ranges.append((start, prev))
|
||||
start = prev = n
|
||||
|
||||
ranges.append((start, prev))
|
||||
|
||||
# Format
|
||||
out = []
|
||||
for s, e in ranges:
|
||||
if s == e:
|
||||
out.append(f"{s}")
|
||||
else:
|
||||
out.append(f"{s}-{e}")
|
||||
|
||||
return out
|
||||
|
||||
|
||||
def write_ultra_compact(data, output_path):
|
||||
"""
|
||||
Writes:
|
||||
file:range,range,...
|
||||
"""
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
for filename in sorted(data.keys()):
|
||||
ranges = compress_ranges(data[filename])
|
||||
if ranges:
|
||||
f.write(f"{filename}:{','.join(ranges)}\n")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print(f"Usage: {sys.argv[0]} input.xml output.txt")
|
||||
sys.exit(1)
|
||||
|
||||
input_path = sys.argv[1]
|
||||
output_path = sys.argv[2]
|
||||
|
||||
tree = ET.parse(input_path)
|
||||
root = tree.getroot()
|
||||
|
||||
uncovered = extract_uncovered(root)
|
||||
write_ultra_compact(uncovered, output_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
|
||||
default:
|
||||
@just -l
|
||||
|
||||
generate CXX="17":
|
||||
cmake -G Xcode -B Build{{CXX}} -DLUABRIDGE_BENCHMARKS=ON -DCMAKE_CXX_STANDARD={{CXX}} .
|
||||
|
||||
open CXX="17":
|
||||
@just generate {{CXX}}
|
||||
-open Build{{CXX}}/LuaBridge.xcodeproj
|
||||
|
||||
build CXX="17":
|
||||
@just generate {{CXX}}
|
||||
cmake --build Build{{CXX}} --config Debug -j8
|
||||
|
||||
test CXX="17":
|
||||
@just build {{CXX}}
|
||||
ctest --test-dir Build{{CXX}} -C Debug -j8
|
||||
|
||||
test-all:
|
||||
@just test 17
|
||||
@just test 20
|
||||
@just test 23
|
||||
|
||||
build1 CXX="17":
|
||||
@just generate {{CXX}}
|
||||
cmake --build Build{{CXX}} --config Debug --target LuaBridgeTests54 -j8
|
||||
|
||||
test1 CXX="17":
|
||||
@just build1 {{CXX}}
|
||||
./Build{{CXX}}/Tests/Debug/LuaBridgeTests54
|
||||
|
||||
sanitize TYPE="address" CXX="17":
|
||||
cmake -G Xcode -B Build{{CXX}} -DLUABRIDGE_SANITIZE={{TYPE}} .
|
||||
|
||||
benchmark CXX="17":
|
||||
@just generate {{CXX}}
|
||||
cmake --build Build{{CXX}} --config Release --target LuaBridge3Benchmark -j8
|
||||
cmake --build Build{{CXX}} --config Release --target LuaBridgeVanillaBenchmark -j8
|
||||
cmake --build Build{{CXX}} --config Release --target Sol3Benchmark -j8
|
||||
./Build{{CXX}}/Benchmarks/Release/LuaBridge3Benchmark --benchmark_out_format=json --benchmark_out=Build{{CXX}}/LuaBridge3Benchmark.json
|
||||
./Build{{CXX}}/Benchmarks/Release/LuaBridgeVanillaBenchmark --benchmark_out_format=json --benchmark_out=Build{{CXX}}/LuaBridgeVanillaBenchmark.json
|
||||
./Build{{CXX}}/Benchmarks/Release/Sol3Benchmark --benchmark_out_format=json --benchmark_out=Build{{CXX}}/Sol3Benchmark.json
|
||||
@just plot {{CXX}}
|
||||
|
||||
plot CXX="17":
|
||||
uv run --with-requirements Benchmarks/requirements.txt Benchmarks/plot_benchmarks.py --input Build{{CXX}}/*.json --output Images/benchmarks.png
|
||||
|
||||
amalgamate:
|
||||
uv run amalgamate.py
|
||||
|
||||
clean:
|
||||
rm -rf Build
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
sonar.projectKey=LuaBridge3
|
||||
sonar.organization=kunitoki
|
||||
|
||||
# This is the name and version displayed in the SonarCloud UI.
|
||||
#sonar.projectName=LuaBridge3
|
||||
#sonar.projectVersion=1.0
|
||||
|
||||
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
|
||||
sonar.sources=Source/LuaBridge,Tests
|
||||
sonar.coverage.exclusions=Tests/**/*
|
||||
sonar.cpd.exclusions=Tests/**/*
|
||||
|
||||
# Disable some rules on some files
|
||||
sonar.issue.ignore.multicriteria=a1
|
||||
sonar.issue.ignore.multicriteria.a1.ruleKey=*
|
||||
sonar.issue.ignore.multicriteria.a1.resourceKey=Tests/**/*
|
||||
|
||||
# Encoding of the source code. Default is default system encoding
|
||||
#sonar.sourceEncoding=UTF-8
|
||||
Reference in New Issue
Block a user