mirror of
https://github.com/boostorg/leaf.git
synced 2026-01-19 04:22:08 +00:00
Significant refactoring:
- Support for error objects crossing DLL boundaries on Windows via BOOST_LEAF_CFG_WIN32=2. - Internal TLS interface improvements, separating logical allocation from reading. - Dynamic allocations (if enabled) for on_error objects now happens before stack unwinding begins. - BOOST_LEAF_SYMBOL_VISIBLE declarations now separated in config/visibility.hpp.
This commit is contained in:
60
.github/workflows/ci.yml
vendored
60
.github/workflows/ci.yml
vendored
@@ -16,7 +16,17 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
config:
|
||||
- variant: "debug,release"
|
||||
- name: No capture
|
||||
variant: "leaf_debug_capture0,leaf_release_capture0"
|
||||
- name: No diagnostics
|
||||
variant: "leaf_debug_diag0,leaf_release_diag0"
|
||||
- name: Embedded
|
||||
variant: "leaf_debug_embedded,leaf_release_embedded"
|
||||
- name: Single header
|
||||
variant: "leaf_debug_single_header,leaf_release_single_header"
|
||||
platform:
|
||||
- toolset: gcc-5
|
||||
cxxstd: "11,14,1z"
|
||||
container: ubuntu:18.04
|
||||
@@ -175,23 +185,25 @@ jobs:
|
||||
container: ubuntu:25.04
|
||||
os: ubuntu-latest
|
||||
install: clang-20
|
||||
- toolset: clang
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: macos-13
|
||||
- toolset: clang
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: macos-14
|
||||
- toolset: clang
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: macos-15
|
||||
- toolset: clang
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: macos-26
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
name: ${{matrix.platform.os}} / ${{matrix.platform.compiler || matrix.platform.toolset}}${{matrix.config.name && format(' / {0}', matrix.config.name) || ''}}
|
||||
|
||||
runs-on: ${{matrix.platform.os}}
|
||||
|
||||
container:
|
||||
image: ${{matrix.container}}
|
||||
image: ${{matrix.platform.container}}
|
||||
volumes:
|
||||
- /node20217:/node20217:rw,rshared
|
||||
- ${{ startsWith(matrix.container, 'ubuntu:1') && '/node20217:/__e/node20:ro,rshared' || ' ' }}
|
||||
- ${{ startsWith(matrix.platform.container, 'ubuntu:1') && '/node20217:/__e/node20:ro,rshared' || ' ' }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -199,13 +211,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Setup container environment
|
||||
if: matrix.container
|
||||
if: matrix.platform.container
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get -y install sudo python3 git g++ curl xz-utils
|
||||
|
||||
- name: Install nodejs20glibc2.17
|
||||
if: ${{ startsWith( matrix.container, 'ubuntu:1' ) }}
|
||||
if: ${{ startsWith( matrix.platform.container, 'ubuntu:1' ) }}
|
||||
run: |
|
||||
curl -LO https://archives.boost.io/misc/node/node-v20.9.0-linux-x64-glibc-217.tar.xz
|
||||
tar -xf node-v20.9.0-linux-x64-glibc-217.tar.xz --strip-components 1 -C /node20217
|
||||
@@ -214,10 +226,10 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
if: matrix.platform.install
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install ${{matrix.install}}
|
||||
sudo apt-get -y install ${{matrix.platform.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
@@ -242,9 +254,9 @@ jobs:
|
||||
./b2 -d0 headers
|
||||
|
||||
- name: Create user-config.jam
|
||||
if: matrix.compiler
|
||||
if: matrix.platform.compiler
|
||||
run: |
|
||||
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
|
||||
echo "using ${{matrix.platform.toolset}} : : ${{matrix.platform.compiler}} ;" > ~/user-config.jam
|
||||
|
||||
- name: Generate headers
|
||||
run: |
|
||||
@@ -254,13 +266,24 @@ jobs:
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root
|
||||
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} ${ADDRMD:+address-model=$ADDRMD} link=shared,static variant=debug,release,leaf_debug_capture0,leaf_release_capture0,leaf_debug_diag0,leaf_release_diag0,leaf_debug_embedded,leaf_release_embedded,leaf_debug_single_header,leaf_release_single_header
|
||||
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.platform.toolset}} cxxstd=${{matrix.platform.cxxstd}} ${ADDRMD:+address-model=$ADDRMD} link=shared,static variant=${{matrix.config.variant}}
|
||||
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.platform.toolset}} cxxstd=${{matrix.platform.cxxstd}} ${ADDRMD:+address-model=$ADDRMD} link=shared,static variant=${{matrix.config.variant}} exception-handling=off rtti=off
|
||||
|
||||
windows:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
config:
|
||||
- variant: "debug,release"
|
||||
- name: No capture
|
||||
variant: "leaf_debug_capture0,leaf_release_capture0"
|
||||
- name: No diagnostics
|
||||
variant: "leaf_debug_diag0,leaf_release_diag0"
|
||||
- name: Embedded
|
||||
variant: "leaf_debug_embedded,leaf_release_embedded"
|
||||
- name: Single header
|
||||
variant: "leaf_debug_single_header,leaf_release_single_header"
|
||||
platform:
|
||||
- toolset: msvc-14.3
|
||||
cxxstd: "14,17,20,latest"
|
||||
addrmd: 32,64
|
||||
@@ -274,7 +297,9 @@ jobs:
|
||||
addrmd: 64
|
||||
os: windows-2022
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
name: ${{matrix.platform.os}} / ${{matrix.platform.compiler || matrix.platform.toolset}}${{matrix.config.name && format(' / {0}', matrix.config.name) || ''}}
|
||||
|
||||
runs-on: ${{matrix.platform.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -310,4 +335,5 @@ jobs:
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} ${{matrix.embedmanifest}} variant=debug,release,leaf_debug_capture0,leaf_release_capture0,leaf_debug_diag0,leaf_release_diag0,leaf_debug_embedded,leaf_release_embedded,leaf_debug_single_header,leaf_release_single_header
|
||||
b2 -j3 --abbreviate-paths libs/%LIBRARY%/test toolset=${{matrix.platform.toolset}} cxxstd=${{matrix.platform.cxxstd}} address-model=${{matrix.platform.addrmd}} link=shared,static variant=${{matrix.config.variant}}
|
||||
b2 -j3 --abbreviate-paths libs/%LIBRARY%/test toolset=${{matrix.platform.toolset}} cxxstd=${{matrix.platform.cxxstd}} address-model=${{matrix.platform.addrmd}} link=shared,static variant=${{matrix.config.variant}} exception-handling=off rtti=off
|
||||
|
||||
70
.vscode/tasks.json
vendored
70
.vscode/tasks.json
vendored
@@ -6,43 +6,43 @@
|
||||
{
|
||||
"label": "Setup Meson build directories",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D leaf_boost_examples=true -D leaf_lua_examples=true _bld/debug && meson setup -D leaf_boost_examples=false -D single_header=true _bld/debug_single_header && meson setup -D leaf_boost_examples=true -D leaf_lua_examples=true _bld/release --buildtype release && meson setup -D single_header=true _bld/release_single_header --buildtype release",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true _bld/debug && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D leaf_single_header=true _bld/debug_single_header && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true _bld/release --buildtype release && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D leaf_single_header=true _bld/release_single_header --buildtype release",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Setup Meson build directories (no exceptions)",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D cpp_eh=none -D leaf_boost_examples=true -D leaf_lua_examples=true _bld/debug && meson setup -D cpp_eh=none -D leaf_boost_examples=true -D single_header=true _bld/debug_single_header && meson setup -D cpp_eh=none -D leaf_boost_examples=true -D leaf_lua_examples=true _bld/release --buildtype release && meson setup -D cpp_eh=none -D leaf_boost_examples=true -D single_header=true _bld/release_single_header --buildtype release",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D cpp_eh=none _bld/debug && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D leaf_single_header=true -D cpp_eh=none _bld/debug_single_header && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D cpp_eh=none _bld/release --buildtype release && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D leaf_single_header=true -D cpp_eh=none _bld/release_single_header --buildtype release",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Setup Meson build directories (no diagnostics)",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D leaf_diagnostics=0 -D leaf_boost_examples=true -D leaf_lua_examples=true _bld/debug && meson setup -D leaf_diagnostics=0 -D leaf_boost_examples=true -D single_header=true _bld/debug_single_header && meson setup -D leaf_diagnostics=0 -D leaf_boost_examples=true -D leaf_lua_examples=true _bld/release --buildtype release && meson setup -D leaf_diagnostics=0 -D leaf_boost_examples=true -D single_header=true _bld/release_single_header --buildtype release",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D leaf_diagnostics=0 _bld/debug && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D leaf_single_header=true -D leaf_diagnostics=0 _bld/debug_single_header && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D leaf_diagnostics=0 _bld/release --buildtype release && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D leaf_single_header=true -D leaf_diagnostics=0 _bld/release_single_header --buildtype release",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Setup Meson build directories (no capture)",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D leaf_capture=0 -D leaf_boost_examples=true -D leaf_lua_examples=true _bld/debug && meson setup -D leaf_capture=0 -D leaf_boost_examples=true -D single_header=true _bld/debug_single_header && meson setup -D leaf_capture=0 -D leaf_boost_examples=true -D leaf_lua_examples=true _bld/release --buildtype release && meson setup -D leaf_capture=0 -D leaf_boost_examples=true -D single_header=true _bld/release_single_header --buildtype release",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D leaf_capture=0 _bld/debug && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D leaf_single_header=true -D leaf_capture=0 _bld/debug_single_header && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D leaf_capture=0 _bld/release --buildtype release && meson setup -D leaf_boost_available=true -D leaf_enable_examples=true -D leaf_single_header=true -D leaf_capture=0 _bld/release_single_header --buildtype release",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Setup Meson build directories (no Boost)",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D leaf_lua_examples=true _bld/debug && meson setup -D single_header=true _bld/debug_single_header && meson setup -D leaf_lua_examples=true _bld/release --buildtype release && meson setup -D single_header=true _bld/release_single_header --buildtype release",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D leaf_boost_available=false -D leaf_enable_examples=true _bld/debug && meson setup -D leaf_boost_available=false -D leaf_enable_examples=true -D leaf_single_header=true _bld/debug_single_header && meson setup -D leaf_boost_available=false -D leaf_enable_examples=true _bld/release --buildtype release && meson setup -D leaf_boost_available=false -D leaf_enable_examples=true -D leaf_single_header=true _bld/release_single_header --buildtype release",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Setup Meson build directories (test embedded)",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D leaf_embedded=true -D leaf_diagnostics=0 _bld/debug && meson setup -D leaf_embedded=true -D leaf_diagnostics=0 -D single_header=true _bld/debug_single_header && meson setup -D leaf_embedded=true -D leaf_diagnostics=0 _bld/release --buildtype release && meson setup -D leaf_embedded=true -D leaf_diagnostics=0 -D single_header=true _bld/release_single_header --buildtype release",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D leaf_embedded=true -D leaf_diagnostics=0 _bld/debug && meson setup -D leaf_embedded=true -D leaf_diagnostics=0 -D leaf_single_header=true _bld/debug_single_header && meson setup -D leaf_embedded=true -D leaf_diagnostics=0 _bld/release --buildtype release && meson setup -D leaf_embedded=true -D leaf_diagnostics=0 -D leaf_single_header=true _bld/release_single_header --buildtype release",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Setup Meson build directories (test embedded, no exceptions)",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D cpp_eh=none -D leaf_embedded=true -D leaf_diagnostics=0 _bld/debug && meson setup -D cpp_eh=none -D leaf_embedded=true -D leaf_diagnostics=0 -D single_header=true _bld/debug_single_header && meson setup -D cpp_eh=none -D leaf_embedded=true -D leaf_diagnostics=0 _bld/release --buildtype release && meson setup -D cpp_eh=none -D leaf_embedded=true -D leaf_diagnostics=0 -D single_header=true _bld/release_single_header --buildtype release",
|
||||
"command": "cd ${workspaceRoot} && meson setup -D cpp_eh=none -D leaf_embedded=true -D leaf_diagnostics=0 _bld/debug && meson setup -D cpp_eh=none -D leaf_embedded=true -D leaf_diagnostics=0 -D leaf_single_header=true _bld/debug_single_header && meson setup -D cpp_eh=none -D leaf_embedded=true -D leaf_diagnostics=0 _bld/release --buildtype release && meson setup -D cpp_eh=none -D leaf_embedded=true -D leaf_diagnostics=0 -D leaf_single_header=true _bld/release_single_header --buildtype release",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
@@ -65,6 +65,15 @@
|
||||
"relative",
|
||||
"${workspaceRoot}/_bld/debug"
|
||||
]
|
||||
},
|
||||
"windows": {
|
||||
"problemMatcher": {
|
||||
"base": "$msCompile",
|
||||
"fileLocation": [
|
||||
"relative",
|
||||
"${workspaceRoot}/_bld/debug"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -81,6 +90,15 @@
|
||||
"relative",
|
||||
"${workspaceRoot}/_bld/debug"
|
||||
]
|
||||
},
|
||||
"windows": {
|
||||
"problemMatcher": {
|
||||
"base": "$msCompile",
|
||||
"fileLocation": [
|
||||
"relative",
|
||||
"${workspaceRoot}/_bld/debug"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -97,6 +115,15 @@
|
||||
"relative",
|
||||
"${workspaceRoot}/_bld/release"
|
||||
]
|
||||
},
|
||||
"windows": {
|
||||
"problemMatcher": {
|
||||
"base": "$msCompile",
|
||||
"fileLocation": [
|
||||
"relative",
|
||||
"${workspaceRoot}/_bld/release"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -106,16 +133,23 @@
|
||||
"dependsOn": [
|
||||
"Generate leaf.hpp"
|
||||
],
|
||||
"command": "../../b2 test link=shared,static variant=debug,release,leaf_debug_diag0,leaf_release_diag0,leaf_debug_single_header,leaf_release_single_header,leaf_debug_embedded,leaf_release_embedded exception-handling=off rtti=off cxxstd=11,14,1z,17 && ../../b2 test link=shared,static variant=debug,release,leaf_debug_diag0,leaf_release_diag0,leaf_debug_single_header,leaf_release_single_header exception-handling=on,off cxxstd=11,14,1z,17",
|
||||
"windows": {
|
||||
"command": "..\\..\\b2 test link=shared,static variant=debug,release,leaf_debug_diag0,leaf_release_diag0,leaf_debug_single_header,leaf_release_single_header,leaf_debug_embedded,leaf_release_embedded exception-handling=off rtti=off cxxstd=14,17,latest && ..\\..\\b2 test link=shared,static variant=debug,release,leaf_debug_diag0,leaf_release_diag0,leaf_debug_single_header,leaf_release_single_header exception-handling=on,off cxxstd=14,17,latest",
|
||||
},
|
||||
"command": "../../b2 --abbreviate-paths test link=shared,static variant=debug,release,leaf_debug_diag0,leaf_release_diag0,leaf_debug_single_header,leaf_release_single_header,leaf_debug_embedded,leaf_release_embedded exception-handling=off rtti=off cxxstd=11,14,1z,17 && ../../b2 --abbreviate-paths test link=shared,static variant=debug,release,leaf_debug_diag0,leaf_release_diag0,leaf_debug_single_header,leaf_release_single_header exception-handling=on,off cxxstd=11,14,1z,17",
|
||||
"problemMatcher": {
|
||||
"base": "$gcc",
|
||||
"fileLocation": [
|
||||
"relative",
|
||||
"${workspaceRoot}/_bld/release"
|
||||
]
|
||||
},
|
||||
"windows": {
|
||||
"command": "..\\..\\b2 --abbreviate-paths test link=shared,static variant=debug,release,leaf_debug_diag0,leaf_release_diag0,leaf_debug_single_header,leaf_release_single_header,leaf_debug_embedded,leaf_release_embedded exception-handling=off rtti=off cxxstd=14,17,latest && ..\\..\\b2 --abbreviate-paths test link=shared,static variant=debug,release,leaf_debug_diag0,leaf_release_diag0,leaf_debug_single_header,leaf_release_single_header exception-handling=on,off cxxstd=14,17,latest",
|
||||
"problemMatcher": {
|
||||
"base": "$msCompile",
|
||||
"fileLocation": [
|
||||
"relative",
|
||||
"${workspaceRoot}/_bld/release"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -125,9 +159,9 @@
|
||||
},
|
||||
"label": "Test current editor file",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/_bld/debug && ninja && {meson test ${fileBasenameNoExtension} || cat ./meson-logs/testlog.txt}",
|
||||
"command": "cd ${workspaceRoot}/_bld/debug && ninja && { meson test ${fileBasenameNoExtension} || cat ./meson-logs/testlog.txt; }",,
|
||||
"windows": {
|
||||
"command": "cd ${workspaceRoot}/_bld/debug && ninja && (meson test ${fileBasenameNoExtension} || cat ./meson-logs/testlog.txt)",
|
||||
"command": "cd ${workspaceRoot}/_bld/debug && ninja && (meson test ${fileBasenameNoExtension} || type .\\meson-logs\\testlog.txt)",
|
||||
},
|
||||
"problemMatcher": {
|
||||
"base": "$gcc",
|
||||
@@ -135,6 +169,16 @@
|
||||
"relative",
|
||||
"${workspaceRoot}/_bld/debug"
|
||||
]
|
||||
},
|
||||
"windows": {
|
||||
"command": "cd ${workspaceRoot}/_bld/debug && ninja && (meson test ${fileBasenameNoExtension} || type .\\meson-logs\\testlog.txt)",
|
||||
"problemMatcher": {
|
||||
"base": "$msCompile",
|
||||
"fileLocation": [
|
||||
"relative",
|
||||
"${workspaceRoot}/_bld/debug"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -28,4 +28,4 @@ Besides GitHub, there are two other distribution channels:
|
||||
* LEAF is included in official [Boost](https://www.boost.org/) releases, starting with Boost 1.75.
|
||||
* For maximum portability, the library is also available in single-header format: [leaf.hpp](https://raw.githubusercontent.com/boostorg/leaf/gh-pages/leaf.hpp).
|
||||
|
||||
Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc. Distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].
|
||||
Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc. Distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].
|
||||
|
||||
@@ -68,19 +68,15 @@ NOTE: LEAF does not depend on Boost or other libraries.
|
||||
[[tutorial]]
|
||||
== Tutorial
|
||||
|
||||
What is a failure? It is simply the inability of a function to return a valid result, instead producing an error object describing the reason for the failure.
|
||||
Typically, error handling libraries define a variant result type, e.g. `result<T, E>`. In LEAF we drop the `E`, using just `result<T>`.
|
||||
|
||||
A typical design is to return a variant type, e.g. `result<T, E>`. Internally, such variant types must store a discriminant (in this case a boolean) to indicate whether the object holds a `T` or an `E`.
|
||||
In case of success, access to the value `T` is immediate and direct, but because error objects are not held in results, handling errors requires a special syntax. Error objects are transported directly to error handling scopes that need them. This is not only more efficient, but also enables any given handler to access multiple objects associated with the same failure, if needed.
|
||||
|
||||
The design of LEAF is informed by the observation that the immediate caller must have access to the discriminant in order to determine the availability of a valid `T`, but otherwise it is rare that it needs to access any error objects. They are only needed once an error handling scope is reached.
|
||||
|
||||
Therefore what would have been a `result<T, E>` becomes `result<T>`, which stores the discriminant and (optionally) a `T`, while error objects are delivered directly to the error handling scope where they are needed.
|
||||
|
||||
The benefit of this decomposition is that `result<T>` becomes extremely lightweight, as it is not coupled with error types; further, error objects are communicated in constant time (independent of the call stack depth). Even very large objects are handled efficiently without dynamic memory allocation.
|
||||
LEAF is also compatible with exception handling, providing identical functionality but without needing a result type.
|
||||
|
||||
=== Reporting Errors
|
||||
|
||||
A function that reports an error:
|
||||
Report errors with `leaf::new_error`:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
@@ -103,7 +99,7 @@ leaf::result<T> f()
|
||||
[[checking_for_errors]]
|
||||
=== Checking for Errors
|
||||
|
||||
Checking for errors communicated by a `leaf::result<T>` works as expected:
|
||||
To bail out on failure, return `result::error()`:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
@@ -120,9 +116,7 @@ leaf::result<U> g()
|
||||
[.text-right]
|
||||
<<result>>
|
||||
|
||||
TIP: The the result of `r.error()` is compatible with any instance of the `leaf::result` template. In the example above, note that `g` returns a `leaf::result<U>`, while `r` is of type `leaf::result<T>`.
|
||||
|
||||
The boilerplate `if` statement can be avoided using `BOOST_LEAF_AUTO`:
|
||||
Use `BOOST_LEAF_AUTO` to avoid the boilerplate `if` statement:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
@@ -136,7 +130,7 @@ leaf::result<U> g()
|
||||
[.text-right]
|
||||
<<BOOST_LEAF_AUTO>>
|
||||
|
||||
`BOOST_LEAF_AUTO` can not be used with `void` results; in that case, to avoid the boilerplate `if` statement, use `BOOST_LEAF_CHECK`:
|
||||
Use `BOOST_LEAF_CHECK` in case of `void` results:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
@@ -151,7 +145,7 @@ leaf::result<int> g()
|
||||
[.text-right]
|
||||
<<BOOST_LEAF_CHECK>>
|
||||
|
||||
On implementations that define `pass:[__GNUC__]` (e.g. GCC/clang), the `BOOST_LEAF_CHECK` macro definition takes advantage of https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html[GNU C statement expressions]. In this case, in addition to its portable usage with `result<void>`, `BOOST_LEAF_CHECK` can be used in expressions with non-`void` result types:
|
||||
On implementations that define `pass:[__GNUC__]` (e.g. GCC/clang), `BOOST_LEAF_CHECK` is compatible with with non-`void` results as well:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
@@ -221,7 +215,7 @@ leaf::result<U> r = leaf::try_handle_some(
|
||||
BOOST_LEAF_AUTO(v1, f1());
|
||||
BOOST_LEAF_AUTO(v2, f2());
|
||||
|
||||
return g(v1. v2);
|
||||
return g(v1, v2);
|
||||
},
|
||||
|
||||
[]( leaf::match<err1, err1::e1, err1::e3> ) -> leaf::result<U>
|
||||
@@ -256,7 +250,7 @@ leaf::result<U> r = leaf::try_handle_some(
|
||||
BOOST_LEAF_AUTO(v1, f1());
|
||||
BOOST_LEAF_AUTO(v2, f2());
|
||||
|
||||
return g(v1. v2);
|
||||
return g(v1, v2);
|
||||
},
|
||||
|
||||
[]( err1 e, leaf::error_info const & ei ) -> leaf::result<U>
|
||||
@@ -285,7 +279,7 @@ U r = leaf::try_handle_all(
|
||||
BOOST_LEAF_AUTO(v1, f1());
|
||||
BOOST_LEAF_AUTO(v2, f2());
|
||||
|
||||
return g(v1. v2);
|
||||
return g(v1, v2);
|
||||
},
|
||||
|
||||
[]( leaf::match<err1, err1::e1> ) -> U
|
||||
@@ -400,9 +394,9 @@ leaf::result<U> r = leaf::try_handle_some(
|
||||
|
||||
Once again, error handlers are considered in order:
|
||||
|
||||
* The first error handler will be used if an error object of type `io_error` _and_ and error_object of type `e_file_name` are available;
|
||||
* The first error handler will be used if an error object of type `io_error` _and_ an error_object of type `e_file_name` are available;
|
||||
* otherwise, the second error handler will be used if an error object of type `io_error` is available;
|
||||
* otherwise, `leaf_try_handle_some` fails.
|
||||
* otherwise, `leaf::try_handle_some` fails.
|
||||
|
||||
An alternative way to write the above is to provide a single error handler that takes the `e_file_name` argument as a pointer:
|
||||
|
||||
@@ -515,7 +509,7 @@ leaf::result<void> r = leaf::try_handle_some(
|
||||
|
||||
[]( io_error e, e_line const * current_line )
|
||||
{
|
||||
std::cerr << "Parse error";
|
||||
std::cerr << "I/O error";
|
||||
if( current_line )
|
||||
std::cerr << " at line " << current_line->value;
|
||||
std::cerr << std::endl;
|
||||
@@ -550,7 +544,7 @@ leaf::result<void> r = leaf::try_handle_some(
|
||||
|
||||
[]( io_error e, e_line const * l )
|
||||
{
|
||||
std::cerr << "Parse error";
|
||||
std::cerr << "I/O error";
|
||||
if( l )
|
||||
std::cerr << " at line " << l.value;
|
||||
std::cerr << std::endl;
|
||||
@@ -584,7 +578,7 @@ leaf::try_catch(
|
||||
|
||||
[]( io_error e, e_line const * l )
|
||||
{
|
||||
std::cerr << "Parse error";
|
||||
std::cerr << "I/O error";
|
||||
if( l )
|
||||
std::cerr << " at line " << l.value;
|
||||
std::cerr << std::endl;
|
||||
@@ -718,7 +712,6 @@ leaf::result<int> r = leaf::try_handle_some(
|
||||
{
|
||||
// Handle lib2::error_code
|
||||
} );
|
||||
}
|
||||
----
|
||||
[.text-right]
|
||||
<<try_handle_some>> | <<result>>
|
||||
@@ -803,7 +796,7 @@ Ideally, when an error is detected, a program using LEAF would always call <<new
|
||||
|
||||
Alas, this is not always possible.
|
||||
|
||||
For example, the error may need to be communicated through uncooperative 3rd-party interfaces. To facilitate this transmission, a error ID may be encoded in a `std::error_code`. As long as a 3rd-party interface is able to transport a `std::error_code`, it can be compatible with LEAF.
|
||||
For example, the error may need to be communicated through uncooperative 3rd-party interfaces. To facilitate this transmission, an error ID may be encoded in a `std::error_code`. As long as a 3rd-party interface is able to transport a `std::error_code`, it can be compatible with LEAF.
|
||||
|
||||
Further, it is sometimes necessary to communicate errors through an interface that does not even use `std::error_code`. An example of this is when an external lower-level library throws an exception, which is unlikely to be able to carry an `error_id`.
|
||||
|
||||
@@ -823,7 +816,7 @@ For a detailed tutorial see <<tutorial-on_error_in_c_callbacks>>.
|
||||
[[tutorial-loading]]
|
||||
=== Loading of Error Objects
|
||||
|
||||
Recall that error objects communicated to LEAF are stored on the stack, local to the `try_handle_same`, `try_handle_all` or `try_catch` function used to handle errors. To _load_ an error object means to move it into such storage, if available.
|
||||
Recall that error objects communicated to LEAF are stored on the stack, local to the `try_handle_some`, `try_handle_all` or `try_catch` function used to handle errors. To _load_ an error object means to move it into such storage, if available.
|
||||
|
||||
Various LEAF functions take a list of error objects to load. As an example, if a function `copy_file` that takes the name of the input file and the name of the output file as its arguments detects a failure, it could communicate an error code `ec`, plus the two relevant file names using <<new_error>>:
|
||||
|
||||
@@ -1098,7 +1091,7 @@ It is also possible to select a handler based on `std::error_category`. The foll
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
[]( std::error_code, leaf::category<std::errc>> )
|
||||
[]( std::error_code, leaf::category<std::errc> )
|
||||
{
|
||||
}
|
||||
----
|
||||
@@ -1109,7 +1102,7 @@ The following predicates are available:
|
||||
|
||||
* <<match>>: as described above.
|
||||
* <<match_value>>: where `match<E, V...>` compares the object `e` of type `E` with the values `V...`, `match_value<E, V...>` compare `e.value` with the values `V...`.
|
||||
* <<match_member>>: similar to `match_value`, but takes a pointer to the data member to compare; that is, `match_member<&E::value, V...>` is equvialent to `match_value<E, V...>`. Note, however, that `match_member` requires {CPP}17 or newer, while `match_value` does not.
|
||||
* <<match_member>>: similar to `match_value`, but takes a pointer to the data member to compare; that is, `match_member<&E::value, V...>` is equivalent to `match_value<E, V...>`. Note, however, that `match_member` requires {CPP}17 or newer, while `match_value` does not.
|
||||
* `<<catch_>><Ex...>`: Similar to `match`, but checks whether the caught `std::exception` object can be `dynamic_cast` to any of the `Ex` types.
|
||||
* <<if_not>> is a special predicate that takes any other predicate `Pred` and requires that an error object of type `E` is available and that `Pred` evaluates to `false`. For example, `if_not<match<E, V...>>` requires that an object `e` of type `E` is available, and that it does not compare equal to any of the specified `V...`.
|
||||
|
||||
@@ -1778,7 +1771,7 @@ NOTE: Follow this link to see the complete program: https://github.com/boostorg/
|
||||
|
||||
TIP: When using Lua with {CPP}, we need to protect the Lua interpreter from exceptions that may be thrown from {CPP} functions installed as `lua_CFunction` callbacks. Here is the program from this section rewritten to use a {CPP} exception (instead of `leaf::result`) to safely communicate errors out of the `do_work` function: https://github.com/boostorg/leaf/blob/master/example/lua_callback_exceptions.cpp?ts=4[lua_callback_exceptions.cpp].
|
||||
|
||||
''''
|
||||
'''
|
||||
|
||||
[[tutorial-diagnostic_information]]
|
||||
=== Diagnostic Information
|
||||
@@ -5543,7 +5536,10 @@ The following configuration macros are recognized:
|
||||
|
||||
* `BOOST_LEAF_CFG_GNUC_STMTEXPR`: This macro controls whether or not <<BOOST_LEAF_CHECK>> is defined in terms of a https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html[GNU C statement expression], which enables its use to check for errors similarly to how the questionmark operator works in some languages (see <<checking_for_errors>>). By default the macro is defined as `1` under `pass:[__GNUC__]`, otherwise as `0`.
|
||||
|
||||
* `BOOST_LEAF_CFG_WIN32`: Defining this macro as 1 enables the default constructor in <<e_LastError>>, and the automatic conversion to string (via `FormatMessageA`) when <<diagnostic_details>> is printed. If the macro is left undefined, LEAF defines it as `0` (even on windows, since including `windows.h` is generally not desirable). Note that the `e_LastError` type itself is available on all platforms, there is no need for conditional compilation in error handlers that use it.
|
||||
* `BOOST_LEAF_CFG_WIN32`: This macro controls the use of Win32 APIs. If left undefined, LEAF defines it as `0` (even on Windows, since including `windows.h` is generally not desirable). The possible values are:
|
||||
** `0`: Disables all Win32-specific features.
|
||||
** `1`: Includes `windows.h` and enables <<e_LastError>> support, which is otherwise stubbed.
|
||||
** `2`: In addition, switches LEAF to using the Win32 TLS API instead of {CPP}11 `thread_local`, enabling error objects to be used across DLL boundaries.
|
||||
|
||||
* `BOOST_LEAF_NO_EXCEPTIONS`: Disables all exception handling support. If left undefined, LEAF defines it automatically based on the compiler configuration (e.g. `-fno-exceptions`).
|
||||
|
||||
@@ -5552,7 +5548,13 @@ The following configuration macros are recognized:
|
||||
[[configuring_tls_access]]
|
||||
=== Configuring TLS Access
|
||||
|
||||
LEAF requires support for thread-local `void` pointers. By default, this is implemented by means of the {CPP}11 `thread_local` keyword, but in order to support <<embedded_platforms,embedded platforms>>, it is possible to configure LEAF to use an array of thread local pointers instead, by defining `BOOST_LEAF_USE_TLS_ARRAY`. In this case, the user is required to define the following two functions to implement the required TLS access:
|
||||
LEAF requires support for thread-local `void` pointers. The available TLS implementations are:
|
||||
|
||||
** {CPP}11 `thread_local` keyword (the default).
|
||||
** Win32 TLS API: selected by defining `BOOST_LEAF_CFG_WIN32=2`. This enables error objects to be used across DLL boundaries.
|
||||
** Custom TLS array: selected by defining `BOOST_LEAF_USE_TLS_ARRAY`. This is intended for <<embedded_platforms,embedded platforms>> where the {CPP}11 `thread_local` keyword is not available or not suitable.
|
||||
|
||||
When using `BOOST_LEAF_USE_TLS_ARRAY`, the user is required to define the following two functions to implement the required TLS access:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
@@ -5577,7 +5579,7 @@ Under `BOOST_LEAF_USE_TLS_ARRAY` the following additional configuration macros a
|
||||
|
||||
* `BOOST_LEAF_CFG_TLS_INDEX_TYPE` may be defined to specify the integral type used to store assigned TLS indices (if the macro is left undefined, LEAF defines it as `unsigned char`).
|
||||
|
||||
TIP: Reporting error objects of types that are not used by the program to handle failures does not consume TLS pointers. The minimum size of the TLS pointer array required by LEAF is the total number of different types used as arguments to error handlers (in the entire program), plus one.
|
||||
TIP: TLS slots are allocated only for types used in error handlers. The minimum size of the TLS pointer array required by LEAF is the total number of different types used as arguments to error handlers (in the entire program), plus one.
|
||||
|
||||
WARNING: Beware of `read_void_ptr`/`write_void_ptr` accessing thread local pointers beyond the static boundaries of the thread local pointer array; this will likely result in undefined behavior.
|
||||
|
||||
@@ -5605,9 +5607,9 @@ Defining `BOOST_LEAF_EMBEDDED` is equivalent to the following:
|
||||
#endif
|
||||
----
|
||||
|
||||
LEAF supports FreeRTOS out of the box, please define `BOOST_LEAF_TLS_FREERTOS` (in which case LEAF automatically defines `BOOST_LEAF_EMBEDDED`, if it is not defined already).
|
||||
LEAF supports FreeRTOS out of the box, define `BOOST_LEAF_TLS_FREERTOS` (in which case LEAF automatically defines `BOOST_LEAF_EMBEDDED`, if it is not defined already).
|
||||
|
||||
For other embedded platforms, please define `BOOST_LEAF_USE_TLS_ARRAY`, see <<configuring_tls_access>>.
|
||||
For other embedded platforms, define `BOOST_LEAF_USE_TLS_ARRAY`, see <<configuring_tls_access>>.
|
||||
|
||||
If your program does not use concurrency at all, simply define `BOOST_LEAF_NO_THREADS`, which requires no TLS support at all (but is NOT thread-safe).
|
||||
|
||||
@@ -5618,8 +5620,6 @@ TIP: Contrary to popular belief, exception handling works great on embedded plat
|
||||
|
||||
The source code is compatible with {CPP}11 or newer.
|
||||
|
||||
LEAF uses thread-local storage (only for pointers). By default, this is implemented via the {CPP}11 `thread_local` storage class specifier, but the library is easily configurable to use any platform-specific TLS API instead (it ships with built-in support for FreeRTOS). See <<configuration>>.
|
||||
|
||||
== Running the Unit Tests
|
||||
|
||||
The unit tests can be run with https://mesonbuild.com[Meson Build] or with Boost Build. To run the unit tests:
|
||||
@@ -5792,9 +5792,9 @@ return leaf::try_handle_some(
|
||||
[.text-right]
|
||||
<<result>> | <<try_handle_some>> | <<match>> | <<e_file_name>> | <<e_errno>>
|
||||
|
||||
== Limitations
|
||||
== Dynamic linking
|
||||
|
||||
When using dynamic linking, it is required that error types are declared with `default` visibility, e.g.:
|
||||
When using dynamic linking, on POSIX platforms it is required that error types are declared with `default` visibility, e.g.:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
@@ -5804,9 +5804,7 @@ struct __attribute__ ((visibility ("default"))) my_error_info
|
||||
};
|
||||
----
|
||||
|
||||
This works as expected except on Windows, where thread-local storage is not shared between the individual binary modules. For this reason, to transport error objects across DLL boundaries.
|
||||
|
||||
TIP: When using dynamic linking, it is always best to define module interfaces in terms of C (and implement them in {CPP} if appropriate).
|
||||
On Windows, to use error objects across DLL boundaries, define `BOOST_LEAF_CFG_WIN32=2`. For two modules to be able to share LEAF error objects, it is required that they are both compiled with the same compiler (not necessarily with the same compiler version). For example, if one module is compiled with MSVC and the other with GCC, the error objects will not be shared.
|
||||
|
||||
== Alternatives to LEAF
|
||||
|
||||
@@ -5929,7 +5927,7 @@ leaf::try_catch(
|
||||
[]
|
||||
{
|
||||
f(); // throws
|
||||
}
|
||||
},
|
||||
[](my_exception &, my_info const & x)
|
||||
{
|
||||
//my_info is available with
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""
|
||||
|
||||
Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
Copyright (c) Sorin Fetche
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
@@ -105,7 +105,7 @@ def _main():
|
||||
'\n'
|
||||
'// Latest published version of this file: https://raw.githubusercontent.com/boostorg/leaf/gh-pages/leaf.hpp.\n'
|
||||
'\n'
|
||||
'// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.\n'
|
||||
'// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.\n'
|
||||
'// Distributed under the Boost Software License, Version 1.0. (See accompanying\n'
|
||||
'// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n'
|
||||
'\n')
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#ifndef BOOST_LEAF_HPP_INCLUDED
|
||||
#define BOOST_LEAF_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/leaf/detail/all.hpp>
|
||||
|
||||
#endif
|
||||
#endif // #ifndef BOOST_LEAF_HPP_INCLUDED
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_LEAF_COMMON_HPP_INCLUDED
|
||||
#define BOOST_LEAF_COMMON_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#if BOOST_LEAF_CFG_WIN32
|
||||
# include <windows.h>
|
||||
# include <cstring>
|
||||
# ifdef min
|
||||
# undef min
|
||||
# endif
|
||||
@@ -29,18 +28,18 @@
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE e_api_function { char const * value; };
|
||||
struct e_api_function { char const * value; };
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_STRING
|
||||
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE e_file_name
|
||||
struct e_file_name
|
||||
{
|
||||
std::string value;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE e_file_name
|
||||
struct e_file_name
|
||||
{
|
||||
char const * value = "<unavailable>";
|
||||
BOOST_LEAF_CONSTEXPR explicit e_file_name( char const * ) { }
|
||||
@@ -48,7 +47,7 @@ struct BOOST_LEAF_SYMBOL_VISIBLE e_file_name
|
||||
|
||||
#endif
|
||||
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE e_errno
|
||||
struct e_errno
|
||||
{
|
||||
int value;
|
||||
|
||||
@@ -61,9 +60,9 @@ struct BOOST_LEAF_SYMBOL_VISIBLE e_errno
|
||||
}
|
||||
};
|
||||
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE e_type_info_name { char const * value; };
|
||||
struct e_type_info_name { char const * value; };
|
||||
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE e_at_line { int value; };
|
||||
struct e_at_line { int value; };
|
||||
|
||||
namespace windows
|
||||
{
|
||||
@@ -97,18 +96,18 @@ namespace windows
|
||||
{
|
||||
BOOST_LEAF_ASSERT(mb.p != nullptr);
|
||||
char * z = std::strchr((LPSTR)mb.p,0);
|
||||
if( z[-1] == '\n' )
|
||||
if( z != (LPSTR)mb.p && z[-1] == '\n' )
|
||||
*--z = 0;
|
||||
if( z[-1] == '\r' )
|
||||
if( z != (LPSTR)mb.p && z[-1] == '\r' )
|
||||
*--z = 0;
|
||||
return os << err.value << ", \"" << (LPCSTR)mb.p << '"';
|
||||
}
|
||||
return os;
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_WIN32
|
||||
};
|
||||
}
|
||||
} // namespace windows
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // BOOST_LEAF_COMMON_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_COMMON_HPP_INCLUDED
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
#ifndef BOOST_LEAF_CONFIG_HPP_INCLUDED
|
||||
#define BOOST_LEAF_CONFIG_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <utility>
|
||||
#include <exception>
|
||||
|
||||
#ifdef BOOST_LEAF_TLS_FREERTOS
|
||||
# ifndef BOOST_LEAF_EMBEDDED
|
||||
# define BOOST_LEAF_EMBEDDED
|
||||
@@ -24,7 +27,7 @@
|
||||
# ifndef BOOST_LEAF_CFG_CAPTURE
|
||||
# define BOOST_LEAF_CFG_CAPTURE 0
|
||||
# endif
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_EMBEDDED
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -87,8 +90,13 @@
|
||||
# error BOOST_LEAF_CFG_CAPTURE must be 0 or 1.
|
||||
#endif
|
||||
|
||||
#if BOOST_LEAF_CFG_WIN32 != 0 && BOOST_LEAF_CFG_WIN32 != 1
|
||||
# error BOOST_LEAF_CFG_WIN32 must be 0 or 1.
|
||||
#if BOOST_LEAF_CFG_WIN32 != 0 && BOOST_LEAF_CFG_WIN32 != 1 && BOOST_LEAF_CFG_WIN32 != 2
|
||||
# error BOOST_LEAF_CFG_WIN32 must be 0 or 1 or 2.
|
||||
#endif
|
||||
|
||||
#if BOOST_LEAF_CFG_WIN32 && !defined(_WIN32)
|
||||
# warning "Ignoring BOOST_LEAF_CFG_WIN32 because _WIN32 is not defined"
|
||||
# define BOOST_LEAF_CFG_WIN32 0
|
||||
#endif
|
||||
|
||||
#if BOOST_LEAF_CFG_GNUC_STMTEXPR != 0 && BOOST_LEAF_CFG_GNUC_STMTEXPR != 1
|
||||
@@ -154,7 +162,7 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#endif
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -203,7 +211,6 @@
|
||||
////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
# include <exception>
|
||||
# if (defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L) || (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
# define BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS 1
|
||||
# else
|
||||
@@ -219,6 +226,8 @@
|
||||
# define BOOST_LEAF_SYMBOL_VISIBLE
|
||||
#endif
|
||||
|
||||
#include <boost/leaf/config/visibility.hpp>
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
#if defined(__GNUC__) && !(defined(__clang__) || defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && (__GNUC__ * 100 + __GNUC_MINOR__) < 409
|
||||
@@ -229,7 +238,36 @@
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define BOOST_LEAF_UNREACHABLE __assume(0)
|
||||
#else
|
||||
# define BOOST_LEAF_UNREACHABLE __builtin_unreachable()
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace boost
|
||||
{
|
||||
[[noreturn]] void throw_exception( std::exception const & ); // user defined
|
||||
}
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class T>
|
||||
[[noreturn]] void throw_exception_( T && e )
|
||||
{
|
||||
#ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
::boost::throw_exception(std::move(e));
|
||||
#else
|
||||
throw std::move(e);
|
||||
#endif
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
// Configure TLS access
|
||||
#include <boost/leaf/config/tls.hpp>
|
||||
|
||||
#endif // BOOST_LEAF_CONFIG_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_CONFIG_HPP_INCLUDED
|
||||
|
||||
@@ -1,12 +1,68 @@
|
||||
#ifndef BOOST_LEAF_CONFIG_TLS_HPP_INCLUDED
|
||||
#define BOOST_LEAF_CONFIG_TLS_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
// The following declarations specify the thread local storage API used
|
||||
// internally by LEAF. To port LEAF to a new TLS API, provide definitions for
|
||||
// each of these functions.
|
||||
namespace tls
|
||||
{
|
||||
// Generate the next unique error_id. Values start at 1 and increment by 4.
|
||||
// Error ids must be unique for the lifetime of the process, and this
|
||||
// function must be thread-safe. Postcondition: (id & 3) == 1 && id != 0.
|
||||
//
|
||||
// This function may not fail.
|
||||
unsigned generate_next_error_id() noexcept;
|
||||
|
||||
// Write x to the TLS for the current error_id. The initial value for each
|
||||
// thread must be 0. Precondition: x == 0 or (x & 3) == 1.
|
||||
//
|
||||
// This function may not fail.
|
||||
void write_current_error_id( unsigned x ) noexcept;
|
||||
|
||||
// Read the current error_id for this thread. The initial value for each
|
||||
// thread must be 0.
|
||||
//
|
||||
// This function may not fail.
|
||||
unsigned read_current_error_id() noexcept;
|
||||
|
||||
// Reserve TLS storage for T. The TLS may be allocated dynamically on the
|
||||
// first call to reserve_ptr<T>, but subsequent calls must reuse the same
|
||||
// TLS. On platforms where allocation is not needed, this function is
|
||||
// still defined but does nothing.
|
||||
//
|
||||
// This function may throw on allocation failure.
|
||||
template <class T>
|
||||
void reserve_ptr();
|
||||
|
||||
// Write p to the TLS previously reserved for T by a call to reserve_ptr<T>.
|
||||
// It is illegal to call write_ptr<T> without a prior successful call to
|
||||
// reserve_ptr<T>.
|
||||
//
|
||||
// This function may not fail.
|
||||
template <class T>
|
||||
void write_ptr( T * p ) noexcept;
|
||||
|
||||
// Read the T * value previously written in the TLS for T. Returns nullptr
|
||||
// if TLS for T has not yet been reserved.
|
||||
//
|
||||
// This function may not fail.
|
||||
template <class T>
|
||||
T * read_ptr() noexcept;
|
||||
} // namespace tls
|
||||
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#if defined(BOOST_LEAF_TLS_FREERTOS)
|
||||
# include <boost/leaf/config/tls_freertos.hpp>
|
||||
# ifndef BOOST_LEAF_USE_TLS_ARRAY
|
||||
# define BOOST_LEAF_USE_TLS_ARRAY
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_LEAF_USE_TLS_ARRAY
|
||||
@@ -23,10 +79,12 @@
|
||||
|
||||
#if defined BOOST_LEAF_USE_TLS_ARRAY
|
||||
# include <boost/leaf/config/tls_array.hpp>
|
||||
#elif BOOST_LEAF_CFG_WIN32 == 2
|
||||
# include <boost/leaf/config/tls_win32.hpp>
|
||||
#elif defined(BOOST_LEAF_NO_THREADS)
|
||||
# include <boost/leaf/config/tls_globals.hpp>
|
||||
#else
|
||||
# include <boost/leaf/config/tls_cpp11.hpp>
|
||||
#endif
|
||||
|
||||
#endif // BOOST_LEAF_CONFIG_TLS_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_CONFIG_TLS_HPP_INCLUDED
|
||||
@@ -1,16 +1,15 @@
|
||||
#ifndef BOOST_LEAF_CONFIG_TLS_ARRAY_HPP_INCLUDED
|
||||
#define BOOST_LEAF_CONFIG_TLS_ARRAY_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Copyright (c) 2022 Khalil Estell
|
||||
|
||||
// LEAF requires thread local storage support for pointers and for uin32_t values.
|
||||
|
||||
// This header implements thread local storage for pointers and for unsigned int
|
||||
// values for platforms that support thread local pointers by index.
|
||||
// This header implements the TLS API specified in tls.hpp for platforms that
|
||||
// provide TLS by indexing an array (this is typical for embedded platforms).
|
||||
// The array is accessed via user-defined functions.
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
@@ -26,8 +25,8 @@ namespace tls
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
#include <limits>
|
||||
#include <atomic>
|
||||
#include <limits>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -56,19 +55,25 @@ namespace boost { namespace leaf {
|
||||
namespace detail
|
||||
{
|
||||
using atomic_unsigned_int = std::atomic<unsigned int>;
|
||||
}
|
||||
|
||||
namespace tls
|
||||
{
|
||||
template <class=void>
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE id_factory
|
||||
{
|
||||
static atomic_unsigned_int counter;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
atomic_unsigned_int id_factory<T>::counter(1);
|
||||
|
||||
template <class=void>
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE index_counter
|
||||
{
|
||||
static int c_;
|
||||
|
||||
static BOOST_LEAF_CFG_TLS_INDEX_TYPE next_() noexcept
|
||||
BOOST_LEAF_ALWAYS_INLINE static BOOST_LEAF_CFG_TLS_INDEX_TYPE next_() noexcept
|
||||
{
|
||||
int idx = ++c_;
|
||||
BOOST_LEAF_ASSERT(idx > (BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX));
|
||||
BOOST_LEAF_ASSERT(idx > (BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX + 1));
|
||||
BOOST_LEAF_ASSERT(idx < (BOOST_LEAF_CFG_TLS_ARRAY_SIZE));
|
||||
return idx;
|
||||
}
|
||||
@@ -76,12 +81,15 @@ namespace tls
|
||||
public:
|
||||
|
||||
template <class T>
|
||||
static BOOST_LEAF_CFG_TLS_INDEX_TYPE next() noexcept
|
||||
BOOST_LEAF_ALWAYS_INLINE static BOOST_LEAF_CFG_TLS_INDEX_TYPE next() noexcept
|
||||
{
|
||||
return next_(); // Set breakpoint here to monitor TLS index allocation for T.
|
||||
return next_();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
int index_counter<T>::c_ = BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX + 1;
|
||||
|
||||
template <class T>
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE tls_index
|
||||
{
|
||||
@@ -89,58 +97,72 @@ namespace tls
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE alloc_tls_index
|
||||
BOOST_LEAF_CFG_TLS_INDEX_TYPE tls_index<T>::idx = BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX + 1;
|
||||
|
||||
template <class T>
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE reserve_tls_index
|
||||
{
|
||||
static BOOST_LEAF_CFG_TLS_INDEX_TYPE const idx;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
int index_counter<T>::c_ = BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX;
|
||||
BOOST_LEAF_CFG_TLS_INDEX_TYPE const reserve_tls_index<T>::idx = tls_index<T>::idx = index_counter<>::next<T>();
|
||||
} // namespace detail
|
||||
|
||||
template <class T>
|
||||
BOOST_LEAF_CFG_TLS_INDEX_TYPE tls_index<T>::idx = BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX;
|
||||
} } // namespace boost::leaf
|
||||
|
||||
template <class T>
|
||||
BOOST_LEAF_CFG_TLS_INDEX_TYPE const alloc_tls_index<T>::idx = tls_index<T>::idx = index_counter<>::next<T>();
|
||||
////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class T>
|
||||
T * read_ptr() noexcept
|
||||
namespace tls
|
||||
{
|
||||
BOOST_LEAF_ALWAYS_INLINE unsigned generate_next_error_id() noexcept
|
||||
{
|
||||
int tls_idx = tls_index<T>::idx;
|
||||
if( tls_idx == (BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX) )
|
||||
return nullptr;
|
||||
--tls_idx;
|
||||
return reinterpret_cast<T *>(read_void_ptr(tls_idx));
|
||||
unsigned id = (detail::id_factory<>::counter += 4);
|
||||
BOOST_LEAF_ASSERT((id&3) == 1);
|
||||
return id;
|
||||
}
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE void write_current_error_id( unsigned x ) noexcept
|
||||
{
|
||||
static_assert(sizeof(std::intptr_t) >= sizeof(unsigned), "Incompatible tls_array implementation");
|
||||
write_void_ptr(BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX, (void *) (std::intptr_t) x);
|
||||
}
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE unsigned read_current_error_id() noexcept
|
||||
{
|
||||
static_assert(sizeof(std::intptr_t) >= sizeof(unsigned), "Incompatible tls_array implementation");
|
||||
return (unsigned) (std::intptr_t) read_void_ptr(BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void write_ptr( T * p ) noexcept
|
||||
BOOST_LEAF_ALWAYS_INLINE void reserve_ptr()
|
||||
{
|
||||
int tls_idx = alloc_tls_index<T>::idx;
|
||||
(void) detail::reserve_tls_index<T>::idx;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_LEAF_ALWAYS_INLINE void write_ptr( T * p ) noexcept
|
||||
{
|
||||
int tls_idx = detail::tls_index<T>::idx;
|
||||
BOOST_LEAF_ASSERT(tls_idx != (BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX + 1));
|
||||
--tls_idx;
|
||||
write_void_ptr(tls_idx, p);
|
||||
BOOST_LEAF_ASSERT(read_void_ptr(tls_idx) == p);
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class Tag>
|
||||
unsigned read_uint() noexcept
|
||||
template <class T>
|
||||
BOOST_LEAF_ALWAYS_INLINE T * read_ptr() noexcept
|
||||
{
|
||||
static_assert(sizeof(std::intptr_t) >= sizeof(unsigned), "Incompatible tls_array implementation");
|
||||
return (unsigned) (std::intptr_t) (void *) read_ptr<Tag>();
|
||||
int tls_idx = detail::tls_index<T>::idx;
|
||||
if( tls_idx == (BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX + 1) )
|
||||
return nullptr;
|
||||
--tls_idx;
|
||||
return reinterpret_cast<T *>(read_void_ptr(tls_idx));
|
||||
}
|
||||
} // namespace tls
|
||||
|
||||
template <class Tag>
|
||||
void write_uint( unsigned x ) noexcept
|
||||
{
|
||||
static_assert(sizeof(std::intptr_t) >= sizeof(unsigned), "Incompatible tls_array implementation");
|
||||
write_ptr<Tag>((Tag *) (void *) (std::intptr_t) x);
|
||||
}
|
||||
}
|
||||
} } // namespace boost::leaf
|
||||
|
||||
} }
|
||||
|
||||
#endif // BOOST_LEAF_CONFIG_TLS_ARRAY_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_CONFIG_TLS_ARRAY_HPP_INCLUDED
|
||||
|
||||
@@ -1,27 +1,34 @@
|
||||
#ifndef BOOST_LEAF_CONFIG_TLS_CPP11_HPP_INCLUDED
|
||||
#define BOOST_LEAF_CONFIG_TLS_CPP11_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// LEAF requires thread local storage support for pointers and for uin32_t values.
|
||||
// This header implements the TLS API specified in tls.hpp using the C++11
|
||||
// built-in thread_local storage class specifier. On Windows, this
|
||||
// implementation does not allow error objects to cross DLL boundaries. If this
|
||||
// is required, define BOOST_LEAF_CFG_WIN32=2 before including any LEAF headers
|
||||
// to enable the alternative implementation defined in tls_win32.hpp.
|
||||
|
||||
// This header implements thread local storage for pointers and for unsigned int
|
||||
// values using the C++11 built-in thread_local storage class specifier.
|
||||
|
||||
#include <cstdint>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
using atomic_unsigned_int = std::atomic<unsigned int>;
|
||||
}
|
||||
|
||||
namespace tls
|
||||
{
|
||||
template <class=void>
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE id_factory
|
||||
{
|
||||
static atomic_unsigned_int counter;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
atomic_unsigned_int id_factory<T>::counter(1);
|
||||
|
||||
template <class T>
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE ptr
|
||||
{
|
||||
@@ -31,42 +38,59 @@ namespace tls
|
||||
template <class T>
|
||||
thread_local T * ptr<T>::p;
|
||||
|
||||
template <class T>
|
||||
T * read_ptr() noexcept
|
||||
{
|
||||
return ptr<T>::p;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void write_ptr( T * p ) noexcept
|
||||
{
|
||||
ptr<T>::p = p;
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class Tag>
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE tagged_uint
|
||||
template <class=void>
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE current_error_id_storage
|
||||
{
|
||||
static thread_local unsigned x;
|
||||
};
|
||||
|
||||
template <class Tag>
|
||||
thread_local unsigned tagged_uint<Tag>::x;
|
||||
template <class T>
|
||||
thread_local unsigned current_error_id_storage<T>::x;
|
||||
} // namespace detail
|
||||
|
||||
template <class Tag>
|
||||
unsigned read_uint() noexcept
|
||||
} } // namespace boost::leaf
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace tls
|
||||
{
|
||||
BOOST_LEAF_ALWAYS_INLINE unsigned generate_next_error_id() noexcept
|
||||
{
|
||||
return tagged_uint<Tag>::x;
|
||||
unsigned id = (detail::id_factory<>::counter += 4);
|
||||
BOOST_LEAF_ASSERT((id&3) == 1);
|
||||
return id;
|
||||
}
|
||||
|
||||
template <class Tag>
|
||||
void write_uint( unsigned x ) noexcept
|
||||
BOOST_LEAF_ALWAYS_INLINE void write_current_error_id( unsigned x ) noexcept
|
||||
{
|
||||
tagged_uint<Tag>::x = x;
|
||||
detail::current_error_id_storage<>::x = x;
|
||||
}
|
||||
}
|
||||
|
||||
} }
|
||||
BOOST_LEAF_ALWAYS_INLINE unsigned read_current_error_id() noexcept
|
||||
{
|
||||
return detail::current_error_id_storage<>::x;
|
||||
}
|
||||
|
||||
#endif // BOOST_LEAF_CONFIG_TLS_CPP11_HPP_INCLUDED
|
||||
template <class T>
|
||||
BOOST_LEAF_ALWAYS_INLINE void reserve_ptr()
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_LEAF_ALWAYS_INLINE void write_ptr( T * p ) noexcept
|
||||
{
|
||||
detail::ptr<T>::p = p;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_LEAF_ALWAYS_INLINE T * read_ptr() noexcept
|
||||
{
|
||||
return detail::ptr<T>::p;
|
||||
}
|
||||
} // namespace tls
|
||||
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // #ifndef BOOST_LEAF_CONFIG_TLS_CPP11_HPP_INCLUDED
|
||||
|
||||
@@ -1,23 +1,18 @@
|
||||
#ifndef BOOST_LEAF_CONFIG_TLS_FREERTOS_HPP_INCLUDED
|
||||
#define BOOST_LEAF_CONFIG_TLS_FREERTOS_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Copyright (c) 2022 Khalil Estell
|
||||
|
||||
// LEAF requires thread local storage support for pointers and for uin32_t values.
|
||||
|
||||
// This header implements "thread local" storage via FreeTOS functions
|
||||
// This header implements the TLS API specified in tls.hpp via the FreeTOS
|
||||
// pvTaskGetThreadLocalStoragePointer / pvTaskSetThreadLocalStoragePointer
|
||||
// functions, using the more general implementation defined in tls_array.hpp.
|
||||
|
||||
#include <task.h>
|
||||
|
||||
#ifndef BOOST_LEAF_USE_TLS_ARRAY
|
||||
# define BOOST_LEAF_USE_TLS_ARRAY
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_LEAF_CFG_TLS_ARRAY_SIZE
|
||||
# define BOOST_LEAF_CFG_TLS_ARRAY_SIZE configNUM_THREAD_LOCAL_STORAGE_POINTERS
|
||||
#endif
|
||||
@@ -31,12 +26,12 @@ namespace tls
|
||||
{
|
||||
// See https://www.freertos.org/thread-local-storage-pointers.html.
|
||||
|
||||
inline void * read_void_ptr( int tls_index ) noexcept
|
||||
BOOST_LEAF_ALWAYS_INLINE void * read_void_ptr( int tls_index ) noexcept
|
||||
{
|
||||
return pvTaskGetThreadLocalStoragePointer(0, tls_index);
|
||||
}
|
||||
|
||||
inline void write_void_ptr( int tls_index, void * p ) noexcept
|
||||
BOOST_LEAF_ALWAYS_INLINE void write_void_ptr( int tls_index, void * p ) noexcept
|
||||
{
|
||||
vTaskSetThreadLocalStoragePointer(0, tls_index, p);
|
||||
}
|
||||
@@ -44,4 +39,4 @@ namespace tls
|
||||
|
||||
} }
|
||||
|
||||
#endif // BOOST_LEAF_CONFIG_TLS_FREERTOS_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_CONFIG_TLS_FREERTOS_HPP_INCLUDED
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
#ifndef BOOST_LEAF_CONFIG_TLS_GLOBALS_HPP_INCLUDED
|
||||
#define BOOST_LEAF_CONFIG_TLS_GLOBALS_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// LEAF requires thread local storage support for pointers and for uin32_t values.
|
||||
|
||||
// This header implements "thread local" storage for pointers and for unsigned int
|
||||
// values using globals, which is suitable for single thread environments.
|
||||
// This header implements the TLS API specified in tls.hpp using globals, which
|
||||
// is suitable for single thread environments.
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -17,10 +15,16 @@ namespace boost { namespace leaf {
|
||||
namespace detail
|
||||
{
|
||||
using atomic_unsigned_int = unsigned int;
|
||||
}
|
||||
|
||||
namespace tls
|
||||
{
|
||||
template <class=void>
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE id_factory
|
||||
{
|
||||
static atomic_unsigned_int counter;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
atomic_unsigned_int id_factory<T>::counter = 1;
|
||||
|
||||
template <class T>
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE ptr
|
||||
{
|
||||
@@ -30,42 +34,59 @@ namespace tls
|
||||
template <class T>
|
||||
T * ptr<T>::p;
|
||||
|
||||
template <class T>
|
||||
T * read_ptr() noexcept
|
||||
{
|
||||
return ptr<T>::p;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void write_ptr( T * p ) noexcept
|
||||
{
|
||||
ptr<T>::p = p;
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class Tag>
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE tagged_uint
|
||||
template <class=void>
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE current_error_id_storage
|
||||
{
|
||||
static unsigned x;
|
||||
};
|
||||
|
||||
template <class Tag>
|
||||
unsigned tagged_uint<Tag>::x;
|
||||
template <class T>
|
||||
unsigned current_error_id_storage<T>::x = 0;
|
||||
} // namespace detail
|
||||
|
||||
template <class Tag>
|
||||
unsigned read_uint() noexcept
|
||||
} } // namespace boost::leaf
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace tls
|
||||
{
|
||||
BOOST_LEAF_ALWAYS_INLINE unsigned generate_next_error_id() noexcept
|
||||
{
|
||||
return tagged_uint<Tag>::x;
|
||||
unsigned id = (detail::id_factory<>::counter += 4);
|
||||
BOOST_LEAF_ASSERT((id&3) == 1);
|
||||
return id;
|
||||
}
|
||||
|
||||
template <class Tag>
|
||||
void write_uint( unsigned x ) noexcept
|
||||
BOOST_LEAF_ALWAYS_INLINE void write_current_error_id( unsigned v ) noexcept
|
||||
{
|
||||
tagged_uint<Tag>::x = x;
|
||||
detail::current_error_id_storage<>::x = v;
|
||||
}
|
||||
}
|
||||
|
||||
} }
|
||||
BOOST_LEAF_ALWAYS_INLINE unsigned read_current_error_id() noexcept
|
||||
{
|
||||
return detail::current_error_id_storage<>::x;
|
||||
}
|
||||
|
||||
#endif // BOOST_LEAF_CONFIG_TLS_GLOBALS_HPP_INCLUDED
|
||||
template <class T>
|
||||
BOOST_LEAF_ALWAYS_INLINE void reserve_ptr()
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_LEAF_ALWAYS_INLINE void write_ptr( T * p ) noexcept
|
||||
{
|
||||
detail::ptr<T>::p = p;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_LEAF_ALWAYS_INLINE T * read_ptr() noexcept
|
||||
{
|
||||
return detail::ptr<T>::p;
|
||||
}
|
||||
} // namespace tls
|
||||
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // #ifndef BOOST_LEAF_CONFIG_TLS_GLOBALS_HPP_INCLUDED
|
||||
|
||||
495
include/boost/leaf/config/tls_win32.hpp
Normal file
495
include/boost/leaf/config/tls_win32.hpp
Normal file
@@ -0,0 +1,495 @@
|
||||
#ifndef BOOST_LEAF_CONFIG_TLS_WIN32_HPP_INCLUDED
|
||||
#define BOOST_LEAF_CONFIG_TLS_WIN32_HPP_INCLUDED
|
||||
|
||||
// Copyright 2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// This header implements the TLS API specified in tls.hpp using Win32 TLS
|
||||
// functions, allowing error objects to cross DLL boundaries on Windows. This
|
||||
// implementation is enabled by defining BOOST_LEAF_CFG_WIN32=2 before including
|
||||
// any LEAF headers.
|
||||
|
||||
#ifndef _WIN32
|
||||
# error "This header is only for Windows"
|
||||
#endif
|
||||
|
||||
#include <atomic>
|
||||
#include <unordered_map>
|
||||
#include <cstdint>
|
||||
#include <new>
|
||||
#include <stdexcept>
|
||||
#include <windows.h>
|
||||
#ifdef min
|
||||
# undef min
|
||||
#endif
|
||||
#ifdef max
|
||||
# undef max
|
||||
#endif
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
// Thrown on TLS allocation failure.
|
||||
class win32_tls_error:
|
||||
public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit win32_tls_error(char const * what) noexcept:
|
||||
std::runtime_error(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
__declspec(noreturn) inline void raise_fail_fast(NTSTATUS status) noexcept
|
||||
{
|
||||
EXCEPTION_RECORD rec = {};
|
||||
rec.ExceptionCode = status;
|
||||
rec.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
|
||||
RaiseFailFastException(&rec, nullptr, 0);
|
||||
BOOST_LEAF_UNREACHABLE;
|
||||
}
|
||||
|
||||
template <class T, class... Args>
|
||||
T * heap_new(Args && ... args) noexcept
|
||||
{
|
||||
void * mem = HeapAlloc(GetProcessHeap(), 0, sizeof(T));
|
||||
if (!mem)
|
||||
{
|
||||
raise_fail_fast(STATUS_NO_MEMORY);
|
||||
BOOST_LEAF_UNREACHABLE;
|
||||
}
|
||||
return new (mem) T(static_cast<Args &&>(args)...);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void heap_delete(T * p) noexcept
|
||||
{
|
||||
if (p)
|
||||
{
|
||||
p->~T();
|
||||
BOOL r = HeapFree(GetProcessHeap(), 0, p);
|
||||
BOOST_LEAF_ASSERT(r), (void) r;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class heap_allocator
|
||||
{
|
||||
public:
|
||||
|
||||
using value_type = T;
|
||||
|
||||
heap_allocator() noexcept = default;
|
||||
|
||||
template <class U>
|
||||
heap_allocator(heap_allocator<U> const &) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
T * allocate(std::size_t n) noexcept
|
||||
{
|
||||
if (void * p = HeapAlloc(GetProcessHeap(), 0, n * sizeof(T)))
|
||||
return static_cast<T *>(p);
|
||||
raise_fail_fast(STATUS_NO_MEMORY);
|
||||
BOOST_LEAF_UNREACHABLE;
|
||||
}
|
||||
|
||||
void deallocate(T * p, std::size_t) noexcept
|
||||
{
|
||||
BOOL r = HeapFree(GetProcessHeap(), 0, p);
|
||||
BOOST_LEAF_ASSERT(r), (void) r;
|
||||
}
|
||||
|
||||
friend bool operator==(heap_allocator const &, heap_allocator const &) noexcept { return true; }
|
||||
friend bool operator!=(heap_allocator const &, heap_allocator const &) noexcept { return false; }
|
||||
};
|
||||
|
||||
class critical_section_lock
|
||||
{
|
||||
critical_section_lock(critical_section_lock const &) = delete;
|
||||
critical_section_lock & operator=(critical_section_lock const &) = delete;
|
||||
|
||||
CRITICAL_SECTION & cs_;
|
||||
|
||||
public:
|
||||
|
||||
explicit critical_section_lock(CRITICAL_SECTION & cs) noexcept:
|
||||
cs_(cs)
|
||||
{
|
||||
EnterCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
~critical_section_lock() noexcept
|
||||
{
|
||||
LeaveCriticalSection(&cs_);
|
||||
}
|
||||
};
|
||||
|
||||
using atomic_unsigned_int = std::atomic<unsigned int>;
|
||||
|
||||
template <int N, int I>
|
||||
struct cpp11_hash_step
|
||||
{
|
||||
BOOST_LEAF_ALWAYS_INLINE constexpr static std::uint32_t compute(char const (&str)[N], std::uint32_t hash) noexcept
|
||||
{
|
||||
return cpp11_hash_step<N, I - 1>::compute(str, (hash ^ static_cast<std::uint32_t>(str[I])) * 16777619u);
|
||||
}
|
||||
};
|
||||
|
||||
template <int N>
|
||||
struct cpp11_hash_step<N, -1>
|
||||
{
|
||||
BOOST_LEAF_ALWAYS_INLINE constexpr static std::uint32_t compute(char const (&)[N], std::uint32_t hash) noexcept
|
||||
{
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
template <int N>
|
||||
BOOST_LEAF_ALWAYS_INLINE constexpr std::uint32_t cpp11_hash_string(char const (&str)[N]) noexcept
|
||||
{
|
||||
return cpp11_hash_step<N, N - 2>::compute(str, 2166136261u); // str[N-2] is the last character before the \0.
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
namespace n
|
||||
{
|
||||
template <class T>
|
||||
BOOST_LEAF_ALWAYS_INLINE constexpr std::uint32_t __cdecl h() noexcept
|
||||
{
|
||||
return detail::cpp11_hash_string(BOOST_LEAF_PRETTY_FUNCTION);
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<class T>
|
||||
BOOST_LEAF_ALWAYS_INLINE constexpr std::uint32_t type_hash() noexcept
|
||||
{
|
||||
return n::h<T>();
|
||||
}
|
||||
}
|
||||
|
||||
} } // namespace boost::leaf
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class slot_map
|
||||
{
|
||||
slot_map(slot_map const &) = delete;
|
||||
slot_map & operator=(slot_map const &) = delete;
|
||||
|
||||
class tls_slot_index
|
||||
{
|
||||
tls_slot_index(tls_slot_index const &) = delete;
|
||||
tls_slot_index & operator=(tls_slot_index const &) = delete;
|
||||
tls_slot_index & operator=(tls_slot_index &&) = delete;
|
||||
|
||||
DWORD idx_;
|
||||
|
||||
public:
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE tls_slot_index():
|
||||
idx_(TlsAlloc())
|
||||
{
|
||||
if (idx_ == TLS_OUT_OF_INDEXES)
|
||||
throw_exception_(win32_tls_error("TLS_OUT_OF_INDEXES"));
|
||||
}
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE ~tls_slot_index() noexcept
|
||||
{
|
||||
if (idx_ == TLS_OUT_OF_INDEXES)
|
||||
return;
|
||||
BOOL r = TlsFree(idx_);
|
||||
BOOST_LEAF_ASSERT(r), (void) r;
|
||||
}
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE tls_slot_index(tls_slot_index && other) noexcept:
|
||||
idx_(other.idx_)
|
||||
{
|
||||
other.idx_ = TLS_OUT_OF_INDEXES;
|
||||
}
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE DWORD get() const noexcept
|
||||
{
|
||||
BOOST_LEAF_ASSERT(idx_ != TLS_OUT_OF_INDEXES);
|
||||
return idx_;
|
||||
}
|
||||
};
|
||||
|
||||
int refcount_;
|
||||
HANDLE const mapping_;
|
||||
tls_slot_index const error_id_slot_;
|
||||
mutable CRITICAL_SECTION cs_;
|
||||
std::unordered_map<
|
||||
std::uint32_t,
|
||||
tls_slot_index,
|
||||
std::hash<std::uint32_t>,
|
||||
std::equal_to<std::uint32_t>,
|
||||
heap_allocator<std::pair<std::uint32_t const, tls_slot_index>>> map_;
|
||||
atomic_unsigned_int error_id_storage_;
|
||||
|
||||
public:
|
||||
|
||||
explicit slot_map(HANDLE mapping) noexcept:
|
||||
refcount_(1),
|
||||
mapping_(mapping),
|
||||
error_id_storage_(1)
|
||||
{
|
||||
BOOST_LEAF_ASSERT(mapping != INVALID_HANDLE_VALUE);
|
||||
InitializeCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
~slot_map() noexcept
|
||||
{
|
||||
DeleteCriticalSection(&cs_);
|
||||
BOOL r = CloseHandle(mapping_);
|
||||
BOOST_LEAF_ASSERT(r), (void) r;
|
||||
}
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE void add_ref() noexcept
|
||||
{
|
||||
BOOST_LEAF_ASSERT(refcount_ >= 1);
|
||||
++refcount_;
|
||||
}
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE void release() noexcept
|
||||
{
|
||||
--refcount_;
|
||||
BOOST_LEAF_ASSERT(refcount_ >= 0);
|
||||
if (refcount_ == 0)
|
||||
heap_delete(this);
|
||||
}
|
||||
|
||||
DWORD check(std::uint32_t type_hash) const noexcept
|
||||
{
|
||||
critical_section_lock lock(cs_);
|
||||
auto it = map_.find(type_hash);
|
||||
return (it != map_.end()) ? it->second.get() : TLS_OUT_OF_INDEXES;
|
||||
}
|
||||
|
||||
DWORD get(std::uint32_t type_hash)
|
||||
{
|
||||
critical_section_lock lock(cs_);
|
||||
DWORD idx = map_[type_hash].get();
|
||||
BOOST_LEAF_ASSERT(idx != TLS_OUT_OF_INDEXES);
|
||||
return idx;
|
||||
}
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE DWORD error_id_slot() const noexcept
|
||||
{
|
||||
return error_id_slot_.get();
|
||||
}
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE atomic_unsigned_int & error_id_storage() noexcept
|
||||
{
|
||||
return error_id_storage_;
|
||||
}
|
||||
}; // class slot_map
|
||||
|
||||
class module_state
|
||||
{
|
||||
module_state(module_state const &) = delete;
|
||||
module_state & operator=(module_state const &) = delete;
|
||||
|
||||
static constexpr unsigned tls_failure_create_mapping = 0x01;
|
||||
static constexpr unsigned tls_failure_map_view = 0x02;
|
||||
|
||||
void * hinstance_;
|
||||
unsigned tls_failures_;
|
||||
slot_map * sm_;
|
||||
|
||||
public:
|
||||
|
||||
constexpr module_state() noexcept:
|
||||
hinstance_(nullptr),
|
||||
tls_failures_(0),
|
||||
sm_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE slot_map & sm() const noexcept
|
||||
{
|
||||
BOOST_LEAF_ASSERT(hinstance_);
|
||||
BOOST_LEAF_ASSERT(!(tls_failures_ & tls_failure_create_mapping));
|
||||
BOOST_LEAF_ASSERT(!(tls_failures_ & tls_failure_map_view));
|
||||
BOOST_LEAF_ASSERT(sm_);
|
||||
return *sm_;
|
||||
}
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE void update(PVOID hinstDLL, DWORD dwReason) noexcept
|
||||
{
|
||||
if (dwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
hinstance_ = hinstDLL;
|
||||
char name[32] = "Local\\boost_leaf_";
|
||||
{
|
||||
constexpr static char const hex[] = "0123456789ABCDEF";
|
||||
DWORD pid = GetCurrentProcessId();
|
||||
for (int i = 7; i >= 0; --i)
|
||||
{
|
||||
name[17 + i] = hex[pid & 0xf];
|
||||
pid >>= 4;
|
||||
}
|
||||
name[25] = '\0';
|
||||
}
|
||||
HANDLE mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, sizeof(slot_map *), name);
|
||||
DWORD mapping_status = GetLastError();
|
||||
if (!mapping)
|
||||
{
|
||||
tls_failures_ |= tls_failure_create_mapping;
|
||||
return;
|
||||
}
|
||||
BOOST_LEAF_ASSERT(mapping_status == ERROR_ALREADY_EXISTS || mapping_status == ERROR_SUCCESS);
|
||||
bool is_first_module = (mapping_status == ERROR_SUCCESS);
|
||||
slot_map * * mapped_ptr = static_cast<slot_map * *>(MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, sizeof(slot_map *)));
|
||||
if (!mapped_ptr)
|
||||
{
|
||||
tls_failures_ |= tls_failure_map_view;
|
||||
BOOL r = CloseHandle(mapping);
|
||||
BOOST_LEAF_ASSERT(r), (void) r;
|
||||
return;
|
||||
}
|
||||
if (is_first_module)
|
||||
sm_ = *mapped_ptr = heap_new<slot_map>(mapping);
|
||||
else
|
||||
{
|
||||
sm_ = *mapped_ptr;
|
||||
sm_->add_ref();
|
||||
BOOL r = CloseHandle(mapping);
|
||||
BOOST_LEAF_ASSERT(r), (void) r;
|
||||
}
|
||||
UnmapViewOfFile(mapped_ptr);
|
||||
}
|
||||
else if (dwReason == DLL_PROCESS_DETACH)
|
||||
{
|
||||
BOOST_LEAF_ASSERT(sm_ || tls_failures_);
|
||||
if (sm_)
|
||||
{
|
||||
sm_->release();
|
||||
sm_ = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}; // class module_state
|
||||
|
||||
template<int = 0>
|
||||
struct module
|
||||
{
|
||||
static module_state state;
|
||||
};
|
||||
|
||||
template<int N>
|
||||
module_state module<N>::state;
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE unsigned generate_next_error_id() noexcept
|
||||
{
|
||||
static atomic_unsigned_int & counter = module<>::state.sm().error_id_storage();
|
||||
unsigned id = (counter += 4);
|
||||
BOOST_LEAF_ASSERT((id&3) == 1);
|
||||
return id;
|
||||
}
|
||||
|
||||
inline void NTAPI tls_callback(PVOID hinstDLL, DWORD dwReason, PVOID) noexcept
|
||||
{
|
||||
module<>::state.update(hinstDLL, dwReason);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma section(".CRT$XLB", long, read)
|
||||
# pragma data_seg(push, ".CRT$XLB")
|
||||
|
||||
extern "C" __declspec(selectany) PIMAGE_TLS_CALLBACK boost_leaf_tls_callback = tls_callback;
|
||||
|
||||
# pragma data_seg(pop)
|
||||
# ifdef _WIN64
|
||||
# pragma comment(linker, "/INCLUDE:boost_leaf_tls_callback")
|
||||
# else
|
||||
# pragma comment(linker, "/INCLUDE:_boost_leaf_tls_callback")
|
||||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wattributes"
|
||||
|
||||
extern "C" __attribute__((used, selectany)) PIMAGE_TLS_CALLBACK boost_leaf_tls_callback __attribute__((section(".CRT$XLB"))) = tls_callback;
|
||||
|
||||
# pragma GCC diagnostic pop
|
||||
#else
|
||||
# error Unknown compiler, unable to define .CRT$XLB section
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
} } // namespace boost::leaf
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace tls
|
||||
{
|
||||
BOOST_LEAF_ALWAYS_INLINE unsigned generate_next_error_id() noexcept
|
||||
{
|
||||
return detail::generate_next_error_id();
|
||||
}
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE void write_current_error_id(unsigned x) noexcept
|
||||
{
|
||||
using namespace detail;
|
||||
DWORD slot = module<>::state.sm().error_id_slot();
|
||||
BOOL r = TlsSetValue(slot, reinterpret_cast<void *>(static_cast<std::uintptr_t>(x)));
|
||||
BOOST_LEAF_ASSERT(r), (void) r;
|
||||
}
|
||||
|
||||
BOOST_LEAF_ALWAYS_INLINE unsigned read_current_error_id() noexcept
|
||||
{
|
||||
using namespace detail;
|
||||
DWORD slot = module<>::state.sm().error_id_slot();
|
||||
LPVOID value = TlsGetValue(slot);
|
||||
BOOST_LEAF_ASSERT(GetLastError() == ERROR_SUCCESS);
|
||||
return static_cast<unsigned>(reinterpret_cast<std::uintptr_t>(value));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_LEAF_ALWAYS_INLINE void reserve_ptr()
|
||||
{
|
||||
using namespace detail;
|
||||
thread_local DWORD const cached_slot = module<>::state.sm().get(type_hash<T>());
|
||||
BOOST_LEAF_ASSERT(cached_slot != TLS_OUT_OF_INDEXES), (void) cached_slot;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_LEAF_ALWAYS_INLINE void write_ptr(T * p) noexcept
|
||||
{
|
||||
using namespace detail;
|
||||
thread_local DWORD const cached_slot = module<>::state.sm().check(type_hash<T>());
|
||||
DWORD slot = cached_slot;
|
||||
BOOST_LEAF_ASSERT(slot != TLS_OUT_OF_INDEXES);
|
||||
BOOL r = TlsSetValue(slot, p);
|
||||
BOOST_LEAF_ASSERT(r), (void) r;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_LEAF_ALWAYS_INLINE T * read_ptr() noexcept
|
||||
{
|
||||
using namespace detail;
|
||||
thread_local DWORD cached_slot = TLS_OUT_OF_INDEXES;
|
||||
if (cached_slot == TLS_OUT_OF_INDEXES)
|
||||
cached_slot = module<>::state.sm().check(type_hash<T>());
|
||||
DWORD slot = cached_slot;
|
||||
if (slot == TLS_OUT_OF_INDEXES)
|
||||
return nullptr;
|
||||
LPVOID value = TlsGetValue(slot);
|
||||
BOOST_LEAF_ASSERT(GetLastError() == ERROR_SUCCESS);
|
||||
return static_cast<T *>(value);
|
||||
}
|
||||
} // namespace tls
|
||||
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // #ifndef BOOST_LEAF_CONFIG_TLS_WIN32_HPP_INCLUDED
|
||||
45
include/boost/leaf/config/visibility.hpp
Normal file
45
include/boost/leaf/config/visibility.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef BOOST_LEAF_CONFIG_VISIBILITY_HPP_INCLUDED
|
||||
#define BOOST_LEAF_CONFIG_VISIBILITY_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE error_id;
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE error_info;
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE diagnostic_info;
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE diagnostic_details;
|
||||
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE e_api_function;
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE e_file_name;
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE e_errno;
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE e_type_info_name;
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE e_at_line;
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE e_source_location;
|
||||
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE bad_result;
|
||||
template <class> class BOOST_LEAF_SYMBOL_VISIBLE result;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class> class BOOST_LEAF_SYMBOL_VISIBLE slot;
|
||||
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE exception_base;
|
||||
|
||||
template <class> class BOOST_LEAF_SYMBOL_VISIBLE exception;
|
||||
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE dynamic_allocator;
|
||||
#endif
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE leaf_error_category;
|
||||
template <class> struct BOOST_LEAF_SYMBOL_VISIBLE get_leaf_error_category;
|
||||
#endif
|
||||
}
|
||||
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // BOOST_LEAF_CONFIG_VISIBILITY_HPP_INCLUDED
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_LEAF_CONTEXT_HPP_INCLUDED
|
||||
#define BOOST_LEAF_CONTEXT_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace detail
|
||||
{
|
||||
static_assert(sizeof(E) == 0, "Error handlers must take this type by value");
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace detail
|
||||
else
|
||||
return find_in_tuple<T, I+1, Tp...>(t);
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -227,7 +227,7 @@ namespace detail
|
||||
{
|
||||
tuple_for_each<std::tuple_size<Tup>::value, Tup>::print(os, tup, to_print, prefix);
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -262,7 +262,7 @@ namespace detail
|
||||
|
||||
template <class... E>
|
||||
using deduce_e_tuple = typename deduce_e_tuple_impl<typename deduce_e_type_list<leaf_detail_mp11::mp_list<E...>>::type>::type;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -292,11 +292,13 @@ class context
|
||||
if( ctx_ )
|
||||
ctx_->activate();
|
||||
}
|
||||
#if __cplusplus < 201703L
|
||||
BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE raii_deactivator( raii_deactivator && x ) noexcept:
|
||||
ctx_(x.ctx_)
|
||||
{
|
||||
x.ctx_ = nullptr;
|
||||
}
|
||||
#endif
|
||||
BOOST_LEAF_ALWAYS_INLINE ~raii_deactivator() noexcept
|
||||
{
|
||||
if( ctx_ && ctx_->is_active() )
|
||||
@@ -313,7 +315,7 @@ public:
|
||||
BOOST_LEAF_ASSERT(!x.is_active());
|
||||
}
|
||||
|
||||
BOOST_LEAF_CONSTEXPR context() noexcept:
|
||||
BOOST_LEAF_CONSTEXPR context():
|
||||
is_active_(false)
|
||||
{
|
||||
}
|
||||
@@ -398,7 +400,7 @@ public:
|
||||
{
|
||||
return raii_deactivator(ctx);
|
||||
}
|
||||
};
|
||||
}; // template context
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -439,7 +441,7 @@ namespace detail
|
||||
{
|
||||
using type = deduce_context<leaf_detail_mp11::mp_append<typename fn_mp_args_fwd<H>::type...>>;
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <class... H>
|
||||
using context_type_from_handlers = typename detail::context_type_from_handlers_impl<H...>::type;
|
||||
@@ -458,6 +460,6 @@ BOOST_LEAF_CONSTEXPR inline context_type_from_handlers<H...> make_context( H &&
|
||||
return { };
|
||||
}
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // BOOST_LEAF_CONTEXT_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_CONTEXT_HPP_INCLUDED
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_LEAF_DETAIL_CAPTURE_LIST_HPP_INCLUDED
|
||||
#define BOOST_LEAF_DETAIL_CAPTURE_LIST_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -14,11 +14,8 @@
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
class error_id;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE tls_tag_id_factory_current_id;
|
||||
|
||||
class capture_list
|
||||
{
|
||||
@@ -87,7 +84,7 @@ namespace detail
|
||||
{
|
||||
capture_list moved(first_);
|
||||
first_ = nullptr;
|
||||
tls::write_uint<detail::tls_tag_id_factory_current_id>(unsigned(err_id));
|
||||
tls::write_current_error_id(unsigned(err_id));
|
||||
moved.for_each(
|
||||
[err_id]( node & n )
|
||||
{
|
||||
@@ -113,12 +110,12 @@ namespace detail
|
||||
(void) to_print;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
}; // class capture_list
|
||||
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
#endif // BOOST_LEAF_DETAIL_CAPTURE_LIST_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_DETAIL_CAPTURE_LIST_HPP_INCLUDED
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_LEAF_DETAIL_DEMANGLE_HPP_INCLUDED
|
||||
#define BOOST_LEAF_DETAIL_DEMANGLE_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -41,14 +41,14 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_DIAGNOSTICS
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// The functions below are C++11 constexpr, but we use BOOST_LEAF_ALWAYS_INLINE to control object file
|
||||
// section count / template bleat. Evidently this makes a difference on gcc / windows at least.
|
||||
// section count / template bloat.
|
||||
|
||||
template <int S1, int S2, int I, bool = S1 >= S2>
|
||||
struct cpp11_prefix
|
||||
@@ -111,7 +111,7 @@ namespace detail
|
||||
{
|
||||
return cpp11_suffix<S1, S2, S1 - 2, S2 - 2>::check(str, suffix) ? S1 - S2 : 0;
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
namespace n
|
||||
{
|
||||
@@ -205,7 +205,7 @@ namespace n
|
||||
int const p = sizeof(char[1 + !!s02 * (p22 + p23 + p24)]) - 1; // p is not zero, we've static asserted the hell out of it
|
||||
return { BOOST_LEAF_PRETTY_FUNCTION + p, s02 - p };
|
||||
}
|
||||
}
|
||||
} // namespace n
|
||||
|
||||
using parsed = n::r;
|
||||
|
||||
@@ -215,7 +215,7 @@ parsed parse()
|
||||
return n::p<T>();
|
||||
}
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -243,11 +243,11 @@ namespace detail
|
||||
} d(mangled_name);
|
||||
if( d.demangled_name )
|
||||
return os << d.demangled_name;
|
||||
#endif
|
||||
#endif // #if defined(BOOST_LEAF_CFG_DIAGNOSTICS) && defined(BOOST_LEAF_HAS_CXXABI_H)
|
||||
return os << mangled_name;
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // BOOST_LEAF_DETAIL_DEMANGLE_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_DETAIL_DEMANGLE_HPP_INCLUDED
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_LEAF_DETAIL_FUNCTION_TRAITS_HPP_INCLUDED
|
||||
#define BOOST_LEAF_DETAIL_FUNCTION_TRAITS_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -92,8 +92,8 @@ namespace detail
|
||||
|
||||
template <class F>
|
||||
using fn_mp_args = typename function_traits<F>::mp_args;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // BOOST_LEAF_DETAIL_FUNCTION_TRAITS_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_DETAIL_FUNCTION_TRAITS_HPP_INCLUDED
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define BOOST_LEAF_DETAIL_MP11_HPP_INCLUDED
|
||||
|
||||
// Copyright 2015-2017 Peter Dimov.
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
//
|
||||
@@ -300,4 +300,4 @@ template<template<class...> class F, class... T> using mp_valid = typename detai
|
||||
|
||||
} } }
|
||||
|
||||
#endif // BOOST_LEAF_DETAIL_MP11_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_DETAIL_MP11_HPP_INCLUDED
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
#ifndef BOOST_LEAF_DETAIL_OPTIONAL_HPP_INCLUDED
|
||||
#define BOOST_LEAF_DETAIL_OPTIONAL_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/leaf/config.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <new>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
@@ -133,16 +131,6 @@ namespace detail
|
||||
return value_;
|
||||
}
|
||||
|
||||
BOOST_LEAF_CONSTEXPR T const * has_value_any_key() const noexcept
|
||||
{
|
||||
return key_ ? &value_ : nullptr;
|
||||
}
|
||||
|
||||
BOOST_LEAF_CONSTEXPR T * has_value_any_key() noexcept
|
||||
{
|
||||
return key_ ? &value_ : nullptr;
|
||||
}
|
||||
|
||||
BOOST_LEAF_CONSTEXPR T const * has_value(int key) const noexcept
|
||||
{
|
||||
BOOST_LEAF_ASSERT(key);
|
||||
@@ -184,18 +172,10 @@ namespace detail
|
||||
reset();
|
||||
return tmp;
|
||||
}
|
||||
}; // template optional
|
||||
|
||||
BOOST_LEAF_CONSTEXPR T & value_or_default(int key) noexcept
|
||||
{
|
||||
if( T * v = has_value(key) )
|
||||
return *v;
|
||||
else
|
||||
return load(key);
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
}
|
||||
} } // namespace boost::leaf
|
||||
|
||||
} }
|
||||
|
||||
#endif // BOOST_LEAF_DETAIL_OPTIONAL_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_DETAIL_OPTIONAL_HPP_INCLUDED
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_LEAF_DETAIL_PRINT_HPP_INCLUDED
|
||||
#define BOOST_LEAF_DETAIL_PRINT_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
#include <boost/leaf/detail/demangle.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <exception>
|
||||
#include <iosfwd>
|
||||
#include <cstring>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
@@ -155,8 +153,8 @@ namespace detail
|
||||
return print_impl<Enum>(os, prefix, delimiter, ": ", static_cast<typename std::underlying_type<Enum>::type>(enum_));
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // BOOST_LEAF_DETAIL_PRINT_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_DETAIL_PRINT_HPP_INCLUDED
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_LEAF_DIAGNOSTICS_HPP_INCLUDED
|
||||
#define BOOST_LEAF_DIAGNOSTICS_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -44,7 +44,7 @@ protected:
|
||||
x.print_diagnostic_info(os);
|
||||
return os << '\n';
|
||||
}
|
||||
};
|
||||
}; // class diagnostic_info
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@@ -68,7 +68,7 @@ namespace detail
|
||||
};
|
||||
}
|
||||
|
||||
#else
|
||||
#else // #if BOOST_LEAF_CFG_DIAGNOSTICS
|
||||
|
||||
class diagnostic_info: public error_info
|
||||
{
|
||||
@@ -94,7 +94,7 @@ protected:
|
||||
x.print_diagnostic_info(os);
|
||||
return os << "\n";
|
||||
}
|
||||
};
|
||||
}; // class diagnostic_info
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@@ -117,7 +117,7 @@ namespace detail
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #else (#if BOOST_LEAF_CFG_DIAGNOSTICS)
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -157,7 +157,7 @@ protected:
|
||||
x.print_diagnostic_details(os);
|
||||
return os << '\n';
|
||||
}
|
||||
};
|
||||
}; // class diagnostic_details
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@@ -177,12 +177,12 @@ namespace detail
|
||||
BOOST_LEAF_CONSTEXPR static diagnostic_details_ get( Tup const & tup, error_info const & ei ) noexcept
|
||||
{
|
||||
slot<dynamic_allocator> const * da = find_in_tuple<slot<dynamic_allocator>>(tup);
|
||||
return diagnostic_details_(ei, tup, da ? da->has_value_any_key() : nullptr );
|
||||
return diagnostic_details_(ei, tup, da ? &da->get() : nullptr );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#else
|
||||
#else // #if BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
class diagnostic_details: public diagnostic_info
|
||||
{
|
||||
@@ -209,7 +209,7 @@ protected:
|
||||
x.print_diagnostic_details(os);
|
||||
return os << "\n";
|
||||
}
|
||||
};
|
||||
}; // class diagnostic_details
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@@ -233,9 +233,9 @@ namespace detail
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #else (#if BOOST_LEAF_CFG_CAPTURE)
|
||||
|
||||
#else
|
||||
#else // #if BOOST_LEAF_CFG_DIAGNOSTICS
|
||||
|
||||
class diagnostic_details: public diagnostic_info
|
||||
{
|
||||
@@ -284,10 +284,10 @@ namespace detail
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #else (#if BOOST_LEAF_CFG_DIAGNOSTICS)
|
||||
|
||||
using verbose_diagnostic_info = diagnostic_details;
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // BOOST_LEAF_DIAGNOSTICS_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_DIAGNOSTICS_HPP_INCLUDED
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_LEAF_ERROR_HPP_INCLUDED
|
||||
#define BOOST_LEAF_ERROR_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
std::move(BOOST_LEAF_TMP);\
|
||||
}).value()
|
||||
|
||||
#else
|
||||
#else // #if BOOST_LEAF_CFG_GNUC_STMTEXPR
|
||||
|
||||
#define BOOST_LEAF_CHECK(r)\
|
||||
{\
|
||||
@@ -56,13 +56,13 @@
|
||||
return BOOST_LEAF_TMP.error();\
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #else (#if BOOST_LEAF_CFG_GNUC_STMTEXPR)
|
||||
|
||||
#define BOOST_LEAF_NEW_ERROR ::boost::leaf::detail::inject_loc{__FILE__,__LINE__,__FUNCTION__}+::boost::leaf::new_error
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE e_source_location
|
||||
struct e_source_location
|
||||
{
|
||||
char const * file;
|
||||
int line;
|
||||
@@ -82,11 +82,9 @@ struct show_in_diagnostics<e_source_location>: std::false_type
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE error_id;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE exception_base
|
||||
class exception_base
|
||||
{
|
||||
public:
|
||||
virtual error_id get_error_id() const noexcept = 0;
|
||||
@@ -104,9 +102,10 @@ namespace detail
|
||||
namespace detail
|
||||
{
|
||||
template <class E>
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE slot:
|
||||
class slot:
|
||||
optional<E>
|
||||
{
|
||||
static_assert(std::is_same<E, typename std::decay<E>::type>::value, "E must be decayed for slot<E>");
|
||||
slot( slot const & ) = delete;
|
||||
slot & operator=( slot const & ) = delete;
|
||||
|
||||
@@ -115,9 +114,18 @@ namespace detail
|
||||
|
||||
public:
|
||||
|
||||
BOOST_LEAF_CONSTEXPR slot() noexcept:
|
||||
BOOST_LEAF_CONSTEXPR slot():
|
||||
prev_(nullptr)
|
||||
{
|
||||
tls::reserve_ptr<slot<E>>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_LEAF_CONSTEXPR slot( int key, T && e ):
|
||||
optional<E>(key, std::forward<T>(e)),
|
||||
prev_(nullptr)
|
||||
{
|
||||
tls::reserve_ptr<slot<E>>();
|
||||
}
|
||||
|
||||
BOOST_LEAF_CONSTEXPR slot( slot && x ) noexcept:
|
||||
@@ -159,11 +167,9 @@ namespace detail
|
||||
|
||||
using impl::load;
|
||||
using impl::has_value;
|
||||
using impl::has_value_any_key;
|
||||
using impl::value;
|
||||
using impl::value_or_default;
|
||||
};
|
||||
}
|
||||
}; // template slot
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -171,12 +177,22 @@ namespace detail
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE dynamic_allocator:
|
||||
class preloaded_base;
|
||||
|
||||
template <class E>
|
||||
struct capturing_slot_node_allocator;
|
||||
|
||||
class dynamic_allocator:
|
||||
capture_list
|
||||
{
|
||||
dynamic_allocator( dynamic_allocator const & ) = delete;
|
||||
dynamic_allocator & operator=( dynamic_allocator const & ) = delete;
|
||||
|
||||
template <class>
|
||||
friend struct capturing_slot_node_allocator;
|
||||
|
||||
preloaded_base * preloaded_list_;
|
||||
|
||||
class capturing_node:
|
||||
public capture_list::node
|
||||
{
|
||||
@@ -192,54 +208,60 @@ namespace detail
|
||||
};
|
||||
|
||||
template <class E>
|
||||
class capturing_slot_node:
|
||||
public capturing_node,
|
||||
public slot<E>
|
||||
class capturing_slot_node final:
|
||||
public slot<E>,
|
||||
public capturing_node
|
||||
{
|
||||
using impl = slot<E>;
|
||||
capturing_slot_node( capturing_slot_node const & ) = delete;
|
||||
capturing_slot_node & operator=( capturing_slot_node const & ) = delete;
|
||||
void deactivate() const noexcept final override
|
||||
void deactivate() const noexcept override
|
||||
{
|
||||
impl::deactivate();
|
||||
}
|
||||
void unload( int err_id ) final override
|
||||
void unload( int err_id ) override
|
||||
{
|
||||
impl::unload(err_id);
|
||||
}
|
||||
#if BOOST_LEAF_CFG_DIAGNOSTICS
|
||||
void print(std::ostream & os, error_id const & to_print, char const * & prefix) const final override
|
||||
void print(std::ostream & os, error_id const & to_print, char const * & prefix) const override
|
||||
{
|
||||
impl::print(os, to_print, prefix);
|
||||
}
|
||||
#endif
|
||||
public:
|
||||
template <class T>
|
||||
BOOST_LEAF_CONSTEXPR capturing_slot_node( capture_list::node * * & last, int err_id, T && e ):
|
||||
BOOST_LEAF_CONSTEXPR explicit capturing_slot_node( capture_list::node * * & last ):
|
||||
capturing_node(last)
|
||||
{
|
||||
BOOST_LEAF_ASSERT(last == &next_);
|
||||
BOOST_LEAF_ASSERT(next_ == nullptr);
|
||||
}
|
||||
template <class T>
|
||||
BOOST_LEAF_CONSTEXPR capturing_slot_node( capture_list::node * * & last, int err_id, T && e ):
|
||||
slot<E>(err_id, std::forward<T>(e)),
|
||||
capturing_node(last)
|
||||
{
|
||||
BOOST_LEAF_ASSERT(last == &next_);
|
||||
BOOST_LEAF_ASSERT(next_ == nullptr);
|
||||
impl::load(err_id, std::forward<T>(e));
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
class capturing_exception_node:
|
||||
class capturing_exception_node final:
|
||||
public capturing_node
|
||||
{
|
||||
capturing_exception_node( capturing_exception_node const & ) = delete;
|
||||
capturing_exception_node & operator=( capturing_exception_node const & ) = delete;
|
||||
void deactivate() const noexcept final override
|
||||
void deactivate() const noexcept override
|
||||
{
|
||||
BOOST_LEAF_ASSERT(0);
|
||||
}
|
||||
void unload( int ) final override
|
||||
void unload( int ) override
|
||||
{
|
||||
std::rethrow_exception(ex_);
|
||||
}
|
||||
#if BOOST_LEAF_CFG_DIAGNOSTICS
|
||||
void print(std::ostream &, error_id const &, char const * &) const final override
|
||||
void print(std::ostream &, error_id const &, char const * &) const override
|
||||
{
|
||||
}
|
||||
#endif
|
||||
@@ -253,7 +275,7 @@ namespace detail
|
||||
BOOST_LEAF_ASSERT(ex_);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
node * * last_;
|
||||
|
||||
@@ -261,6 +283,7 @@ namespace detail
|
||||
|
||||
dynamic_allocator() noexcept:
|
||||
capture_list(nullptr),
|
||||
preloaded_list_(nullptr),
|
||||
last_(&first_)
|
||||
{
|
||||
BOOST_LEAF_ASSERT(first_ == nullptr);
|
||||
@@ -268,24 +291,52 @@ namespace detail
|
||||
|
||||
dynamic_allocator( dynamic_allocator && other ) noexcept:
|
||||
capture_list(std::move(other)),
|
||||
preloaded_list_(nullptr),
|
||||
last_(other.last_ == &other.first_? &first_ : other.last_)
|
||||
{
|
||||
BOOST_LEAF_ASSERT(last_ != nullptr);
|
||||
BOOST_LEAF_ASSERT(*last_ == nullptr);
|
||||
BOOST_LEAF_ASSERT(other.first_ == nullptr);
|
||||
BOOST_LEAF_ASSERT(other.preloaded_list_ == nullptr);
|
||||
other.last_ = &other.first_;
|
||||
}
|
||||
|
||||
template <class E>
|
||||
typename std::decay<E>::type & dynamic_load(int err_id, E && e)
|
||||
preloaded_base * preloaded_list() const noexcept
|
||||
{
|
||||
return preloaded_list_;
|
||||
}
|
||||
|
||||
preloaded_base * link_preloaded_item(preloaded_base * pb) noexcept
|
||||
{
|
||||
BOOST_LEAF_ASSERT(pb != nullptr);
|
||||
preloaded_base * next = preloaded_list_;
|
||||
preloaded_list_ = pb;
|
||||
return next;
|
||||
}
|
||||
|
||||
void unlink_preloaded_item(preloaded_base * next) noexcept
|
||||
{
|
||||
preloaded_list_ = next;
|
||||
}
|
||||
|
||||
template <class E>
|
||||
slot<E> * alloc()
|
||||
{
|
||||
using T = typename std::decay<E>::type;
|
||||
BOOST_LEAF_ASSERT(last_ != nullptr);
|
||||
BOOST_LEAF_ASSERT(*last_ == nullptr);
|
||||
BOOST_LEAF_ASSERT(tls::read_ptr<slot<T>>() == nullptr);
|
||||
capturing_slot_node<T> * csn = new capturing_slot_node<T>(last_, err_id, std::forward<E>(e));
|
||||
BOOST_LEAF_ASSERT(tls::read_ptr<slot<E>>() == nullptr);
|
||||
capturing_slot_node<E> * csn = capturing_slot_node_allocator<E>::new_(last_);
|
||||
csn->activate();
|
||||
return csn->value(err_id);
|
||||
return csn;
|
||||
}
|
||||
|
||||
template <class E>
|
||||
slot<E> * reserve()
|
||||
{
|
||||
if( slot<E> * p = tls::read_ptr<slot<E>>() )
|
||||
return p;
|
||||
else
|
||||
return alloc<E>();
|
||||
}
|
||||
|
||||
void deactivate() const noexcept
|
||||
@@ -312,180 +363,165 @@ namespace detail
|
||||
|
||||
using capture_list::unload;
|
||||
using capture_list::print;
|
||||
}; // class dynamic_allocator
|
||||
|
||||
template <class E>
|
||||
struct capturing_slot_node_allocator
|
||||
{
|
||||
template <class... A>
|
||||
static dynamic_allocator::capturing_slot_node<E> * new_( A && ... a )
|
||||
{
|
||||
return new dynamic_allocator::capturing_slot_node<E>(std::forward<A>(a)...);
|
||||
}
|
||||
|
||||
static void delete_( dynamic_allocator::capturing_slot_node<E> * p ) noexcept
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
inline void slot<dynamic_allocator>::deactivate() const noexcept
|
||||
class slot<dynamic_allocator>
|
||||
{
|
||||
if( dynamic_allocator const * c = this->has_value_any_key() )
|
||||
c->deactivate();
|
||||
tls::write_ptr<slot<dynamic_allocator>>(prev_);
|
||||
}
|
||||
slot( slot const & ) = delete;
|
||||
slot & operator=( slot const & ) = delete;
|
||||
|
||||
template <>
|
||||
inline void slot<dynamic_allocator>::unload( int err_id ) noexcept(false)
|
||||
{
|
||||
BOOST_LEAF_ASSERT(err_id);
|
||||
if( dynamic_allocator * da1 = this->has_value_any_key() )
|
||||
da1->unload(err_id);
|
||||
}
|
||||
dynamic_allocator da_;
|
||||
slot * prev_;
|
||||
|
||||
template <class E>
|
||||
inline void dynamic_load_( int err_id, E && e )
|
||||
{
|
||||
if( slot<dynamic_allocator> * sl = tls::read_ptr<slot<dynamic_allocator>>() )
|
||||
public:
|
||||
|
||||
slot() noexcept:
|
||||
prev_(nullptr)
|
||||
{
|
||||
if( dynamic_allocator * c = sl->has_value_any_key() )
|
||||
c->dynamic_load(err_id, std::forward<E>(e));
|
||||
else
|
||||
sl->load(err_id).dynamic_load(err_id, std::forward<E>(e));
|
||||
tls::reserve_ptr<slot<dynamic_allocator>>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class E, class F>
|
||||
inline void dynamic_accumulate_( int err_id, F && f )
|
||||
{
|
||||
if( slot<dynamic_allocator> * sl = tls::read_ptr<slot<dynamic_allocator>>() )
|
||||
slot( slot && x ) noexcept:
|
||||
da_(std::move(x.da_)),
|
||||
prev_(nullptr)
|
||||
{
|
||||
if( dynamic_allocator * c = sl->has_value(err_id) )
|
||||
(void) std::forward<F>(f)(c->dynamic_load(err_id, E{}));
|
||||
else
|
||||
(void) std::forward<F>(f)(sl->load(err_id).dynamic_load(err_id, E{}));
|
||||
BOOST_LEAF_ASSERT(x.prev_ == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool OnError, class E>
|
||||
inline void dynamic_load( int err_id, E && e ) noexcept(OnError)
|
||||
{
|
||||
if( OnError )
|
||||
~slot() noexcept
|
||||
{
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
dynamic_load_(err_id, std::forward<E>(e));
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
BOOST_LEAF_ASSERT(tls::read_ptr<slot<dynamic_allocator>>() != this);
|
||||
}
|
||||
else
|
||||
dynamic_load_(err_id, std::forward<E>(e));
|
||||
}
|
||||
|
||||
template <bool OnError, class E, class F>
|
||||
inline void dynamic_load_accumulate( int err_id, F && f ) noexcept(OnError)
|
||||
{
|
||||
if( OnError )
|
||||
dynamic_allocator const & get() const noexcept
|
||||
{
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
dynamic_accumulate_<E>(err_id, std::forward<F>(f));
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
return da_;
|
||||
}
|
||||
else
|
||||
dynamic_accumulate_<E>(err_id, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
struct show_in_diagnostics<detail::dynamic_allocator>: std::false_type
|
||||
{
|
||||
};
|
||||
dynamic_allocator & get() noexcept
|
||||
{
|
||||
return da_;
|
||||
}
|
||||
|
||||
void activate() noexcept
|
||||
{
|
||||
prev_ = tls::read_ptr<slot<dynamic_allocator>>();
|
||||
tls::write_ptr<slot<dynamic_allocator>>(this);
|
||||
}
|
||||
|
||||
void deactivate() const noexcept
|
||||
{
|
||||
da_.deactivate();
|
||||
tls::write_ptr<slot<dynamic_allocator>>(prev_);
|
||||
}
|
||||
|
||||
void unload( int err_id )
|
||||
{
|
||||
BOOST_LEAF_ASSERT(err_id);
|
||||
da_.unload(err_id);
|
||||
}
|
||||
|
||||
#if BOOST_LEAF_CFG_DIAGNOSTICS
|
||||
template <class CharT, class Traits, class ErrorID>
|
||||
void print(std::basic_ostream<CharT, Traits> &, ErrorID, char const * &) const
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}; // slot specialization for dynamic_allocator
|
||||
} // namespace detail
|
||||
|
||||
#endif // #if BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace detail
|
||||
{
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
inline dynamic_allocator * get_dynamic_allocator() noexcept
|
||||
{
|
||||
if( slot<dynamic_allocator> * sl = tls::read_ptr<slot<dynamic_allocator>>() )
|
||||
return &sl->get();
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class E>
|
||||
inline slot<E> * get_slot() noexcept(!BOOST_LEAF_CFG_CAPTURE)
|
||||
{
|
||||
static_assert(!std::is_pointer<E>::value, "Error objects of pointer types are not allowed");
|
||||
static_assert(!std::is_same<E, error_id>::value, "Error objects of type error_id are not allowed");
|
||||
if( slot<E> * p = tls::read_ptr<slot<E>>() )
|
||||
return p;
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
if( dynamic_allocator * da = get_dynamic_allocator() )
|
||||
return da->alloc<E>();
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class E>
|
||||
inline void slot<E>::unload( int err_id ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
|
||||
{
|
||||
BOOST_LEAF_ASSERT(err_id);
|
||||
if( this->key() != err_id )
|
||||
return;
|
||||
if( impl * p = tls::read_ptr<slot<E>>() )
|
||||
{
|
||||
if( impl * p = get_slot<E>() )
|
||||
if( !p->has_value(err_id) )
|
||||
*p = std::move(*this);
|
||||
}
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
else
|
||||
dynamic_load<false>(err_id, std::move(*this).value(err_id));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <bool OnError, class E>
|
||||
BOOST_LEAF_CONSTEXPR inline int load_slot( int err_id, E && e ) noexcept(OnError)
|
||||
template <class E>
|
||||
BOOST_LEAF_CONSTEXPR inline int load_slot( int err_id, E && e ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
|
||||
{
|
||||
using T = typename std::decay<E>::type;
|
||||
static_assert(!std::is_pointer<T>::value, "Error objects of pointer types are not allowed");
|
||||
static_assert(!std::is_same<T, error_id>::value, "Error objects of type error_id are not allowed");
|
||||
using E_decayed = typename std::decay<E>::type;
|
||||
BOOST_LEAF_ASSERT((err_id&3) == 1);
|
||||
if( slot<T> * p = tls::read_ptr<slot<T>>() )
|
||||
{
|
||||
if( !OnError || !p->has_value(err_id) )
|
||||
(void) p->load(err_id, std::forward<E>(e));
|
||||
}
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
else
|
||||
dynamic_load<OnError>(err_id, std::forward<E>(e));
|
||||
#endif
|
||||
if( slot<E_decayed> * p = get_slot<E_decayed>() )
|
||||
(void) p->load(err_id, std::forward<E>(e));
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <bool OnError, class F>
|
||||
BOOST_LEAF_CONSTEXPR inline int load_slot_deferred( int err_id, F && f ) noexcept(OnError)
|
||||
template <class F>
|
||||
BOOST_LEAF_CONSTEXPR inline int load_slot_deferred( int err_id, F && f )
|
||||
{
|
||||
using E = typename function_traits<F>::return_type;
|
||||
using T = typename std::decay<E>::type;
|
||||
static_assert(!std::is_pointer<T>::value, "Error objects of pointer types are not allowed");
|
||||
static_assert(!std::is_same<T, error_id>::value, "Error objects of type error_id are not allowed");
|
||||
using E_decayed = typename std::decay<E>::type;
|
||||
BOOST_LEAF_ASSERT((err_id&3) == 1);
|
||||
if( slot<T> * p = tls::read_ptr<slot<T>>() )
|
||||
{
|
||||
if( !OnError || !p->has_value(err_id) )
|
||||
(void) p->load(err_id, std::forward<F>(f)());
|
||||
}
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
else
|
||||
dynamic_load<OnError>(err_id, std::forward<F>(f)());
|
||||
#endif
|
||||
if( slot<E_decayed> * p = get_slot<E_decayed>() )
|
||||
(void) p->load(err_id, std::forward<F>(f)());
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <bool OnError, class F>
|
||||
BOOST_LEAF_CONSTEXPR inline int load_slot_accumulate( int err_id, F && f ) noexcept(OnError)
|
||||
template <class F>
|
||||
BOOST_LEAF_CONSTEXPR inline int load_slot_accumulate( int err_id, F && f )
|
||||
{
|
||||
static_assert(function_traits<F>::arity == 1, "Lambdas passed to accumulate must take a single e-type argument by reference");
|
||||
using E = typename std::decay<fn_arg_type<F,0>>::type;
|
||||
using T = typename std::decay<E>::type;
|
||||
static_assert(!std::is_pointer<T>::value, "Error objects of pointer types are not allowed");
|
||||
using E = fn_arg_type<F,0>;
|
||||
using E_decayed = typename std::decay<E>::type;
|
||||
BOOST_LEAF_ASSERT((err_id&3) == 1);
|
||||
if( auto sl = tls::read_ptr<slot<E>>() )
|
||||
{
|
||||
if( auto v = sl->has_value(err_id) )
|
||||
if( slot<E_decayed> * p = get_slot<E_decayed>() )
|
||||
if( E_decayed * v = p->has_value(err_id) )
|
||||
(void) std::forward<F>(f)(*v);
|
||||
else
|
||||
(void) std::forward<F>(f)(sl->load(err_id,E()));
|
||||
}
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
else
|
||||
dynamic_load_accumulate<OnError, E>(err_id, std::forward<F>(f));
|
||||
#endif
|
||||
(void) std::forward<F>(f)(p->load(err_id, E_decayed()));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -500,27 +536,27 @@ namespace detail
|
||||
template <class E>
|
||||
struct load_item<E, -1>
|
||||
{
|
||||
BOOST_LEAF_CONSTEXPR static int load_( int err_id, E && e ) noexcept
|
||||
BOOST_LEAF_CONSTEXPR static int load_( int err_id, E && e )
|
||||
{
|
||||
return load_slot<false>(err_id, std::forward<E>(e));
|
||||
return load_slot(err_id, std::forward<E>(e));
|
||||
}
|
||||
};
|
||||
|
||||
template <class F>
|
||||
struct load_item<F, 0>
|
||||
{
|
||||
BOOST_LEAF_CONSTEXPR static int load_( int err_id, F && f ) noexcept
|
||||
BOOST_LEAF_CONSTEXPR static int load_( int err_id, F && f )
|
||||
{
|
||||
return load_slot_deferred<false>(err_id, std::forward<F>(f));
|
||||
return load_slot_deferred(err_id, std::forward<F>(f));
|
||||
}
|
||||
};
|
||||
|
||||
template <class F>
|
||||
struct load_item<F, 1>
|
||||
{
|
||||
BOOST_LEAF_CONSTEXPR static int load_( int err_id, F && f ) noexcept
|
||||
BOOST_LEAF_CONSTEXPR static int load_( int err_id, F && f )
|
||||
{
|
||||
return load_slot_accumulate<false>(err_id, std::forward<F>(f));
|
||||
return load_slot_accumulate(err_id, std::forward<F>(f));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -529,38 +565,63 @@ namespace detail
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE tls_tag_id_factory_current_id;
|
||||
|
||||
template <class=void>
|
||||
struct BOOST_LEAF_SYMBOL_VISIBLE id_factory
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
class preloaded_base
|
||||
{
|
||||
static atomic_unsigned_int counter;
|
||||
protected:
|
||||
|
||||
BOOST_LEAF_CONSTEXPR static unsigned generate_next_id() noexcept
|
||||
preloaded_base() noexcept:
|
||||
next_(
|
||||
[]( preloaded_base * this_ ) -> preloaded_base *
|
||||
{
|
||||
if( dynamic_allocator * da = get_dynamic_allocator() )
|
||||
return da->link_preloaded_item(this_);
|
||||
return nullptr;
|
||||
}(this))
|
||||
{
|
||||
auto id = (counter+=4);
|
||||
BOOST_LEAF_ASSERT((id&3) == 1);
|
||||
return id;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
atomic_unsigned_int id_factory<T>::counter(1);
|
||||
~preloaded_base() noexcept
|
||||
{
|
||||
if( dynamic_allocator * da = get_dynamic_allocator() )
|
||||
da->unlink_preloaded_item(next_);
|
||||
else
|
||||
BOOST_LEAF_ASSERT(next_ == nullptr);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
preloaded_base * const next_;
|
||||
|
||||
virtual void reserve( dynamic_allocator & ) const = 0;
|
||||
};
|
||||
#endif // #if BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
inline int current_id() noexcept
|
||||
{
|
||||
unsigned id = tls::read_uint<tls_tag_id_factory_current_id>();
|
||||
unsigned id = tls::read_current_error_id();
|
||||
BOOST_LEAF_ASSERT(id == 0 || (id&3) == 1);
|
||||
return int(id);
|
||||
}
|
||||
|
||||
inline int new_id() noexcept
|
||||
{
|
||||
unsigned id = id_factory<>::generate_next_id();
|
||||
tls::write_uint<tls_tag_id_factory_current_id>(id);
|
||||
unsigned id = tls::generate_next_error_id();
|
||||
tls::write_current_error_id(id);
|
||||
return int(id);
|
||||
}
|
||||
|
||||
inline int start_new_error()
|
||||
{
|
||||
int id = new_id();
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
if( dynamic_allocator * da = get_dynamic_allocator() )
|
||||
for( preloaded_base const * e = da->preloaded_list(); e; e = e->next_ )
|
||||
e->reserve(*da);
|
||||
#endif
|
||||
return id;
|
||||
}
|
||||
|
||||
struct inject_loc
|
||||
{
|
||||
char const * file;
|
||||
@@ -568,26 +629,27 @@ namespace detail
|
||||
char const * fn;
|
||||
|
||||
template <class T>
|
||||
friend T operator+( inject_loc loc, T && x ) noexcept
|
||||
friend T operator+( inject_loc loc, T && x ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
|
||||
{
|
||||
x.load_source_location_(loc.file, loc.line, loc.fn);
|
||||
return std::move(x);
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class leaf_error_category final: public std::error_category
|
||||
class leaf_error_category final:
|
||||
public std::error_category
|
||||
{
|
||||
bool equivalent( int, std::error_condition const & ) const noexcept final override { return false; }
|
||||
bool equivalent( std::error_code const &, int ) const noexcept final override { return false; }
|
||||
char const * name() const noexcept final override { return "LEAF error"; }
|
||||
std::string message( int ) const final override { return name(); }
|
||||
bool equivalent( int, std::error_condition const & ) const noexcept override { return false; }
|
||||
bool equivalent( std::error_code const &, int ) const noexcept override { return false; }
|
||||
char const * name() const noexcept override { return "LEAF error"; }
|
||||
std::string message( int ) const override { return name(); }
|
||||
public:
|
||||
~leaf_error_category() noexcept final override { }
|
||||
~leaf_error_category() noexcept override { }
|
||||
};
|
||||
|
||||
template <class=void>
|
||||
@@ -599,7 +661,7 @@ namespace detail
|
||||
template <class T>
|
||||
leaf_error_category get_leaf_error_category<T>::cat;
|
||||
|
||||
inline int import_error_code( std::error_code const & ec ) noexcept
|
||||
inline int import_error_code( std::error_code const & ec ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
|
||||
{
|
||||
if( int err_id = ec.value() )
|
||||
{
|
||||
@@ -611,15 +673,15 @@ namespace detail
|
||||
}
|
||||
else
|
||||
{
|
||||
err_id = new_id();
|
||||
(void) load_slot<false>(err_id, ec);
|
||||
err_id = start_new_error();
|
||||
(void) load_slot(err_id, ec);
|
||||
return (err_id&~3)|1;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
inline bool is_error_id( std::error_code const & ec ) noexcept
|
||||
{
|
||||
@@ -628,7 +690,7 @@ inline bool is_error_id( std::error_code const & ec ) noexcept
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -637,7 +699,7 @@ namespace detail
|
||||
BOOST_LEAF_CONSTEXPR error_id make_error_id(int) noexcept;
|
||||
}
|
||||
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE error_id
|
||||
class error_id
|
||||
{
|
||||
friend error_id BOOST_LEAF_CONSTEXPR detail::make_error_id(int) noexcept;
|
||||
|
||||
@@ -657,14 +719,14 @@ public:
|
||||
}
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
explicit error_id( std::error_code const & ec ) noexcept:
|
||||
explicit error_id( std::error_code const & ec ) noexcept(!BOOST_LEAF_CFG_CAPTURE):
|
||||
value_(detail::import_error_code(std::error_code(ec)))
|
||||
{
|
||||
BOOST_LEAF_ASSERT(!value_ || ((value_&3) == 1));
|
||||
}
|
||||
|
||||
template <class Enum>
|
||||
error_id( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type = 0 ) noexcept:
|
||||
error_id( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type = 0 ) noexcept(!BOOST_LEAF_CFG_CAPTURE):
|
||||
value_(detail::import_error_code(e))
|
||||
{
|
||||
}
|
||||
@@ -674,7 +736,7 @@ public:
|
||||
{
|
||||
return std::error_code(value_, detail::get_leaf_error_category<>::cat);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
BOOST_LEAF_CONSTEXPR error_id load() const noexcept
|
||||
{
|
||||
@@ -682,7 +744,7 @@ public:
|
||||
}
|
||||
|
||||
template <class Item>
|
||||
BOOST_LEAF_CONSTEXPR error_id load(Item && item) const noexcept
|
||||
BOOST_LEAF_CONSTEXPR error_id load(Item && item) const
|
||||
{
|
||||
if (int err_id = value())
|
||||
{
|
||||
@@ -693,7 +755,7 @@ public:
|
||||
}
|
||||
|
||||
template <class... Item>
|
||||
BOOST_LEAF_CONSTEXPR error_id load( Item && ... item ) const noexcept
|
||||
BOOST_LEAF_CONSTEXPR error_id load( Item && ... item ) const
|
||||
{
|
||||
if( int err_id = value() )
|
||||
{
|
||||
@@ -735,7 +797,7 @@ public:
|
||||
return os << (x.value_ / 4);
|
||||
}
|
||||
|
||||
BOOST_LEAF_CONSTEXPR void load_source_location_( char const * file, int line, char const * function ) const noexcept
|
||||
BOOST_LEAF_CONSTEXPR void load_source_location_( char const * file, int line, char const * function ) const noexcept(!BOOST_LEAF_CFG_CAPTURE)
|
||||
{
|
||||
BOOST_LEAF_ASSERT(file&&*file);
|
||||
BOOST_LEAF_ASSERT(line>0);
|
||||
@@ -743,7 +805,7 @@ public:
|
||||
BOOST_LEAF_ASSERT(value_);
|
||||
(void) load(e_source_location {file,line,function});
|
||||
}
|
||||
};
|
||||
}; // class error_id
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@@ -754,15 +816,15 @@ namespace detail
|
||||
}
|
||||
}
|
||||
|
||||
inline error_id new_error() noexcept
|
||||
inline error_id new_error()
|
||||
{
|
||||
return detail::make_error_id(detail::new_id());
|
||||
return detail::make_error_id(detail::start_new_error());
|
||||
}
|
||||
|
||||
template <class... Item>
|
||||
inline error_id new_error( Item && ... item ) noexcept
|
||||
inline error_id new_error( Item && ... item )
|
||||
{
|
||||
return detail::make_error_id(detail::new_id()).load(std::forward<Item>(item)...);
|
||||
return detail::make_error_id(detail::start_new_error()).load(std::forward<Item>(item)...);
|
||||
}
|
||||
|
||||
inline error_id current_error() noexcept
|
||||
@@ -782,6 +844,6 @@ struct is_result_type<R const>: is_result_type<R>
|
||||
{
|
||||
};
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // BOOST_LEAF_ERROR_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_ERROR_HPP_INCLUDED
|
||||
|
||||
@@ -1,52 +1,14 @@
|
||||
#ifndef BOOST_LEAF_EXCEPTION_HPP_INCLUDED
|
||||
#define BOOST_LEAF_EXCEPTION_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/leaf/config.hpp>
|
||||
#include <boost/leaf/error.hpp>
|
||||
#include <exception>
|
||||
#include <typeinfo>
|
||||
|
||||
#ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
namespace boost
|
||||
{
|
||||
[[noreturn]] void throw_exception( std::exception const & ); // user defined
|
||||
}
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class T>
|
||||
[[noreturn]] void throw_exception_impl( T && e )
|
||||
{
|
||||
::boost::throw_exception(std::move(e));
|
||||
}
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#else
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class T>
|
||||
[[noreturn]] void throw_exception_impl( T && e )
|
||||
{
|
||||
throw std::move(e);
|
||||
}
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
#define BOOST_LEAF_THROW_EXCEPTION ::boost::leaf::detail::throw_with_loc{__FILE__,__LINE__,__FUNCTION__}+::boost::leaf::detail::make_exception
|
||||
@@ -65,7 +27,7 @@ namespace detail
|
||||
[[noreturn]] friend void operator+( throw_with_loc loc, Ex && ex )
|
||||
{
|
||||
ex.load_source_location_(loc.file, loc.line, loc.fn);
|
||||
::boost::leaf::detail::throw_exception_impl(std::move(ex));
|
||||
::boost::leaf::throw_exception_(std::move(ex));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -77,7 +39,7 @@ namespace detail
|
||||
inline void enforce_std_exception( std::exception const & ) noexcept { }
|
||||
|
||||
template <class Ex>
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE exception:
|
||||
class exception final:
|
||||
public Ex,
|
||||
public exception_base,
|
||||
public error_id
|
||||
@@ -86,17 +48,17 @@ namespace detail
|
||||
|
||||
bool is_current_exception() const noexcept
|
||||
{
|
||||
return tls::read_uint<detail::tls_tag_id_factory_current_id>() == unsigned(error_id::value());
|
||||
return tls::read_current_error_id() == unsigned(error_id::value());
|
||||
}
|
||||
|
||||
error_id get_error_id() const noexcept final override
|
||||
error_id get_error_id() const noexcept override
|
||||
{
|
||||
clear_current_error_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if BOOST_LEAF_CFG_DIAGNOSTICS && !defined(BOOST_LEAF_NO_EXCEPTIONS)
|
||||
void print_type_name(std::ostream & os) const final override
|
||||
void print_type_name(std::ostream & os) const override
|
||||
{
|
||||
detail::demangle_and_print(os, typeid(Ex).name());
|
||||
}
|
||||
@@ -148,9 +110,9 @@ namespace detail
|
||||
~exception() noexcept
|
||||
{
|
||||
if( clear_current_error_ && is_current_exception() )
|
||||
tls::write_uint<detail::tls_tag_id_factory_current_id>(0);
|
||||
tls::write_current_error_id(0);
|
||||
}
|
||||
};
|
||||
}; // template exception
|
||||
|
||||
template <class... T>
|
||||
struct at_least_one_derives_from_std_exception;
|
||||
@@ -167,7 +129,7 @@ namespace detail
|
||||
template <class Ex, class... E>
|
||||
inline
|
||||
typename std::enable_if<std::is_base_of<std::exception,typename std::remove_reference<Ex>::type>::value, exception<typename std::remove_reference<Ex>::type>>::type
|
||||
make_exception( error_id err, Ex && ex, E && ... e ) noexcept
|
||||
make_exception( error_id err, Ex && ex, E && ... e ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
|
||||
{
|
||||
static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
|
||||
return exception<typename std::remove_reference<Ex>::type>( err.load(std::forward<E>(e)...), std::forward<Ex>(ex) );
|
||||
@@ -176,7 +138,7 @@ namespace detail
|
||||
template <class E1, class... E>
|
||||
inline
|
||||
typename std::enable_if<!std::is_base_of<std::exception,typename std::remove_reference<E1>::type>::value, exception<std::exception>>::type
|
||||
make_exception( error_id err, E1 && car, E && ... cdr ) noexcept
|
||||
make_exception( error_id err, E1 && car, E && ... cdr ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
|
||||
{
|
||||
static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
|
||||
return exception<std::exception>( err.load(std::forward<E1>(car), std::forward<E>(cdr)...) );
|
||||
@@ -190,7 +152,7 @@ namespace detail
|
||||
template <class Ex, class... E>
|
||||
inline
|
||||
typename std::enable_if<std::is_base_of<std::exception,typename std::remove_reference<Ex>::type>::value, exception<typename std::remove_reference<Ex>::type>>::type
|
||||
make_exception( Ex && ex, E && ... e ) noexcept
|
||||
make_exception( Ex && ex, E && ... e ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
|
||||
{
|
||||
static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
|
||||
return exception<typename std::remove_reference<Ex>::type>( new_error().load(std::forward<E>(e)...), std::forward<Ex>(ex) );
|
||||
@@ -199,7 +161,7 @@ namespace detail
|
||||
template <class E1, class... E>
|
||||
inline
|
||||
typename std::enable_if<!std::is_base_of<std::exception,typename std::remove_reference<E1>::type>::value, exception<std::exception>>::type
|
||||
make_exception( E1 && car, E && ... cdr ) noexcept
|
||||
make_exception( E1 && car, E && ... cdr ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
|
||||
{
|
||||
static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
|
||||
return exception<std::exception>( new_error().load(std::forward<E1>(car), std::forward<E>(cdr)...) );
|
||||
@@ -209,7 +171,7 @@ namespace detail
|
||||
{
|
||||
return exception<std::exception>(leaf::new_error());
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <class... E>
|
||||
[[noreturn]] void throw_exception( E && ... e )
|
||||
@@ -217,17 +179,14 @@ template <class... E>
|
||||
// Warning: setting a breakpoint here will not intercept exceptions thrown
|
||||
// via BOOST_LEAF_THROW_EXCEPTION or originating in the few other throw
|
||||
// points elsewhere in LEAF. To intercept all of those exceptions as well,
|
||||
// set a breakpoint inside boost::leaf::detail::throw_exception_impl.
|
||||
detail::throw_exception_impl(detail::make_exception(std::forward<E>(e)...));
|
||||
// set a breakpoint inside boost::leaf::throw_exception_.
|
||||
throw_exception_(detail::make_exception(std::forward<E>(e)...));
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
template <class T>
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE result;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline error_id catch_exceptions_helper( std::exception const &, leaf_detail_mp11::mp_list<> )
|
||||
@@ -258,12 +217,12 @@ namespace detail
|
||||
|
||||
template <class T>
|
||||
using deduce_exception_to_result_return_type = typename deduce_exception_to_result_return_type_impl<T>::type;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <class... Ex, class F>
|
||||
inline
|
||||
detail::deduce_exception_to_result_return_type<detail::fn_return_type<F>>
|
||||
exception_to_result( F && f ) noexcept
|
||||
exception_to_result( F && f ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -279,8 +238,8 @@ exception_to_result( F && f ) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // BOOST_LEAF_EXCEPTION_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_EXCEPTION_HPP_INCLUDED
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED
|
||||
#define BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class T>
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE result;
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
@@ -30,11 +27,11 @@ namespace detail
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE error_info
|
||||
class error_info
|
||||
{
|
||||
error_info & operator=( error_info const & ) = delete;
|
||||
|
||||
@@ -97,7 +94,7 @@ public:
|
||||
detail::demangle_and_print(os, typeid(*ex_).name());
|
||||
os << ": \"" << ex_->what() << '"';
|
||||
}
|
||||
#endif
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
}
|
||||
|
||||
template <class CharT, class Traits>
|
||||
@@ -106,7 +103,7 @@ public:
|
||||
x.print_error_info(os);
|
||||
return os << '\n';
|
||||
}
|
||||
};
|
||||
}; // class error_info
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@@ -202,7 +199,7 @@ namespace detail
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
template <class E>
|
||||
struct peek_exception<E, true>
|
||||
@@ -222,7 +219,7 @@ namespace detail
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
template <class E, bool = does_not_participate_in_context_deduction<E>::value>
|
||||
struct peek_tuple;
|
||||
@@ -292,7 +289,7 @@ namespace detail
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -347,7 +344,7 @@ namespace detail
|
||||
return handler_argument_traits<Car>::check(tup, ei) && check_arguments<Tup, Cdr...>::check(tup, ei);
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -472,7 +469,7 @@ namespace detail
|
||||
std::forward<Car>(car),
|
||||
std::forward<Cdr>(cdr)...);
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -570,7 +567,7 @@ try_catch( TryBlock && try_block, H && ... ) noexcept
|
||||
return std::forward<TryBlock>(try_block)();
|
||||
}
|
||||
|
||||
#else
|
||||
#else // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@@ -610,7 +607,7 @@ namespace detail
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <class TryBlock, class... H>
|
||||
inline
|
||||
@@ -701,7 +698,7 @@ try_catch( TryBlock && try_block, H && ... h )
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #else (#ifdef BOOST_LEAF_NO_EXCEPTIONS)
|
||||
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
@@ -716,7 +713,7 @@ namespace detail
|
||||
inline
|
||||
static
|
||||
leaf_result
|
||||
try_capture_all_( TryBlock && try_block ) noexcept
|
||||
try_capture_all_( TryBlock && try_block )
|
||||
{
|
||||
detail::slot<detail::dynamic_allocator> sl;
|
||||
sl.activate();
|
||||
@@ -733,7 +730,7 @@ namespace detail
|
||||
{
|
||||
sl.deactivate();
|
||||
int const err_id = error_id(r.error()).value();
|
||||
return leaf_result(sl.value_or_default(err_id).template extract_capture_list<leaf_result>(err_id));
|
||||
return leaf_result(sl.get().template extract_capture_list<leaf_result>(err_id));
|
||||
}
|
||||
}
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
@@ -741,15 +738,15 @@ namespace detail
|
||||
{
|
||||
sl.deactivate();
|
||||
int err_id = unpack_error_id(ex).value();
|
||||
return sl.value_or_default(err_id).template extract_capture_list<leaf_result>(err_id);
|
||||
return sl.get().template extract_capture_list<leaf_result>(err_id);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
sl.deactivate();
|
||||
int err_id = current_error().value();
|
||||
return sl.value_or_default(err_id).template extract_capture_list<leaf_result>(err_id);
|
||||
return sl.get().template extract_capture_list<leaf_result>(err_id);
|
||||
}
|
||||
#endif
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
}
|
||||
};
|
||||
|
||||
@@ -777,7 +774,7 @@ namespace detail
|
||||
inline
|
||||
static
|
||||
leaf_result
|
||||
try_capture_all_( TryBlock && try_block ) noexcept
|
||||
try_capture_all_( TryBlock && try_block )
|
||||
{
|
||||
detail::slot<detail::dynamic_allocator> sl;
|
||||
sl.activate();
|
||||
@@ -793,18 +790,18 @@ namespace detail
|
||||
{
|
||||
sl.deactivate();
|
||||
int err_id = unpack_error_id(ex).value();
|
||||
return sl.value_or_default(err_id).template extract_capture_list<leaf_result>(err_id);
|
||||
return sl.get().template extract_capture_list<leaf_result>(err_id);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
sl.deactivate();
|
||||
int err_id = current_error().value();
|
||||
return sl.value_or_default(err_id).template extract_capture_list<leaf_result>(err_id);
|
||||
return sl.get().template extract_capture_list<leaf_result>(err_id);
|
||||
}
|
||||
#endif
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <class TryBlock>
|
||||
inline
|
||||
@@ -813,9 +810,10 @@ try_capture_all( TryBlock && try_block ) noexcept
|
||||
{
|
||||
return detail::try_capture_all_dispatch<decltype(std::declval<TryBlock>()())>::try_capture_all_(std::forward<TryBlock>(try_block));
|
||||
}
|
||||
#endif
|
||||
|
||||
} }
|
||||
#endif // #if BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
} } // namespace boost::leaf
|
||||
|
||||
// Boost Exception Integration
|
||||
|
||||
@@ -875,8 +873,8 @@ namespace detail
|
||||
template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> const *>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { };
|
||||
template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> &>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { };
|
||||
template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> *>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { };
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_LEAF_ON_ERROR_HPP_INCLUDED
|
||||
#define BOOST_LEAF_ON_ERROR_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
# else
|
||||
if( std::uncaught_exception() )
|
||||
# endif
|
||||
return detail::new_id();
|
||||
return detail::start_new_error();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
{
|
||||
return detail::make_error_id(get_id());
|
||||
}
|
||||
};
|
||||
}; // class error_monitor
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -79,19 +79,31 @@ namespace detail
|
||||
tuple_for_each_preload<I-1,Tup>::trigger(tup,err_id);
|
||||
std::get<I-1>(tup).trigger(err_id);
|
||||
}
|
||||
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
static void reserve( Tup const & tup, dynamic_allocator & da )
|
||||
{
|
||||
tuple_for_each_preload<I-1,Tup>::reserve(tup,da);
|
||||
std::get<I-1>(tup).reserve(da);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class Tup>
|
||||
struct tuple_for_each_preload<0, Tup>
|
||||
{
|
||||
BOOST_LEAF_CONSTEXPR static void trigger( Tup const &, int ) noexcept { }
|
||||
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
static void reserve( Tup const &, dynamic_allocator & ) { }
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class E>
|
||||
class preloaded_item
|
||||
{
|
||||
using decay_E = typename std::decay<E>::type;
|
||||
decay_E e_;
|
||||
using E_decayed = typename std::decay<E>::type;
|
||||
E_decayed e_;
|
||||
|
||||
public:
|
||||
|
||||
@@ -102,26 +114,57 @@ namespace detail
|
||||
|
||||
BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept
|
||||
{
|
||||
(void) load_slot<true>(err_id, std::move(e_));
|
||||
if( slot<E_decayed> * p = tls::read_ptr<slot<E_decayed>>() )
|
||||
if( !p->has_value(err_id) )
|
||||
(void) p->load(err_id, std::move(e_));
|
||||
}
|
||||
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
void reserve( dynamic_allocator & da ) const
|
||||
{
|
||||
da.reserve<E_decayed>();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class F, class ReturnType = typename function_traits<F>::return_type>
|
||||
class deferred_item
|
||||
{
|
||||
using E_decayed = typename std::decay<ReturnType>::type;
|
||||
F f_;
|
||||
|
||||
public:
|
||||
|
||||
BOOST_LEAF_CONSTEXPR deferred_item( F && f ) noexcept:
|
||||
BOOST_LEAF_CONSTEXPR deferred_item( F && f ):
|
||||
f_(std::forward<F>(f))
|
||||
{
|
||||
}
|
||||
|
||||
BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept
|
||||
void trigger( int err_id ) noexcept
|
||||
{
|
||||
(void) load_slot_deferred<true>(err_id, f_);
|
||||
if( slot<E_decayed> * p = tls::read_ptr<slot<E_decayed>>() )
|
||||
if( !p->has_value(err_id) )
|
||||
{
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
(void) p->load(err_id, f_());
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
void reserve( dynamic_allocator & da ) const
|
||||
{
|
||||
da.reserve<E_decayed>();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class F>
|
||||
@@ -136,10 +179,26 @@ namespace detail
|
||||
{
|
||||
}
|
||||
|
||||
BOOST_LEAF_CONSTEXPR void trigger( int ) noexcept
|
||||
void trigger( int ) noexcept
|
||||
{
|
||||
f_();
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
f_();
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
void reserve( dynamic_allocator & ) const
|
||||
{
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class F, class A0 = fn_arg_type<F,0>, int arity = function_traits<F>::arity>
|
||||
@@ -148,50 +207,89 @@ namespace detail
|
||||
template <class F, class A0>
|
||||
class accumulating_item<F, A0 &, 1>
|
||||
{
|
||||
using E_decayed = typename std::decay<A0>::type;
|
||||
F f_;
|
||||
|
||||
public:
|
||||
|
||||
BOOST_LEAF_CONSTEXPR accumulating_item( F && f ) noexcept:
|
||||
BOOST_LEAF_CONSTEXPR accumulating_item( F && f ):
|
||||
f_(std::forward<F>(f))
|
||||
{
|
||||
}
|
||||
|
||||
BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept
|
||||
void trigger( int err_id ) noexcept
|
||||
{
|
||||
load_slot_accumulate<true>(err_id, std::move(f_));
|
||||
if( slot<E_decayed> * p = tls::read_ptr<slot<E_decayed>>() )
|
||||
{
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
if( E_decayed * v = p->has_value(err_id) )
|
||||
(void) std::move(f_)(*v);
|
||||
else
|
||||
(void) std::move(f_)(p->load(err_id, E_decayed()));
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
void reserve( dynamic_allocator & da ) const
|
||||
{
|
||||
da.reserve<E_decayed>();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class... Item>
|
||||
class preloaded
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
: preloaded_base
|
||||
#endif
|
||||
{
|
||||
preloaded( preloaded const & ) = delete;
|
||||
preloaded & operator=( preloaded const & ) = delete;
|
||||
|
||||
std::tuple<Item...> p_;
|
||||
bool moved_;
|
||||
error_monitor id_;
|
||||
#if __cplusplus < 201703L
|
||||
bool moved_ = false;
|
||||
#endif
|
||||
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
void reserve( dynamic_allocator & da ) const override
|
||||
{
|
||||
tuple_for_each_preload<sizeof...(Item),decltype(p_)>::reserve(p_,da);
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
BOOST_LEAF_CONSTEXPR explicit preloaded( Item && ... i ):
|
||||
p_(std::forward<Item>(i)...),
|
||||
moved_(false)
|
||||
p_(std::forward<Item>(i)...)
|
||||
{
|
||||
}
|
||||
|
||||
#if __cplusplus < 201703L
|
||||
BOOST_LEAF_CONSTEXPR preloaded( preloaded && x ) noexcept:
|
||||
p_(std::move(x.p_)),
|
||||
moved_(false),
|
||||
id_(std::move(x.id_))
|
||||
{
|
||||
x.moved_ = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
~preloaded() noexcept
|
||||
{
|
||||
#if __cplusplus < 201703L
|
||||
if( moved_ )
|
||||
return;
|
||||
#endif
|
||||
if( auto id = id_.check_id() )
|
||||
tuple_for_each_preload<sizeof...(Item),decltype(p_)>::trigger(p_,id);
|
||||
}
|
||||
@@ -217,7 +315,7 @@ namespace detail
|
||||
{
|
||||
using type = accumulating_item<F>;
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <class... Item>
|
||||
BOOST_LEAF_ATTRIBUTE_NODISCARD BOOST_LEAF_CONSTEXPR inline
|
||||
@@ -227,6 +325,6 @@ on_error( Item && ... i )
|
||||
return detail::preloaded<typename detail::deduce_item_type<Item>::type...>(std::forward<Item>(i)...);
|
||||
}
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // BOOST_LEAF_ON_ERROR_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_ON_ERROR_HPP_INCLUDED
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_LEAF_PRED_HPP_INCLUDED
|
||||
#define BOOST_LEAF_PRED_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace detail
|
||||
BOOST_LEAF_ASSERT(P != nullptr);
|
||||
return P(e);
|
||||
}
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
|
||||
template <class MatchType, class V>
|
||||
BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, V v )
|
||||
@@ -46,7 +46,7 @@ namespace detail
|
||||
{
|
||||
return cmp_value_pack(e, car) || cmp_value_pack(e, cdr...);
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -71,7 +71,7 @@ BOOST_LEAF_CONSTEXPR inline bool category( std::error_code const & ec )
|
||||
return &ec.category() == &std::error_code(ErrorCodeEnum{}).category();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace detail
|
||||
{
|
||||
static_assert(sizeof(Enum) == 0, "leaf::condition<E, Enum> should be used with leaf::match_value<>, not with leaf::match<>");
|
||||
};
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
}
|
||||
|
||||
template <class E, BOOST_LEAF_MATCH_ARGS(match_enum_type<E>, V1, V)>
|
||||
@@ -123,7 +123,7 @@ struct match<condition<Enum, Enum>, V1, V...>
|
||||
return detail::cmp_value_pack(e, V1, V...);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
template <class E, BOOST_LEAF_MATCH_ARGS(match_enum_type<E>, V1, V)>
|
||||
struct is_predicate<match<E, V1, V...>>: std::true_type
|
||||
@@ -152,7 +152,7 @@ namespace detail
|
||||
{
|
||||
static_assert(sizeof(Enum) == 0, "leaf::condition<Enum> should be used with leaf::match<>, not with leaf::match_value<>");
|
||||
};
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
}
|
||||
|
||||
template <class E, BOOST_LEAF_MATCH_ARGS(match_value_enum_type<E>, V1, V)>
|
||||
@@ -179,7 +179,7 @@ struct match_value<condition<E, Enum>, V1, V...>
|
||||
return detail::cmp_value_pack(e.value, V1, V...);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
template <class E, BOOST_LEAF_MATCH_ARGS(match_value_enum_type<E>, V1, V)>
|
||||
struct is_predicate<match_value<E, V1, V...>>: std::true_type
|
||||
@@ -208,7 +208,7 @@ template <auto P, auto V1, auto... V>
|
||||
struct is_predicate<match_member<P, V1, V...>>: std::true_type
|
||||
{
|
||||
};
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -289,8 +289,8 @@ struct is_predicate<catch_<Ex...>>: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // BOOST_LEAF_PRED_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_PRED_HPP_INCLUDED
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_LEAF_RESULT_HPP_INCLUDED
|
||||
#define BOOST_LEAF_RESULT_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -10,19 +10,16 @@
|
||||
#include <boost/leaf/detail/capture_list.hpp>
|
||||
#include <boost/leaf/exception.hpp>
|
||||
|
||||
#include <climits>
|
||||
#include <functional>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace detail { class dynamic_allocator; }
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
class bad_result:
|
||||
public std::exception
|
||||
{
|
||||
char const * what() const noexcept final override
|
||||
char const * what() const noexcept override
|
||||
{
|
||||
return "boost::leaf::bad_result";
|
||||
}
|
||||
@@ -60,7 +57,7 @@ namespace detail
|
||||
{
|
||||
result_value_printer<T>::print(s, x);
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -158,20 +155,19 @@ namespace detail
|
||||
BOOST_LEAF_ASSERT(kind() == err_id_zero || kind() == err_id || kind() == err_id_capture_list);
|
||||
return make_error_id(int((state_&~3)|1));
|
||||
}
|
||||
};
|
||||
}
|
||||
}; // class result_discriminant
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result
|
||||
class BOOST_LEAF_ATTRIBUTE_NODISCARD result
|
||||
{
|
||||
template <class U>
|
||||
friend class result;
|
||||
|
||||
friend class detail::dynamic_allocator;
|
||||
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
friend class detail::dynamic_allocator;
|
||||
using capture_list = detail::capture_list;
|
||||
#endif
|
||||
|
||||
@@ -223,6 +219,7 @@ class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result
|
||||
#endif
|
||||
default:
|
||||
BOOST_LEAF_ASSERT(k == result_discriminant::err_id);
|
||||
(void) k;
|
||||
case result_discriminant::err_id_zero:
|
||||
return result<U>(what.get_error_id());
|
||||
}
|
||||
@@ -243,6 +240,7 @@ class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result
|
||||
{
|
||||
default:
|
||||
BOOST_LEAF_ASSERT(k == result_discriminant::err_id);
|
||||
(void) k;
|
||||
case result_discriminant::err_id_zero:
|
||||
break;
|
||||
case result_discriminant::err_id_capture_list:
|
||||
@@ -265,6 +263,7 @@ class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result
|
||||
{
|
||||
default:
|
||||
BOOST_LEAF_ASSERT(k == result_discriminant::err_id);
|
||||
(void) k;
|
||||
case result_discriminant::err_id_zero:
|
||||
break;
|
||||
case result_discriminant::err_id_capture_list:
|
||||
@@ -412,7 +411,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
#else // #if defined(BOOST_STRICT_CONFIG) || !defined(__clang__)
|
||||
|
||||
private:
|
||||
static int init_T_with_A( T && );
|
||||
@@ -426,7 +425,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #else (#if defined(BOOST_STRICT_CONFIG) || !defined(__clang__))
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
result( std::error_code const & ec ) noexcept:
|
||||
@@ -439,7 +438,7 @@ public:
|
||||
what_(error_id(e))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
~result() noexcept
|
||||
{
|
||||
@@ -490,7 +489,7 @@ public:
|
||||
return stored_;
|
||||
}
|
||||
|
||||
#else
|
||||
#else // #ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS
|
||||
|
||||
value_cref value() const &
|
||||
{
|
||||
@@ -516,7 +515,7 @@ public:
|
||||
return std::move(stored_);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #else (#ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS)
|
||||
|
||||
value_no_ref_const * operator->() const noexcept
|
||||
{
|
||||
@@ -544,7 +543,7 @@ public:
|
||||
return *p;
|
||||
}
|
||||
|
||||
#else
|
||||
#else // #ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS
|
||||
|
||||
value_cref operator*() const & noexcept
|
||||
{
|
||||
@@ -574,7 +573,7 @@ public:
|
||||
return std::move(*p);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #else (#ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS)
|
||||
|
||||
error_result error() noexcept
|
||||
{
|
||||
@@ -582,7 +581,7 @@ public:
|
||||
}
|
||||
|
||||
template <class... Item>
|
||||
error_id load( Item && ... item ) noexcept
|
||||
error_id load( Item && ... item ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
|
||||
{
|
||||
return error_id(error()).load(std::forward<Item>(item)...);
|
||||
}
|
||||
@@ -604,7 +603,7 @@ public:
|
||||
r.print_error_result(os);
|
||||
return os;
|
||||
}
|
||||
};
|
||||
}; // template result
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -614,19 +613,19 @@ namespace detail
|
||||
}
|
||||
|
||||
template <>
|
||||
class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result<void>:
|
||||
class BOOST_LEAF_ATTRIBUTE_NODISCARD result<void>:
|
||||
result<detail::void_>
|
||||
{
|
||||
template <class U>
|
||||
friend class result;
|
||||
|
||||
friend class detail::dynamic_allocator;
|
||||
|
||||
using result_discriminant = detail::result_discriminant;
|
||||
using void_ = detail::void_;
|
||||
using base = result<void_>;
|
||||
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
friend class detail::dynamic_allocator;
|
||||
|
||||
result( int err_id, detail::capture_list && cap ) noexcept:
|
||||
base(err_id, std::move(cap))
|
||||
{
|
||||
@@ -663,7 +662,7 @@ public:
|
||||
base(e)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
~result() noexcept
|
||||
{
|
||||
@@ -712,7 +711,7 @@ public:
|
||||
using base::error;
|
||||
using base::load;
|
||||
using base::unload;
|
||||
};
|
||||
}; // result specialization for void
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -724,6 +723,6 @@ struct is_result_type<result<T>>: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif // BOOST_LEAF_RESULT_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_RESULT_HPP_INCLUDED
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_LEAF_TO_VARIANT_HPP_INCLUDED
|
||||
#define BOOST_LEAF_TO_VARIANT_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -42,8 +42,8 @@ to_variant( TryBlock && try_block )
|
||||
} );
|
||||
}
|
||||
|
||||
} }
|
||||
} } // namespace boost::leaf
|
||||
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
|
||||
#endif // BOOST_LEAF_TO_VARIANT_HPP_INCLUDED
|
||||
#endif // #ifndef BOOST_LEAF_TO_VARIANT_HPP_INCLUDED
|
||||
|
||||
54
meson.build
54
meson.build
@@ -1,13 +1,12 @@
|
||||
# Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
# Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
project('leaf', 'cpp', default_options : ['cpp_std=c++17', 'b_pch=false'], license : 'boost')
|
||||
|
||||
option_single_header = get_option('single_header')
|
||||
option_boost = get_option('leaf_boost_examples')
|
||||
option_lua = get_option('leaf_lua_examples')
|
||||
option_single_header = get_option('leaf_single_header')
|
||||
option_boost_available = get_option('leaf_boost_available')
|
||||
option_diagnostics = get_option('leaf_diagnostics')
|
||||
option_capture = get_option('leaf_capture')
|
||||
option_exceptions = (get_option('cpp_eh')!='none')
|
||||
@@ -15,15 +14,6 @@ option_enable_unit_tests = get_option('leaf_enable_unit_tests')
|
||||
option_enable_examples = get_option('leaf_enable_examples')
|
||||
option_embedded = get_option('leaf_embedded')
|
||||
|
||||
if not option_enable_examples
|
||||
if option_boost
|
||||
error('The option leaf_boost_examples requires leaf_enable_examples. Aborting.')
|
||||
endif
|
||||
if option_lua
|
||||
error('The option leaf_lua_examples requires leaf_enable_examples. Aborting.')
|
||||
endif
|
||||
endif
|
||||
|
||||
if target_machine.system() == 'windows'
|
||||
add_global_arguments('-D_CRT_SECURE_NO_WARNINGS', language: 'cpp')
|
||||
endif
|
||||
@@ -31,7 +21,7 @@ endif
|
||||
compiler = meson.get_compiler('cpp')
|
||||
compiler_id = compiler.get_id()
|
||||
if not meson.is_subproject()
|
||||
if option_boost
|
||||
if option_boost_available
|
||||
add_global_arguments(
|
||||
'-DBOOST_LEAF_BOOST_AVAILABLE',
|
||||
language:'cpp' )
|
||||
@@ -88,12 +78,12 @@ if not meson.is_subproject()
|
||||
endif
|
||||
|
||||
dep_boost = [ ]
|
||||
if option_boost # Requires that LEAF resides under boost_root/libs/leaf.
|
||||
if option_boost_available # Requires that LEAF resides under boost_root/libs/leaf.
|
||||
dep_boost = declare_dependency(include_directories: '../..')
|
||||
endif
|
||||
|
||||
dep_lua = [ ]
|
||||
if option_lua
|
||||
if option_enable_examples
|
||||
dep_lua = subproject('lua').get_variable('all')
|
||||
endif
|
||||
|
||||
@@ -139,7 +129,6 @@ if option_enable_unit_tests
|
||||
'diagnostics_test5',
|
||||
'diagnostics_test6',
|
||||
'e_errno_test',
|
||||
'e_LastError_test',
|
||||
'error_code_test',
|
||||
'error_id_test',
|
||||
'exception_test',
|
||||
@@ -163,6 +152,7 @@ if option_enable_unit_tests
|
||||
'on_error_accumulate_nested_new_error_result_test',
|
||||
'on_error_accumulate_nested_success_exception_test',
|
||||
'on_error_accumulate_nested_success_result_test',
|
||||
'on_error_alloc_fail_test',
|
||||
'on_error_defer_basic_test',
|
||||
'on_error_defer_nested_error_exception_test',
|
||||
'on_error_defer_nested_error_result_test',
|
||||
@@ -170,6 +160,9 @@ if option_enable_unit_tests
|
||||
'on_error_defer_nested_new_error_result_test',
|
||||
'on_error_defer_nested_success_exception_test',
|
||||
'on_error_defer_nested_success_result_test',
|
||||
'on_error_dynamic_reserve_test1',
|
||||
'on_error_dynamic_reserve_test2',
|
||||
'on_error_dynamic_reserve_test3',
|
||||
'on_error_preload_basic_test',
|
||||
'on_error_preload_exception_test',
|
||||
'on_error_preload_nested_error_exception_test',
|
||||
@@ -198,7 +191,7 @@ if option_enable_unit_tests
|
||||
'try_catch_test',
|
||||
'try_exception_and_result_test',
|
||||
]
|
||||
if option_boost and option_exceptions
|
||||
if option_boost_available and option_exceptions
|
||||
tests += [
|
||||
'boost_exception_test'
|
||||
]
|
||||
@@ -213,6 +206,11 @@ if option_enable_unit_tests
|
||||
test(t, executable(t, 'test/'+t+'.cpp', dependencies: [leaf, dep_thread, dep_boost, dep_test_single_header]) )
|
||||
endforeach
|
||||
|
||||
if target_machine.system() == 'windows'
|
||||
dep_e_LastError = declare_dependency(compile_args: ['-DBOOST_LEAF_CFG_WIN32=1'])
|
||||
test('e_LastError_test', executable('e_LastError_test', 'test/e_LastError_test.cpp', dependencies: [leaf, dep_thread, dep_boost, dep_test_single_header, dep_e_LastError]) )
|
||||
endif
|
||||
|
||||
header_tests = [
|
||||
'_hpp_common_test',
|
||||
'_hpp_config_test',
|
||||
@@ -231,6 +229,22 @@ if option_enable_unit_tests
|
||||
test(t, executable(t, 'test/'+t+'.cpp', dependencies: [leaf, dep_thread, dep_boost]) )
|
||||
endforeach
|
||||
|
||||
# Shared library test
|
||||
dep_so_dll = []
|
||||
if target_machine.system() == 'windows'
|
||||
dep_so_dll = declare_dependency(compile_args: ['-DBOOST_LEAF_CFG_WIN32=2'])
|
||||
endif
|
||||
so_dll_test_lib1 = shared_library('so_dll_test_lib1', 'test/so_dll_lib1.cpp', dependencies: [leaf, dep_so_dll], gnu_symbol_visibility: 'hidden')
|
||||
so_dll_test_lib2 = shared_library('so_dll_test_lib2', 'test/so_dll_lib2.cpp', dependencies: [leaf, dep_so_dll], gnu_symbol_visibility: 'hidden')
|
||||
test('so_dll_test', executable('so_dll_test', 'test/so_dll_test.cpp', dependencies: [leaf, dep_so_dll], link_with: [so_dll_test_lib1, so_dll_test_lib2]))
|
||||
|
||||
# Test that the DLL test works when linked statically as well.
|
||||
# This is to verify that we don't get multiply defined symbol link errors when tls_win32.hpp is included in multiple compilation units..
|
||||
dep_so_dll_static = declare_dependency(compile_args: ['-DBOOST_LEAF_SO_DLL_TEST_STATIC'])
|
||||
so_dll_static_lib1 = static_library('so_dll_static_lib1', 'test/so_dll_lib1.cpp', dependencies: [leaf, dep_so_dll, dep_so_dll_static])
|
||||
so_dll_static_lib2 = static_library('so_dll_static_lib2', 'test/so_dll_lib2.cpp', dependencies: [leaf, dep_so_dll, dep_so_dll_static])
|
||||
test('so_dll_static_test', executable('so_dll_static_test', 'test/so_dll_test.cpp', dependencies: [leaf, dep_so_dll, dep_so_dll_static], link_with: [so_dll_static_lib1, so_dll_static_lib2]))
|
||||
|
||||
endif
|
||||
|
||||
#################################
|
||||
@@ -241,7 +255,7 @@ if option_enable_examples
|
||||
if option_exceptions
|
||||
executable('print_file_exceptions', 'example/print_file/print_file_exceptions.cpp', dependencies: [leaf] )
|
||||
endif
|
||||
if option_boost
|
||||
if option_boost_available
|
||||
executable('print_file_system_result', 'example/print_file/print_file_system_result.cpp', dependencies: [leaf, dep_boost] )
|
||||
endif
|
||||
|
||||
@@ -254,7 +268,7 @@ if option_enable_examples
|
||||
executable('exception_to_result', 'example/exception_to_result.cpp', dependencies: [leaf] )
|
||||
endif
|
||||
|
||||
if option_lua
|
||||
if option_enable_examples
|
||||
if option_exceptions
|
||||
executable('lua_callback_exceptions', 'example/lua_callback_exceptions.cpp', dependencies: [leaf, dep_lua] )
|
||||
endif
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
option('single_header',type:'boolean',value:false,description:'Unit tests #include "leaf.hpp" instead of individual headers')
|
||||
option('leaf_boost_examples',type:'boolean',value:false,description:'Builds the examples that use Boost')
|
||||
option('leaf_lua_examples',type:'boolean',value:false,description:'Enable or disable downloading of Lua and building the Lua examples')
|
||||
option('leaf_single_header',type:'boolean',value:false,description:'Unit tests #include "leaf.hpp" instead of individual headers')
|
||||
option('leaf_boost_available',type:'boolean',value:false,description:'Set to true to enable tests and examples that require Boost')
|
||||
option('leaf_diagnostics',type:'integer',value:1,description:'BOOST_LEAF_CFG_DIAGNOSTICS value')
|
||||
option('leaf_capture',type:'integer',value:1,description:'BOOST_LEAF_CFG_CAPTURE value')
|
||||
option('leaf_embedded',type:'boolean',value:false,description:'Defines BOOST_LEAF_EMBEDDED')
|
||||
|
||||
0
subprojects/.wraplock
Normal file
0
subprojects/.wraplock
Normal file
@@ -70,8 +70,8 @@ run diagnostics_test3.cpp ;
|
||||
run diagnostics_test4.cpp ;
|
||||
run diagnostics_test5.cpp ;
|
||||
run e_errno_test.cpp ;
|
||||
run e_LastError_test.cpp ;
|
||||
run error_code_test.cpp ;
|
||||
run e_LastError_test.cpp : : : <target-os>windows:<define>BOOST_LEAF_CFG_WIN32=1 ;
|
||||
run error_code_test.cpp : : : <toolset>clang-darwin,<exception-handling>off,<rtti>off:<linkflags>"-Wl,-ld_classic" ; # workaround for macos-14 linker bug
|
||||
run error_id_test.cpp ;
|
||||
run exception_test.cpp ;
|
||||
run exception_to_result_test.cpp ;
|
||||
@@ -94,6 +94,7 @@ run on_error_accumulate_nested_new_error_exception_test.cpp ;
|
||||
run on_error_accumulate_nested_new_error_result_test.cpp ;
|
||||
run on_error_accumulate_nested_success_exception_test.cpp ;
|
||||
run on_error_accumulate_nested_success_result_test.cpp ;
|
||||
run on_error_alloc_fail_test.cpp ;
|
||||
run on_error_defer_basic_test.cpp ;
|
||||
run on_error_defer_nested_error_exception_test.cpp ;
|
||||
run on_error_defer_nested_error_result_test.cpp ;
|
||||
@@ -101,6 +102,9 @@ run on_error_defer_nested_new_error_exception_test.cpp ;
|
||||
run on_error_defer_nested_new_error_result_test.cpp ;
|
||||
run on_error_defer_nested_success_exception_test.cpp ;
|
||||
run on_error_defer_nested_success_result_test.cpp ;
|
||||
run on_error_dynamic_reserve_test1.cpp ;
|
||||
run on_error_dynamic_reserve_test2.cpp ;
|
||||
run on_error_dynamic_reserve_test3.cpp ;
|
||||
run on_error_preload_basic_test.cpp ;
|
||||
run on_error_preload_exception_test.cpp ;
|
||||
run on_error_preload_nested_error_exception_test.cpp ;
|
||||
@@ -129,9 +133,13 @@ run try_catch_system_error_test.cpp ;
|
||||
run try_catch_test.cpp ;
|
||||
run try_exception_and_result_test.cpp ;
|
||||
|
||||
lib visibility_test_lib : visibility_test_lib.cpp : <visibility>hidden ;
|
||||
run visibility_test.cpp visibility_test_lib/<link>shared ;
|
||||
run visibility_test.cpp visibility_test_lib/<link>static : : : <target-os>windows ; # This can't work on Windows, so use static link for the test.
|
||||
lib so_dll_lib1 : so_dll_lib1.cpp : <link>shared <visibility>hidden <target-os>windows:<define>BOOST_LEAF_CFG_WIN32=2 : : <target-os>windows:<define>BOOST_LEAF_CFG_WIN32=2 ;
|
||||
lib so_dll_lib2 : so_dll_lib2.cpp : <link>shared <visibility>hidden <target-os>windows:<define>BOOST_LEAF_CFG_WIN32=2 : : <target-os>windows:<define>BOOST_LEAF_CFG_WIN32=2 ;
|
||||
run so_dll_test.cpp so_dll_lib1 so_dll_lib2 : : : <target-os>windows:<define>BOOST_LEAF_CFG_WIN32=2 ;
|
||||
|
||||
lib so_dll_static_lib1 : so_dll_lib1.cpp : <link>static <define>BOOST_LEAF_SO_DLL_TEST_STATIC <target-os>windows:<define>BOOST_LEAF_CFG_WIN32=2 ;
|
||||
lib so_dll_static_lib2 : so_dll_lib2.cpp : <link>static <define>BOOST_LEAF_SO_DLL_TEST_STATIC <target-os>windows:<define>BOOST_LEAF_CFG_WIN32=2 ;
|
||||
run so_dll_test.cpp so_dll_static_lib1 so_dll_static_lib2 : : : <define>BOOST_LEAF_SO_DLL_TEST_STATIC <target-os>windows:<define>BOOST_LEAF_CFG_WIN32=2 : so_dll_static_test ;
|
||||
|
||||
compile-fail _compile-fail-arg_boost_error_info_1.cpp ;
|
||||
compile-fail _compile-fail-arg_boost_error_info_2.cpp ;
|
||||
|
||||
@@ -155,4 +155,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if defined(BOOST_LEAF_NO_EXCEPTIONS) || defined(BOOST_LEAF_NO_THREADS) || !BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
@@ -154,4 +154,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if defined(BOOST_LEAF_NO_EXCEPTIONS) || defined(BOOST_LEAF_NO_THREADS) || !BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
@@ -185,4 +185,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if defined(BOOST_LEAF_NO_EXCEPTIONS) || !BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
@@ -82,7 +82,7 @@ int main()
|
||||
BOOST_TEST_NE(s.find("info<3> instance"), s.npos);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_STRING
|
||||
|
||||
int ret = leaf::try_catch(
|
||||
[&]
|
||||
@@ -104,4 +104,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if defined(BOOST_LEAF_NO_EXCEPTIONS) || !BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
@@ -183,4 +183,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if defined(BOOST_LEAF_NO_EXCEPTIONS) || !BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
@@ -156,4 +156,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if defined(BOOST_LEAF_NO_THREADS) || !BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
@@ -81,7 +81,7 @@ int main()
|
||||
BOOST_TEST_NE(s.find("info<3> instance"), s.npos);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_STRING
|
||||
|
||||
int ret = leaf::try_handle_all(
|
||||
[&]
|
||||
@@ -103,4 +103,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if !BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
@@ -164,4 +164,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if !BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
@@ -8,13 +8,15 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "This test requires Windows";
|
||||
std::cout << "Test skipped (Windows only)";
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_LEAF_CFG_WIN32 1
|
||||
#if BOOST_LEAF_CFG_WIN32 <= 0
|
||||
# error This test requires BOOST_LEAF_CFG_WIN32 > 0
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
|
||||
# include "leaf.hpp"
|
||||
@@ -67,4 +69,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifndef _WIN32
|
||||
|
||||
@@ -14,7 +14,7 @@ int main()
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#else // #if !BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
|
||||
# include "leaf.hpp"
|
||||
@@ -27,10 +27,12 @@ int main()
|
||||
#include "_test_res.hpp"
|
||||
#include "lightweight_test.hpp"
|
||||
|
||||
#if BOOST_LEAF_BOOST_AVAILABLE
|
||||
#include "boost/system/result.hpp"
|
||||
namespace boost { namespace leaf {
|
||||
template <class T> struct is_result_type<boost::system::result<T, std::error_code>>: std::true_type { };
|
||||
} }
|
||||
#endif
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
@@ -97,7 +99,7 @@ void test()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 42);
|
||||
}
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
|
||||
{
|
||||
int r = leaf::try_handle_all(
|
||||
@@ -154,7 +156,7 @@ void test()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 42);
|
||||
}
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
{
|
||||
int r = leaf::try_handle_all(
|
||||
[]() -> R
|
||||
@@ -212,7 +214,7 @@ void test()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 42);
|
||||
}
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
|
||||
{
|
||||
int r = leaf::try_handle_all(
|
||||
@@ -271,7 +273,7 @@ void test()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 42);
|
||||
}
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
{
|
||||
int r = leaf::try_handle_all(
|
||||
[]() -> R
|
||||
@@ -313,7 +315,7 @@ void test()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 42);
|
||||
}
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
}
|
||||
|
||||
template <class R>
|
||||
@@ -380,7 +382,7 @@ void test_void()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 42);
|
||||
}
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
|
||||
{
|
||||
int r = 0;
|
||||
@@ -440,7 +442,7 @@ void test_void()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 42);
|
||||
}
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
{
|
||||
int r = 0;
|
||||
leaf::try_handle_all(
|
||||
@@ -501,7 +503,7 @@ void test_void()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 42);
|
||||
}
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
|
||||
{
|
||||
int r = 0;
|
||||
@@ -563,7 +565,7 @@ void test_void()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 42);
|
||||
}
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
{
|
||||
int r = 0;
|
||||
leaf::try_handle_all(
|
||||
@@ -607,7 +609,7 @@ void test_void()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 42);
|
||||
}
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
}
|
||||
|
||||
int main()
|
||||
@@ -616,8 +618,10 @@ int main()
|
||||
test<test_res<int, std::error_code>>();
|
||||
test_void<leaf::result<void>>();
|
||||
test_void<test_res<void, std::error_code>>();
|
||||
#ifdef BOOST_LEAF_BOOST_AVAILABLE
|
||||
test<boost::system::result<int, std::error_code>>();
|
||||
#endif
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if !BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
@@ -291,4 +291,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
@@ -128,4 +128,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
@@ -52,7 +52,7 @@ leaf::result<R> f_errc_wrapped( Errc ec )
|
||||
{
|
||||
return leaf::new_error(e_std_error_code{make_error_code(ec)}, info<1>{1}, info<2>{2}, info<3>{3});
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
struct move_only
|
||||
{
|
||||
@@ -142,7 +142,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(c, 2);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
// void, try_handle_all (failure), match cond_x (wrapped std::error_code)
|
||||
@@ -175,7 +175,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(c, 2);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
// void, try_handle_all (failure), match enum (single enum value)
|
||||
{
|
||||
@@ -366,7 +366,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 2);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
// int, try_handle_all (failure), match cond_x (wrapped std::error_code)
|
||||
@@ -394,7 +394,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 2);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
// int, try_handle_all (failure), match enum (single enum value)
|
||||
{
|
||||
@@ -565,7 +565,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(r.value, 2);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
// move_only, try_handle_all (failure), match cond_x (wrapped std::error_code)
|
||||
@@ -593,7 +593,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(r.value, 2);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
// move_only, try_handle_all (failure), match enum (single enum value)
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@ leaf::result<R> f_errc_wrapped( Errc ec )
|
||||
{
|
||||
return leaf::new_error(e_std_error_code{make_error_code(ec)}, info<1>{1}, info<2>{2}, info<3>{3});
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -120,7 +120,7 @@ int main()
|
||||
BOOST_TEST_EQ(c, 1);
|
||||
BOOST_TEST(r);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
// void, try_handle_some (failure, matched), match cond_x (wrapped std::error_code)
|
||||
@@ -144,7 +144,7 @@ int main()
|
||||
BOOST_TEST_EQ(c, 1);
|
||||
BOOST_TEST(r);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
// void, try_handle_some (failure, matched), match enum (single enum value)
|
||||
{
|
||||
@@ -330,7 +330,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(c, 2);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
// void, try_handle_some (failure, initially not matched), match cond_x (wrapped std::error_code)
|
||||
@@ -370,7 +370,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(c, 2);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
// void, try_handle_some (failure, initially not matched), match enum (single enum value)
|
||||
{
|
||||
@@ -600,7 +600,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(c, 1);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
// void, try_handle_some (failure, initially matched), match cond_x (wrapped std::error_code)
|
||||
@@ -640,7 +640,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(c, 1);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
// void, try_handle_some (failure, initially matched), match enum (single enum value)
|
||||
{
|
||||
@@ -853,7 +853,7 @@ int main()
|
||||
BOOST_TEST(r);
|
||||
BOOST_TEST_EQ(*r, 2);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
// int, try_handle_some (failure, matched), match enum (single enum value)
|
||||
{
|
||||
@@ -1011,7 +1011,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 2);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
// int, try_handle_some (failure, initially not matched), match cond_x (wrapped std::error_code)
|
||||
@@ -1045,7 +1045,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 2);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
// int, try_handle_some (failure, initially not matched), match enum (single enum value)
|
||||
{
|
||||
@@ -1239,7 +1239,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 1);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
// int, try_handle_some (failure, initially matched), match cond_x (wrapped std::error_code)
|
||||
@@ -1273,7 +1273,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 1);
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
// int, try_handle_some (failure, initially matched), match enum (single enum value)
|
||||
{
|
||||
@@ -1474,7 +1474,7 @@ int main()
|
||||
BOOST_TEST_EQ(r.value(), 1);
|
||||
BOOST_TEST_EQ(handle_some_handler_called, 1);
|
||||
}
|
||||
#endif
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
// exception caught, error not handled
|
||||
@@ -1509,7 +1509,7 @@ int main()
|
||||
});
|
||||
BOOST_TEST_EQ(r, 1);
|
||||
}
|
||||
#endif
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -4,19 +4,18 @@
|
||||
|
||||
#include <boost/leaf/config.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
#include <exception>
|
||||
|
||||
#ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
namespace boost
|
||||
{
|
||||
[[noreturn]] void throw_exception( std::exception const & e )
|
||||
[[noreturn]] inline void throw_exception( std::exception const & e )
|
||||
{
|
||||
std::cerr << "Terminating due to a C++ exception under BOOST_LEAF_NO_EXCEPTIONS: " << e.what();
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
struct source_location;
|
||||
[[noreturn]] void throw_exception( std::exception const & e, boost::source_location const & )
|
||||
[[noreturn]] inline void throw_exception( std::exception const & e, boost::source_location const & )
|
||||
{
|
||||
throw_exception(e);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ int main()
|
||||
|
||||
#include "_test_ec.hpp"
|
||||
#include "lightweight_test.hpp"
|
||||
#include <exception>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include "_test_ec.hpp"
|
||||
#include "lightweight_test.hpp"
|
||||
#include <exception>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
@@ -32,7 +31,7 @@ constexpr bool e_my_error_gt( e_my_error const & e ) noexcept
|
||||
{
|
||||
return e.value > S;
|
||||
}
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
|
||||
struct my_exception: std::exception
|
||||
{
|
||||
@@ -100,9 +99,9 @@ int main()
|
||||
BOOST_TEST(( !test<leaf::if_not<leaf::match<std::error_code, errc_a::a0>>>(e) ));
|
||||
BOOST_TEST(( test<leaf::if_not<leaf::match<std::error_code, errc_a::a2>>>(e) ));
|
||||
BOOST_TEST(( !test<leaf::if_not<leaf::match<std::error_code, errc_a::a2, errc_a::a0>>>(e) ));
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
}
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
{
|
||||
@@ -275,7 +274,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 2);
|
||||
}
|
||||
#endif
|
||||
#endif // #if __cplusplus >= 201703L
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include "_test_ec.hpp"
|
||||
#include "lightweight_test.hpp"
|
||||
#include <exception>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#endif
|
||||
|
||||
#include "lightweight_test.hpp"
|
||||
#include <exception>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
|
||||
@@ -84,4 +84,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
@@ -99,4 +99,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
@@ -68,4 +68,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
125
test/on_error_alloc_fail_test.cpp
Normal file
125
test/on_error_alloc_fail_test.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
|
||||
# include "leaf.hpp"
|
||||
#else
|
||||
# include <boost/leaf/error.hpp>
|
||||
# include <boost/leaf/on_error.hpp>
|
||||
# include <boost/leaf/handle_errors.hpp>
|
||||
# include <boost/leaf/result.hpp>
|
||||
# include <boost/leaf/diagnostics.hpp>
|
||||
#endif
|
||||
|
||||
#if !BOOST_LEAF_CFG_CAPTURE || defined(BOOST_LEAF_NO_EXCEPTIONS)
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
struct alloc_fail_info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
namespace boost { namespace leaf { namespace detail {
|
||||
|
||||
template <>
|
||||
struct capturing_slot_node_allocator<alloc_fail_info>
|
||||
{
|
||||
template <class... A>
|
||||
static dynamic_allocator::capturing_slot_node<alloc_fail_info> * new_( A && ... )
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
static void delete_( dynamic_allocator::capturing_slot_node<alloc_fail_info> * p ) noexcept
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
};
|
||||
|
||||
} } } // namespace boost::leaf::detail
|
||||
|
||||
#include "lightweight_test.hpp"
|
||||
|
||||
template <int N>
|
||||
struct other_info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::result<void> f()
|
||||
{
|
||||
auto load = leaf::on_error( other_info<1>{1}, alloc_fail_info{42}, other_info<2>{2} );
|
||||
return leaf::new_error();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
auto captured = leaf::try_capture_all(
|
||||
[]() -> leaf::result<void>
|
||||
{
|
||||
return f();
|
||||
} );
|
||||
|
||||
int r = leaf::try_handle_all(
|
||||
[&]() -> leaf::result<int>
|
||||
{
|
||||
(void) captured.value();
|
||||
return 0;
|
||||
},
|
||||
[]( std::bad_alloc const &, other_info<1> const & oi1, other_info<2> const * oi2, alloc_fail_info const * afi )
|
||||
{
|
||||
BOOST_TEST_EQ(oi1.value, 1);
|
||||
BOOST_TEST_EQ(oi2, nullptr);
|
||||
BOOST_TEST_EQ(afi, nullptr);
|
||||
return 1;
|
||||
},
|
||||
[]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 1);
|
||||
}
|
||||
|
||||
#if BOOST_LEAF_CFG_DIAGNOSTICS && BOOST_LEAF_CFG_STD_STRING
|
||||
{
|
||||
int r = leaf::try_handle_all(
|
||||
[]() -> leaf::result<int>
|
||||
{
|
||||
BOOST_LEAF_CHECK(f());
|
||||
return 0;
|
||||
},
|
||||
[]( std::bad_alloc const &, leaf::diagnostic_details const & dd )
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << dd;
|
||||
std::string str = s.str();
|
||||
BOOST_TEST(str.find("other_info<1>") != std::string::npos);
|
||||
BOOST_TEST(str.find("other_info<2>") == std::string::npos);
|
||||
BOOST_TEST(str.find("alloc_fail_info") == std::string::npos);
|
||||
return 1;
|
||||
},
|
||||
[]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -84,4 +84,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
@@ -91,4 +91,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
@@ -68,4 +68,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
52
test/on_error_dynamic_reserve_test1.cpp
Normal file
52
test/on_error_dynamic_reserve_test1.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
|
||||
# include "leaf.hpp"
|
||||
#else
|
||||
# include <boost/leaf/on_error.hpp>
|
||||
# include <boost/leaf/handle_errors.hpp>
|
||||
# include <boost/leaf/result.hpp>
|
||||
# include <boost/leaf/config/tls.hpp>
|
||||
#endif
|
||||
|
||||
#include "lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int N>
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::result<void> f()
|
||||
{
|
||||
BOOST_TEST(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>() == nullptr);
|
||||
BOOST_TEST(leaf::tls::read_ptr<leaf::detail::slot<info<43>>>() != nullptr);
|
||||
auto load = leaf::on_error( info<42>{42} );
|
||||
BOOST_TEST(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>() == nullptr);
|
||||
return leaf::new_error(info<43>{});
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int r = leaf::try_handle_all(
|
||||
[]() -> leaf::result<int>
|
||||
{
|
||||
BOOST_LEAF_CHECK(f());
|
||||
return 0;
|
||||
},
|
||||
[]( info<43> const & )
|
||||
{
|
||||
return 1;
|
||||
},
|
||||
[]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 1);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
58
test/on_error_dynamic_reserve_test2.cpp
Normal file
58
test/on_error_dynamic_reserve_test2.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
|
||||
# include "leaf.hpp"
|
||||
#else
|
||||
# include <boost/leaf/on_error.hpp>
|
||||
# include <boost/leaf/handle_errors.hpp>
|
||||
# include <boost/leaf/result.hpp>
|
||||
# include <boost/leaf/config/tls.hpp>
|
||||
# include <boost/leaf/diagnostics.hpp>
|
||||
#endif
|
||||
|
||||
#include "lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int N>
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::result<void> f()
|
||||
{
|
||||
BOOST_TEST(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>() == nullptr);
|
||||
BOOST_TEST(leaf::tls::read_ptr<leaf::detail::slot<info<43>>>() != nullptr);
|
||||
auto load = leaf::on_error( info<42>{42} );
|
||||
BOOST_TEST(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>() == nullptr);
|
||||
auto e = leaf::new_error(info<43>{});
|
||||
BOOST_TEST(
|
||||
(BOOST_LEAF_CFG_CAPTURE == 0 || BOOST_LEAF_CFG_DIAGNOSTICS == 0)
|
||||
==
|
||||
(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>() == nullptr));
|
||||
return e;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int r = leaf::try_handle_all(
|
||||
[]() -> leaf::result<int>
|
||||
{
|
||||
BOOST_LEAF_CHECK(f());
|
||||
return 0;
|
||||
},
|
||||
[]( info<43> const & )
|
||||
{
|
||||
return 1;
|
||||
},
|
||||
[]( leaf::diagnostic_details const & )
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 1);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
74
test/on_error_dynamic_reserve_test3.cpp
Normal file
74
test/on_error_dynamic_reserve_test3.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/leaf/config.hpp>
|
||||
|
||||
#if !BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "Unit test not applicable." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
|
||||
# include "leaf.hpp"
|
||||
#else
|
||||
# include <boost/leaf/on_error.hpp>
|
||||
# include <boost/leaf/handle_errors.hpp>
|
||||
# include <boost/leaf/result.hpp>
|
||||
# include <boost/leaf/config/tls.hpp>
|
||||
#endif
|
||||
|
||||
#include "lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int N>
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::result<void> f()
|
||||
{
|
||||
BOOST_TEST(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>() == nullptr);
|
||||
BOOST_TEST(leaf::tls::read_ptr<leaf::detail::slot<info<43>>>() != nullptr);
|
||||
auto load = leaf::on_error( info<42>{42} );
|
||||
BOOST_TEST(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>() == nullptr);
|
||||
auto e = leaf::new_error(info<43>{});
|
||||
BOOST_TEST(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>() != nullptr);
|
||||
return e;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int r = leaf::try_handle_all(
|
||||
[]() -> leaf::result<int>
|
||||
{
|
||||
return leaf::try_capture_all(
|
||||
[]() -> leaf::result<int>
|
||||
{
|
||||
BOOST_LEAF_CHECK(f());
|
||||
return 0;
|
||||
} );
|
||||
},
|
||||
[]( info<43> const & )
|
||||
{
|
||||
return 1;
|
||||
},
|
||||
[]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 1);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,6 +6,7 @@
|
||||
# include "leaf.hpp"
|
||||
#else
|
||||
# include <boost/leaf/on_error.hpp>
|
||||
# include <boost/leaf/handle_errors.hpp>
|
||||
# include <boost/leaf/diagnostics.hpp>
|
||||
# include <boost/leaf/result.hpp>
|
||||
#endif
|
||||
@@ -69,5 +70,22 @@ int main()
|
||||
auto load = leaf::on_error( inf1, info<-42>{-42} );
|
||||
return leaf::new_error();
|
||||
});
|
||||
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
(void) leaf::try_capture_all(
|
||||
[]() -> leaf::result<void>
|
||||
{
|
||||
leaf::detail::dynamic_allocator * da = leaf::detail::get_dynamic_allocator();
|
||||
BOOST_TEST(da != nullptr);
|
||||
BOOST_TEST(da->preloaded_list() == nullptr);
|
||||
{
|
||||
auto load = leaf::on_error( info<42>{42} );
|
||||
BOOST_TEST(da->preloaded_list() != nullptr);
|
||||
}
|
||||
BOOST_TEST(da->preloaded_list() == nullptr);
|
||||
return { };
|
||||
} );
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -149,4 +149,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if defined(BOOST_LEAF_NO_EXCEPTIONS) || defined(BOOST_LEAF_NO_THREADS)
|
||||
|
||||
@@ -84,4 +84,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
@@ -91,4 +91,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
@@ -68,4 +68,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
@@ -369,7 +369,7 @@ int main()
|
||||
}
|
||||
BOOST_TEST_EQ(err::count, 0);
|
||||
BOOST_TEST_EQ(val::count, 0);
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
// ^^ result<T> ^^
|
||||
|
||||
@@ -545,7 +545,7 @@ int main()
|
||||
BOOST_TEST(r2.operator->() == 0);
|
||||
}
|
||||
BOOST_TEST_EQ(err::count, 0);
|
||||
#endif
|
||||
#endif // #if BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
{
|
||||
leaf::result<int> r = leaf::error_id();
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "visibility_test_lib.hpp"
|
||||
|
||||
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
|
||||
# include "leaf.hpp"
|
||||
#else
|
||||
@@ -12,17 +10,23 @@
|
||||
# include <boost/leaf/on_error.hpp>
|
||||
#endif
|
||||
|
||||
#include "lightweight_test.hpp"
|
||||
|
||||
#define BOOST_LEAF_SO_DLL_TEST_BUILDING_LIB1
|
||||
|
||||
#include "so_dll_lib1.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
leaf::result<void> BOOST_SYMBOL_VISIBLE hidden_result()
|
||||
BOOST_LEAF_SO_DLL_TEST_LIB1_API leaf::result<void> hidden_result1()
|
||||
{
|
||||
auto load = leaf::on_error( my_info<1>{1}, my_info<3>{3} );
|
||||
return leaf::new_error( my_info<2>{2} );
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
void BOOST_SYMBOL_VISIBLE hidden_throw()
|
||||
BOOST_LEAF_SO_DLL_TEST_LIB1_API void hidden_throw1()
|
||||
{
|
||||
auto load = leaf::on_error( my_info<1>{1}, my_info<3>{3} );
|
||||
leaf::throw_exception( my_info<2>{2} );
|
||||
29
test/so_dll_lib1.hpp
Normal file
29
test/so_dll_lib1.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef SO_DLL_TEST_LIB1_HPP_INCLUDED
|
||||
#define SO_DLL_TEST_LIB1_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "so_dll_test.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef BOOST_LEAF_SO_DLL_TEST_STATIC
|
||||
# define BOOST_LEAF_SO_DLL_TEST_LIB1_API
|
||||
# elif defined(BOOST_LEAF_SO_DLL_TEST_BUILDING_LIB1)
|
||||
# define BOOST_LEAF_SO_DLL_TEST_LIB1_API __declspec(dllexport)
|
||||
# else
|
||||
# define BOOST_LEAF_SO_DLL_TEST_LIB1_API __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# define BOOST_LEAF_SO_DLL_TEST_LIB1_API [[gnu::visibility("default")]]
|
||||
#endif
|
||||
|
||||
BOOST_LEAF_SO_DLL_TEST_LIB1_API boost::leaf::result<void> hidden_result1();
|
||||
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
BOOST_LEAF_SO_DLL_TEST_LIB1_API void hidden_throw1();
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
35
test/so_dll_lib2.cpp
Normal file
35
test/so_dll_lib2.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
|
||||
# include "leaf.hpp"
|
||||
#else
|
||||
# include <boost/leaf/exception.hpp>
|
||||
# include <boost/leaf/result.hpp>
|
||||
# include <boost/leaf/on_error.hpp>
|
||||
#endif
|
||||
|
||||
#include "lightweight_test.hpp"
|
||||
|
||||
#define BOOST_LEAF_SO_DLL_TEST_BUILDING_LIB2
|
||||
|
||||
#include "so_dll_lib2.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
BOOST_LEAF_SO_DLL_TEST_LIB2_API leaf::result<void> hidden_result2()
|
||||
{
|
||||
auto load = leaf::on_error( my_info<1>{1}, my_info<3>{3} );
|
||||
return leaf::new_error( my_info<2>{2} );
|
||||
}
|
||||
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
BOOST_LEAF_SO_DLL_TEST_LIB2_API void hidden_throw2()
|
||||
{
|
||||
auto load = leaf::on_error( my_info<1>{1}, my_info<3>{3} );
|
||||
leaf::throw_exception( my_info<2>{2} );
|
||||
}
|
||||
|
||||
#endif
|
||||
29
test/so_dll_lib2.hpp
Normal file
29
test/so_dll_lib2.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef SO_DLL_TEST_LIB2_HPP_INCLUDED
|
||||
#define SO_DLL_TEST_LIB2_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "so_dll_test.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef BOOST_LEAF_SO_DLL_TEST_STATIC
|
||||
# define BOOST_LEAF_SO_DLL_TEST_LIB2_API
|
||||
# elif defined(BOOST_LEAF_SO_DLL_TEST_BUILDING_LIB2)
|
||||
# define BOOST_LEAF_SO_DLL_TEST_LIB2_API __declspec(dllexport)
|
||||
# else
|
||||
# define BOOST_LEAF_SO_DLL_TEST_LIB2_API __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# define BOOST_LEAF_SO_DLL_TEST_LIB2_API [[gnu::visibility("default")]]
|
||||
#endif
|
||||
|
||||
BOOST_LEAF_SO_DLL_TEST_LIB2_API boost::leaf::result<void> hidden_result2();
|
||||
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
BOOST_LEAF_SO_DLL_TEST_LIB2_API void hidden_throw2();
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
226
test/so_dll_test.cpp
Normal file
226
test/so_dll_test.cpp
Normal file
@@ -0,0 +1,226 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_LEAF_SO_DLL_TEST_BUILDING_EXE
|
||||
|
||||
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
|
||||
# include "leaf.hpp"
|
||||
#else
|
||||
# include <boost/leaf/diagnostics.hpp>
|
||||
# include <boost/leaf/result.hpp>
|
||||
#endif
|
||||
|
||||
#include "so_dll_lib1.hpp"
|
||||
#include "so_dll_lib2.hpp"
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_STRING
|
||||
# include <sstream>
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
|
||||
#include "lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
int test_result(leaf::result<void> (*f)(), bool print)
|
||||
{
|
||||
int r = leaf::try_handle_all(
|
||||
[f]() -> leaf::result<int>
|
||||
{
|
||||
BOOST_LEAF_CHECK(f());
|
||||
return 0;
|
||||
},
|
||||
[&]( my_info<1> x1, my_info<2> x2, leaf::diagnostic_details const & info, leaf::diagnostic_details const & vinfo )
|
||||
{
|
||||
if( x1.value != 1 )
|
||||
return 1;
|
||||
if( x2.value != 2 )
|
||||
return 2;
|
||||
if( BOOST_LEAF_CFG_DIAGNOSTICS && print )
|
||||
{
|
||||
#if BOOST_LEAF_CFG_STD_STRING
|
||||
std::ostringstream ss; ss << vinfo;
|
||||
std::string s = ss.str();
|
||||
std::cout << "Handler matched, diagnostics:\n" << s << std::endl;
|
||||
if( BOOST_LEAF_CFG_DIAGNOSTICS && BOOST_LEAF_CFG_CAPTURE )
|
||||
if( s.find("Test my_info<3>::value = 3") == std::string::npos )
|
||||
return 3;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
[&](leaf::diagnostic_details const & vinfo)
|
||||
{
|
||||
#if BOOST_LEAF_CFG_STD_STRING
|
||||
if( print )
|
||||
std::cout << "Test is failing (catch-all), diagnostics:\n" << vinfo << std::endl;
|
||||
#endif
|
||||
return 4;
|
||||
} );
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
int test_exception(void (*f)(), bool print)
|
||||
{
|
||||
int r = leaf::try_catch(
|
||||
[f]
|
||||
{
|
||||
f();
|
||||
return 0;
|
||||
},
|
||||
[&]( my_info<1> x1, my_info<2> x2, leaf::diagnostic_details const & info, leaf::diagnostic_details const & vinfo )
|
||||
{
|
||||
if( x1.value != 1 )
|
||||
return 1;
|
||||
if( x2.value != 2 )
|
||||
return 2;
|
||||
if( BOOST_LEAF_CFG_DIAGNOSTICS && print )
|
||||
{
|
||||
#if BOOST_LEAF_CFG_STD_STRING
|
||||
std::ostringstream ss; ss << vinfo;
|
||||
std::string s = ss.str();
|
||||
std::cout << s << std::endl;
|
||||
if( BOOST_LEAF_CFG_DIAGNOSTICS && BOOST_LEAF_CFG_CAPTURE )
|
||||
if( s.find("Test my_info<3>::value = 3") == std::string::npos )
|
||||
return 3;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
[&](leaf::diagnostic_details const & vinfo)
|
||||
{
|
||||
#if BOOST_LEAF_CFG_STD_STRING
|
||||
if( print )
|
||||
std::cout << "Test is failing\n" << vinfo;
|
||||
#endif
|
||||
return 4;
|
||||
} );
|
||||
return r;
|
||||
}
|
||||
|
||||
int test_catch(void (*f)())
|
||||
{
|
||||
try
|
||||
{
|
||||
f();
|
||||
return 1;
|
||||
}
|
||||
catch( leaf::error_id const & )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
void test_single_thread()
|
||||
{
|
||||
BOOST_TEST_EQ(test_result(hidden_result2, true), 0);
|
||||
BOOST_TEST_EQ(test_result(hidden_result1, true), 0);
|
||||
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
BOOST_TEST_EQ(test_exception(hidden_throw1, true), 0);
|
||||
BOOST_TEST_EQ(test_catch(hidden_throw1), 0);
|
||||
BOOST_TEST_EQ(test_exception(hidden_throw2, true), 0);
|
||||
BOOST_TEST_EQ(test_catch(hidden_throw2), 0);
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
}
|
||||
|
||||
void test_multithreaded()
|
||||
{
|
||||
constexpr int N = 100;
|
||||
{
|
||||
std::mutex mtx;
|
||||
std::condition_variable cv;
|
||||
bool ready = false;
|
||||
auto test_function = [&]
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
cv.wait(lock, [&]{ return ready; });
|
||||
lock.unlock();
|
||||
int result1 = test_result(hidden_result1, false);
|
||||
int result2 = test_result(hidden_result2, false);
|
||||
return result1 + result2;
|
||||
};
|
||||
std::vector<std::future<int>> futures;
|
||||
for (int i = 0; i < N; ++i)
|
||||
futures.push_back(std::async(std::launch::async, test_function));
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
ready = true;
|
||||
}
|
||||
cv.notify_all();
|
||||
for (auto start = std::chrono::steady_clock::now(); std::chrono::steady_clock::now() - start < std::chrono::seconds(1); )
|
||||
if ((std::rand() % 2) == 0 || futures.empty())
|
||||
futures.push_back(std::async(std::launch::async, test_function));
|
||||
else
|
||||
{
|
||||
BOOST_TEST_EQ(futures.back().get(), 0);
|
||||
futures.pop_back();
|
||||
}
|
||||
for (auto & f : futures)
|
||||
BOOST_TEST_EQ(f.get(), 0);
|
||||
}
|
||||
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
{
|
||||
std::mutex mtx;
|
||||
std::condition_variable cv;
|
||||
bool ready = false;
|
||||
auto test_function = [&]
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
cv.wait(lock, [&]{ return ready; });
|
||||
lock.unlock();
|
||||
int result1 = test_exception(hidden_throw1, false);
|
||||
int result2 = test_catch(hidden_throw1);
|
||||
int result3 = test_exception(hidden_throw2, false);
|
||||
int result4 = test_catch(hidden_throw2);
|
||||
return result1 + result2 + result3 + result4;
|
||||
};
|
||||
std::vector<std::future<int>> futures;
|
||||
for (int i = 0; i < N; ++i)
|
||||
futures.push_back(std::async(std::launch::async, test_function));
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
ready = true;
|
||||
}
|
||||
cv.notify_all();
|
||||
for (auto start = std::chrono::steady_clock::now(); std::chrono::steady_clock::now() - start < std::chrono::seconds(1); )
|
||||
if ((std::rand() % 2) == 0 || futures.empty())
|
||||
futures.push_back(std::async(std::launch::async, test_function));
|
||||
else
|
||||
{
|
||||
BOOST_TEST_EQ(futures.back().get(), 0);
|
||||
futures.pop_back();
|
||||
}
|
||||
for (auto & f : futures)
|
||||
BOOST_TEST_EQ(f.get(), 0);
|
||||
}
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::srand(std::hash<unsigned>{}(static_cast<unsigned>(std::time(nullptr))));
|
||||
|
||||
test_single_thread();
|
||||
test_multithreaded();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,15 +1,20 @@
|
||||
#ifndef VISIBILITY_TEST_LIB_HPP_INCLUDED
|
||||
#define VISIBILITY_TEST_LIB_HPP_INCLUDED
|
||||
#ifndef SO_DLL_TEST_HPP_INCLUDED
|
||||
#define SO_DLL_TEST_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <iosfwd>
|
||||
#include <boost/leaf/config.hpp>
|
||||
|
||||
#if defined(_WIN32) && BOOST_LEAF_CFG_WIN32 < 2
|
||||
# error This test requires BOOST_LEAF_CFG_WIN32 >= 2
|
||||
#endif
|
||||
|
||||
// Note, under BOOST_LEAF_CFG_WIN32==2 (using Win32 TLS) we do not need
|
||||
// import/export for error types. We still need default visibility on POSIX.
|
||||
template <int Tag>
|
||||
struct BOOST_SYMBOL_VISIBLE my_info
|
||||
struct [[gnu::visibility("default")]] my_info
|
||||
{
|
||||
int value;
|
||||
|
||||
@@ -21,3 +26,4 @@ struct BOOST_SYMBOL_VISIBLE my_info
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -58,9 +58,9 @@ int main()
|
||||
BOOST_TEST(std::get<0>(t).value() == E1::e12);
|
||||
BOOST_TEST(std::get<2>(t).value() == E3::e31);
|
||||
}
|
||||
#endif
|
||||
#endif // #if !defined(__clang__) || __clang_major__ < 5 || __clang_major__ > 7
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if __cplusplus < 201703L
|
||||
|
||||
@@ -87,7 +87,7 @@ int main()
|
||||
} );
|
||||
BOOST_TEST_EQ(r1, 1);
|
||||
}
|
||||
#endif
|
||||
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
{
|
||||
leaf::result<void> r = leaf::try_capture_all(
|
||||
[]() -> leaf::result<void>
|
||||
@@ -147,4 +147,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if !BOOST_LEAF_CFG_CAPTURE
|
||||
|
||||
@@ -52,4 +52,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
@@ -147,4 +147,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #if defined(BOOST_LEAF_NO_EXCEPTIONS) || !BOOST_LEAF_CFG_STD_SYSTEM_ERROR
|
||||
|
||||
@@ -613,4 +613,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
@@ -705,4 +705,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifdef BOOST_LEAF_NO_EXCEPTIONS
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
|
||||
# include "leaf.hpp"
|
||||
#else
|
||||
# include <boost/leaf/diagnostics.hpp>
|
||||
# include <boost/leaf/result.hpp>
|
||||
#endif
|
||||
|
||||
#include "visibility_test_lib.hpp"
|
||||
|
||||
#if BOOST_LEAF_CFG_STD_STRING
|
||||
# include <sstream>
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
#include "lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
leaf::result<void> hidden_result();
|
||||
void hidden_throw();
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
int r = leaf::try_handle_all(
|
||||
[]() -> leaf::result<int>
|
||||
{
|
||||
BOOST_LEAF_CHECK(hidden_result());
|
||||
return 0;
|
||||
},
|
||||
[]( my_info<1> x1, my_info<2> x2, leaf::diagnostic_details const & info, leaf::diagnostic_details const & vinfo )
|
||||
{
|
||||
BOOST_TEST_EQ(x1.value, 1);
|
||||
BOOST_TEST_EQ(x2.value, 2);
|
||||
if( BOOST_LEAF_CFG_DIAGNOSTICS )
|
||||
{
|
||||
#if BOOST_LEAF_CFG_STD_STRING
|
||||
std::ostringstream ss; ss << vinfo;
|
||||
std::string s = ss.str();
|
||||
std::cout << s << std::endl;
|
||||
if( BOOST_LEAF_CFG_DIAGNOSTICS && BOOST_LEAF_CFG_CAPTURE )
|
||||
BOOST_TEST_NE(s.find("Test my_info<3>::value = 3"), std::string::npos);
|
||||
#endif
|
||||
}
|
||||
return 1;
|
||||
},
|
||||
[](leaf::diagnostic_details const & vinfo)
|
||||
{
|
||||
std::cout << "Test is failing\n" << vinfo;
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 1);
|
||||
}
|
||||
|
||||
#ifndef BOOST_LEAF_NO_EXCEPTIONS
|
||||
{
|
||||
int r = leaf::try_catch(
|
||||
[]
|
||||
{
|
||||
hidden_throw();
|
||||
return 0;
|
||||
},
|
||||
[]( my_info<1> x1, my_info<2> x2, leaf::diagnostic_details const & info, leaf::diagnostic_details const & vinfo )
|
||||
{
|
||||
BOOST_TEST_EQ(x1.value, 1);
|
||||
BOOST_TEST_EQ(x2.value, 2);
|
||||
if( BOOST_LEAF_CFG_DIAGNOSTICS )
|
||||
{
|
||||
#if BOOST_LEAF_CFG_STD_STRING
|
||||
std::ostringstream ss; ss << vinfo;
|
||||
std::string s = ss.str();
|
||||
std::cout << s << std::endl;
|
||||
if( BOOST_LEAF_CFG_DIAGNOSTICS && BOOST_LEAF_CFG_CAPTURE )
|
||||
BOOST_TEST_NE(s.find("Test my_info<3>::value = 3"), std::string::npos);
|
||||
#endif
|
||||
}
|
||||
return 1;
|
||||
},
|
||||
[](leaf::diagnostic_details const & vinfo)
|
||||
{
|
||||
std::cout << "Test is failing\n" << vinfo;
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 1);
|
||||
}
|
||||
{
|
||||
try
|
||||
{
|
||||
hidden_throw();
|
||||
BOOST_ERROR("hidden_throw() failed to throw");
|
||||
}
|
||||
catch( leaf::error_id const & )
|
||||
{
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
BOOST_ERROR("Failed to catch leaf::error_id");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
2
wasm.txt
2
wasm.txt
@@ -1,4 +1,4 @@
|
||||
# Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
|
||||
# Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
|
||||
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Reference in New Issue
Block a user