mirror of
https://github.com/boostorg/leaf.git
synced 2026-01-30 07:52:13 +00:00
Merge branch 'feature/try_' of https://github.com/zajo/leaf
This commit is contained in:
@@ -231,7 +231,7 @@ install:
|
||||
- gem install coderay
|
||||
# - pip3 install meson
|
||||
- cd ..
|
||||
- git clone -b $TRAVIS_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
- git clone -b master --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
- cd boost-root
|
||||
- git submodule update --init tools/build
|
||||
- git submodule update --init tools/inspect
|
||||
|
||||
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -8,8 +8,8 @@
|
||||
"name": "(lldb) Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/bld/debug/preload_test.2",
|
||||
"args": [ "test/Jafile.v2" ],
|
||||
"program": "${workspaceFolder}/bld/debug/result_state_test",
|
||||
"args": [ ],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": false,
|
||||
|
||||
288
.vscode/tasks.json
vendored
288
.vscode/tasks.json
vendored
@@ -24,192 +24,129 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "basic_test",
|
||||
"label": "capture_exception_async_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test basic_test",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test capture_exception_async_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test basic_test"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test capture_exception_async_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "defer_test.1",
|
||||
"label": "capture_exception_state_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_test.1",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test capture_exception_state_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_test.1"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test capture_exception_state_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "defer_test.2",
|
||||
"label": "capture_exception_unload_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_test.2",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test capture_exception_unload_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_test.2"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test capture_exception_unload_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "defer_test.3",
|
||||
"label": "capture_result_async_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_test.3",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test capture_result_async_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_test.3"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test capture_result_async_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "defer_test.4",
|
||||
"label": "capture_result_state_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_test.4",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test capture_result_state_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_test.4"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test capture_result_state_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "defer_test.5",
|
||||
"label": "capture_result_unload_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_test.5",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test capture_result_unload_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_test.5"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test capture_result_unload_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "defer_test.6",
|
||||
"label": "defer_basic_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_test.6",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_basic_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_test.6"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_basic_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "defer_test.7",
|
||||
"label": "defer_nested_error_exception_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_test.7",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_nested_error_exception_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_test.7"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_nested_error_exception_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "defer_test.8",
|
||||
"label": "defer_nested_error_result_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_test.8",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_nested_error_result_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_test.8"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_nested_error_result_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "diagnostic_output_test",
|
||||
"label": "defer_nested_new_error_exception_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test diagnostic_output_test",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_nested_new_error_exception_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test diagnostic_output_test"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_nested_new_error_exception_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "error_capture_test.1",
|
||||
"label": "defer_nested_new_error_result_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test error_capture_test.1",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_nested_new_error_result_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test error_capture_test.1"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_nested_new_error_result_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "error_capture_test.2",
|
||||
"label": "defer_nested_success_exception_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test error_capture_test.2",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_nested_success_exception_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test error_capture_test.2"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_nested_success_exception_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "error_test",
|
||||
"label": "defer_nested_success_result_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test error_test",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test defer_nested_success_result_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test error_test"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test defer_nested_success_result_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "exception_capture_test",
|
||||
"label": "diagnostic_info_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test exception_capture_test",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test diagnostic_info_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test exception_capture_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "exception_test.1",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test exception_test.1",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test exception_test.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "exception_test.2",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test exception_test.2",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test exception_test.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "expect_test.1",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test expect_test.1",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test expect_test.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "expect_test.2",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test expect_test.2",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test expect_test.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "expect_test.3",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test expect_test.3",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test expect_test.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "expect_test.4",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test expect_test.4",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test expect_test.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "expect_test.5",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test expect_test.5",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test expect_test.5"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test diagnostic_info_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -221,6 +158,33 @@
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test function_traits_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "handle_all_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test handle_all_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test handle_all_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "handle_some_basic_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test handle_some_basic_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test handle_some_basic_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "handle_some_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test handle_some_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test handle_some_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "is_error_type_test",
|
||||
"type": "shell",
|
||||
@@ -230,82 +194,76 @@
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test is_error_type_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "multiple_errors_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test multiple_errors_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test multiple_errors_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "optional_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test optional_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] }
|
||||
},
|
||||
{
|
||||
"label": "preload_test.1",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_test.1",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test optional_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "preload_test.2",
|
||||
"label": "preload_basic_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_test.2",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_basic_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test preload_test.2"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test preload_basic_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "preload_test.3",
|
||||
"label": "preload_nested_error_exception_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_test.3",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_nested_error_exception_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test preload_test.3"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test preload_nested_error_exception_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "preload_test.4",
|
||||
"label": "preload_nested_error_result_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_test.4",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_nested_error_result_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test preload_test.4"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test preload_nested_error_result_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "preload_test.5",
|
||||
"label": "preload_nested_new_error_exception_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_test.5",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_nested_new_error_exception_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test preload_test.5"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test preload_nested_new_error_exception_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "preload_test.6",
|
||||
"label": "preload_nested_new_error_result_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_test.6",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_nested_new_error_result_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test preload_test.6"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test preload_nested_new_error_result_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "preload_test.7",
|
||||
"label": "preload_nested_success_exception_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_test.7",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_nested_success_exception_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test preload_test.7"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test preload_nested_success_exception_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "preload_nested_success_result_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test preload_nested_success_result_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test preload_nested_success_result_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -318,75 +276,57 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "result_capture_test",
|
||||
"label": "result_bad_result_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test result_capture_test",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test result_bad_result_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test result_capture_test"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test result_bad_result_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "result_test.1",
|
||||
"label": "result_state_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test result_test.1",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test result_state_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test result_test.1"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test result_state_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "result_test.2",
|
||||
"label": "static_store_deduction_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test result_test.2",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test static_store_deduction_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test result_test.2"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test static_store_deduction_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "result_test.3",
|
||||
"label": "static_store_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test result_test.3",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test static_store_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test result_test.3"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test static_store_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "result_test.4",
|
||||
"label": "try_exception_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test result_test.4",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test try_exception_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test result_test.4"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test try_exception_test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "result_test.5",
|
||||
"label": "try_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test result_test.5",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test try_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test result_test.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "result_test.6",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test result_test.6",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test result_test.6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "result_void_capture_test",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceRoot}/bld/debug && meson test result_void_capture_test",
|
||||
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
|
||||
"windows": {
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test result_void_capture_test"
|
||||
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test try_test"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
3769
doc/leaf.adoc
3769
doc/leaf.adoc
File diff suppressed because it is too large
Load Diff
10
doc/synopses/capture_exception.adoc
Normal file
10
doc/synopses/capture_exception.adoc
Normal file
@@ -0,0 +1,10 @@
|
||||
[source,c++]
|
||||
.#include <boost/leaf/capture_exception.hpp>
|
||||
----
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class... E, class F>
|
||||
<<unspecified_function_type>> capture_exception( F && f ) noexcept;
|
||||
|
||||
} }
|
||||
----
|
||||
10
doc/synopses/capture_result.adoc
Normal file
10
doc/synopses/capture_result.adoc
Normal file
@@ -0,0 +1,10 @@
|
||||
[source,c++]
|
||||
.#include <boost/leaf/capture_result.hpp>
|
||||
----
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class... E, class F>
|
||||
<<unspecified_function_type>> capture_result( F && f ) noexcept;
|
||||
|
||||
} }
|
||||
----
|
||||
@@ -3,54 +3,20 @@
|
||||
----
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
struct e_api_function { char const * value; };
|
||||
|
||||
struct e_file_name { std::string value; };
|
||||
|
||||
struct e_errno
|
||||
{
|
||||
int value;
|
||||
friend std::ostream & operator<<( std::ostream & os, e_errno const & err );
|
||||
};
|
||||
struct e_api_function { .... };
|
||||
struct e_file_name { .... };
|
||||
struct e_errno { .... };
|
||||
struct e_at_line { .... };
|
||||
struct e_type_info_name { .... };
|
||||
struct e_source_location { .... };
|
||||
|
||||
namespace windows
|
||||
{
|
||||
struct e_LastError
|
||||
{
|
||||
unsigned value;
|
||||
};
|
||||
struct e_LastError { .... };
|
||||
}
|
||||
|
||||
struct e_at_line { int value; };
|
||||
|
||||
struct e_type_info_name { char const * value; };
|
||||
|
||||
struct e_source_location
|
||||
{
|
||||
char const * const file;
|
||||
int const line;
|
||||
char const * const function;
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, e_source_location const & x );
|
||||
};
|
||||
|
||||
struct e_unexpected
|
||||
{
|
||||
char const * (*first_type)();
|
||||
int count;
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, e_unexpected const & x );
|
||||
};
|
||||
|
||||
struct e_unexpected_diagnostic_output
|
||||
{
|
||||
<<unspecified>>
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, e_unexpected_diagnostic_output const & x );
|
||||
};
|
||||
|
||||
} }
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
<<e_api_function>> | <<e_file_name>> | <<e_errno>> | <<e_LastError>> | <<e_at_line>> | <<e_type_info_name>> | <<e_source_location>> | <<e_unexpected>> | <<e_unexpected_diagnostic_output>>
|
||||
<<e_api_function>> | <<e_file_name>> | <<e_errno>> | <<e_LastError>> | <<e_at_line>> | <<e_type_info_name>> | <<e_source_location>>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
.#include <boost/leaf/diagnostic_output_current_exception.hpp>
|
||||
[source,c++]
|
||||
----
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class... E>
|
||||
void diagnostic_output_current_exception( std::ostream & os, expect<E...> const & exp );
|
||||
|
||||
} }
|
||||
----
|
||||
@@ -3,26 +3,28 @@
|
||||
----
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
class error
|
||||
class error_id;
|
||||
|
||||
template <class... E>
|
||||
error_id new_error( E && ... e ) noexcept;
|
||||
|
||||
error_id next_error() noexcept;
|
||||
|
||||
error_id last_error() noexcept;
|
||||
|
||||
class error_id
|
||||
{
|
||||
public:
|
||||
|
||||
template <class... E>
|
||||
explicit error( E && ... e ) noexcept:
|
||||
error_id propagate( E && ... e ) const noexcept;
|
||||
|
||||
template <class... E>
|
||||
error propagate( E && ... e ) const noexcept;
|
||||
friend bool operator==( error_id const & e1, error_id const & e2 ) noexcept;
|
||||
friend bool operator!=( error_id const & e1, error_id const & e2 ) noexcept;
|
||||
|
||||
friend bool operator==( error const & e1, error const & e2 ) noexcept;
|
||||
friend bool operator!=( error const & e1, error const & e2 ) noexcept;
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, error const & e )
|
||||
friend std::ostream & operator<<( std::ostream & os, error_id const & e )
|
||||
};
|
||||
|
||||
error next_error_value() noexcept;
|
||||
|
||||
error last_error_value() noexcept;
|
||||
|
||||
template <class T>
|
||||
struct is_error_type
|
||||
{
|
||||
@@ -33,4 +35,4 @@ namespace boost { namespace leaf {
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
`<<error,error>>` | <<error::error>> | <<error::propagate>> | <<operator_eq-error>> | <<operator_neq-error>> | <<operator_shl-error>> | <<next_error_value>> | <<last_error_value>>
|
||||
<<error_id>> | <<new_error>> | <<next_error>> | <<last_error>> | <<propagate>> | <<operator_eq-error_id>> | <<operator_neq-error_id>> | <<operator_shl-error_id>> | <<is_error_type>>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
.#include <boost/leaf/error_capture.hpp>
|
||||
[source,c++]
|
||||
----
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
class error_capture
|
||||
{
|
||||
public:
|
||||
|
||||
error_capture() noexcept;
|
||||
|
||||
explicit operator bool() const noexcept;
|
||||
|
||||
error unload() noexcept;
|
||||
};
|
||||
|
||||
template <class... F>
|
||||
<<deduced_return_type>> handle_error( error_capture const & ec, F && ... f ) noexcept;
|
||||
|
||||
template <class P>
|
||||
P const * peek( error_capture const & ec ) noexcept;
|
||||
|
||||
void diagnostic_output( std::ostream & os, error_capture const & ec );
|
||||
|
||||
} }
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
`<<error_capture,error_capture>>` | <<error_capture::error_capture>> | <<error_capture::operator_bool>> | <<error_capture::unload>> | <<handle_error-error_capture>> | <<peek-error_capture>> | <<diagnostic_output-error_capture>>
|
||||
@@ -1,28 +0,0 @@
|
||||
[source,c++]
|
||||
.#include <boost/leaf/exception.hpp>
|
||||
----
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class Ex, class... E>
|
||||
<<unspecified>> exception( Ex && ex, E... && e ) noexcept;
|
||||
|
||||
error get_error( std::exception const & ex ) noexcept;
|
||||
|
||||
template <class P, class... E>
|
||||
P const * peek( expect<E...> const & exp, std::exception const & ex ) noexcept;
|
||||
|
||||
template <class... E, class... F>
|
||||
void handle_exception( expect<E...> & exp, std::exception const & ex, F && ... f );
|
||||
|
||||
template <class... E>
|
||||
void diagnostic_output( std::ostream & os, expect<E...> const & exp, std::exception const & ex );
|
||||
|
||||
} }
|
||||
|
||||
#define LEAF_EXCEPTION(...) <<unspecified>>
|
||||
|
||||
#define LEAF_THROW(...) throw LEAF_EXCEPTION(__VA_ARGS__)
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
<<exception>> | <<get_error>> | <<peek-exception>> | <<handle_exception>> | <<diagnostic_output-exception>> | <<LEAF_EXCEPTION>> | <<LEAF_THROW>>
|
||||
@@ -1,17 +0,0 @@
|
||||
[source,c++]
|
||||
.#include <boost/leaf/exception_capture.hpp>
|
||||
----
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class... E, class F>
|
||||
<<unspecified>> capture_exception( F && f ) noexcept;
|
||||
|
||||
template <class Future>
|
||||
decltype(std::declval<Future>().get()) get( Future && f );
|
||||
|
||||
} }
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
<<capture_exception>> | <<get>>
|
||||
|
||||
10
doc/synopses/exception_to_result.adoc
Normal file
10
doc/synopses/exception_to_result.adoc
Normal file
@@ -0,0 +1,10 @@
|
||||
[source,c++]
|
||||
.#include <boost/leaf/exception_to_result.hpp>
|
||||
----
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class... Ex, class F>
|
||||
<<deduced-type>> exception_to_result( F && f ) noexcept;
|
||||
|
||||
} }
|
||||
----
|
||||
@@ -1,40 +0,0 @@
|
||||
.#include <boost/leaf/expect.hpp>
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class... E>
|
||||
class expect
|
||||
{
|
||||
public:
|
||||
|
||||
expect() noexcept;
|
||||
~expect() noexcept;
|
||||
};
|
||||
|
||||
template <class... E>
|
||||
error_capture capture( expect<E...> & exp, error const & e );
|
||||
|
||||
template <class R>
|
||||
struct uhnandled_error
|
||||
{
|
||||
static constexpr R value( error const & ) noexcept;
|
||||
};
|
||||
|
||||
template <class... E, class... F>
|
||||
<<deduced_return_type>> handle_error( expect<E...> const & exp, error const & e, F && ... f ) noexcept;
|
||||
|
||||
template <class P, class... E>
|
||||
P const * peek( expect<E...> const & exp, error const & e ) noexcept;
|
||||
|
||||
template <class... E>
|
||||
void diagnostic_output( std::ostream & os, expect<E...> const & exp );
|
||||
|
||||
template <class... E>
|
||||
void diagnostic_output( std::ostream & os, expect<E...> const & exp, error const & e );
|
||||
|
||||
} }
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
<<expect::expect>> | <<expect-dtor>> | <<expect::propagate>> | <<capture-expect>> | <<handle_error-expect>> | <<peek-expect>> | <<diagnostic_output-expect>>
|
||||
21
doc/synopses/handle.adoc
Normal file
21
doc/synopses/handle.adoc
Normal file
@@ -0,0 +1,21 @@
|
||||
.#include <boost/leaf/handle.hpp>
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class TryBlock, class... Handler>
|
||||
typename std::remove_reference<decltype(std::declval<TryBlock>()().value())>::type
|
||||
handle_all( TryBlock && try_block, Handler && ... handler );
|
||||
|
||||
template <class TryBlock, class... Handler>
|
||||
decltype(std::declval<TryBlock>()())
|
||||
handle_some( TryBlock && try_block, Handler && ... handler );
|
||||
|
||||
template <class E, typename deduced-type<E>::type... V>
|
||||
struct match;
|
||||
|
||||
} }
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
<<handle_all>> | <<handle_some>> | <<match>>
|
||||
@@ -9,44 +9,48 @@ namespace boost { namespace leaf {
|
||||
public:
|
||||
|
||||
result() noexcept;
|
||||
result( T const & v );
|
||||
result( T && v ) noexcept;
|
||||
result( leaf::error const & e ) noexcept;
|
||||
result( leaf::error_capture const & ec ) noexcept;
|
||||
result( T const & v );
|
||||
result( error_id const & err ) noexcept;
|
||||
|
||||
result( result && r ) noexcept;
|
||||
result( result const & r );
|
||||
|
||||
template <class U>
|
||||
result( result<U> && r ) noexcept
|
||||
|
||||
template <class U>
|
||||
result( result<U> const & r )
|
||||
|
||||
result & operator=( result && r ) noexcept;
|
||||
result & operator=( result const & r );
|
||||
|
||||
template <class U>
|
||||
result & operator=( result<U> && r ) noexcept
|
||||
|
||||
template <class U>
|
||||
result & operator=( result<U> const & r )
|
||||
|
||||
explicit operator bool() const noexcept;
|
||||
|
||||
T const & value() const;
|
||||
T & value();
|
||||
|
||||
T const & operator*() const;
|
||||
T & operator*();
|
||||
|
||||
template <class... E>
|
||||
leaf::error error( E && ... e ) noexcept;
|
||||
error_id error( E && ... e ) noexcept;
|
||||
};
|
||||
|
||||
template <class... E, class T>
|
||||
result<T> capture( expect<E...> & exp, result<T> const & r );
|
||||
|
||||
template <class... E, class T, class... F>
|
||||
<<deduced_return_type>> handle_error( expect<E...> const & exp, result<T> const & r, F && ... f ) noexcept;
|
||||
|
||||
template <class P, class... E, class T>
|
||||
P const * peek( expect<E...> const &, result<T> const & ) noexcept;
|
||||
|
||||
template <class... E, class T>
|
||||
void diagnostic_output( std::ostream & os, expect<E...> const & exp, result<T> const & r );
|
||||
|
||||
struct bad_result: std::exception { };
|
||||
|
||||
} }
|
||||
|
||||
#define LEAF_ERROR(...) <<unspecified>>
|
||||
|
||||
#define LEAF_AUTO(v,r) auto _r_##v = r; if( !_r_##v ) return _r_##v.error(); auto & v = *_r_##v
|
||||
|
||||
#define LEAF_CHECK(r) {auto _r = r; if( !_r ) return _r.error();}
|
||||
#define LEAF_ERROR(...) ....
|
||||
#define LEAF_AUTO(v,r) ....
|
||||
#define LEAF_CHECK(r) ....
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
`<<result,result>>` | <<result::result>> | <<result::operator_bool>> | <<result::value>> | <<result::error>> | <<capture-result>> | <<handle_error-result>> | <<peek-result>> | <<diagnostic_output-result>> | <<bad_result>> | <<LEAF_ERROR>> | <<LEAF_AUTO>> | <<LEAF_CHECK>>
|
||||
<<result>> | <<result::result>> | <<result::operator_eq>> | <<result::operator_bool>> | <<result::value>> | <<result::error>> | <<bad_result>> | <<LEAF_ERROR>> | <<LEAF_AUTO>> | <<LEAF_CHECK>>
|
||||
|
||||
17
doc/synopses/throw.adoc
Normal file
17
doc/synopses/throw.adoc
Normal file
@@ -0,0 +1,17 @@
|
||||
.#include <boost/leaf/throw.hpp>
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class Ex, class... E>
|
||||
<<unspecified>> exception( Ex && ex, E && ... e ) noexcept;
|
||||
|
||||
} }
|
||||
|
||||
#define LEAF_EXCEPTION(...) ....
|
||||
|
||||
#define LEAF_THROW(...) ....
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
<<exception>> | <<LEAF_EXCEPTION>> | <<LEAF_THROW>>
|
||||
21
doc/synopses/try.adoc
Normal file
21
doc/synopses/try.adoc
Normal file
@@ -0,0 +1,21 @@
|
||||
.#include <boost/leaf/try.hpp>
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class TryBlock, class... Handler>
|
||||
decltype(std::declval<TryBlock>()()) try_( TryBlock && try_block, Handler && ... handler );
|
||||
|
||||
template <class E, typename deduced-type<E>::type... V>
|
||||
struct match;
|
||||
|
||||
template <class... Ex>
|
||||
struct catch_;
|
||||
|
||||
error_id get_error_id( std::exception const & ex ) noexcept;
|
||||
|
||||
} }
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
<<try_>> | <<match>> | <<catch_>> | <<get_error_id>>
|
||||
@@ -1,14 +1,15 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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 is a simple program that demonstrates the use of LEAF to transport e-objects between threads,
|
||||
//when using exception handling to report failures. See capture_result.cpp for the variant that doesn't
|
||||
//use exception handling.
|
||||
// This is a simple program that demonstrates the use of LEAF to transport e-objects between threads,
|
||||
// without using exception handling. See capture_eh.cpp for the exception-handling variant.
|
||||
|
||||
#include <boost/leaf/all.hpp>
|
||||
#include <boost/leaf/capture_exception.hpp>
|
||||
#include <boost/leaf/try.hpp>
|
||||
#include <boost/leaf/throw.hpp>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <future>
|
||||
@@ -18,84 +19,72 @@
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
//Define several e-types.
|
||||
// Define several e-types.
|
||||
struct e_thread_id { std::thread::id value; };
|
||||
struct e_failure_info1 { std::string value; };
|
||||
struct e_failure_info2 { int value; };
|
||||
struct e_failure_info3 { long value; };
|
||||
struct e_failure_info4 { float value; };
|
||||
|
||||
//A type that represents a successfully returned result from a task.
|
||||
// A type that represents a successfully returned result from a task.
|
||||
struct task_result { };
|
||||
|
||||
//An exception type thrown in case of task failure.
|
||||
struct failure : virtual std::exception { };
|
||||
|
||||
//This is a test task which succeeds or fails depending on its argument. In case of success, it returns
|
||||
//task_result, in case of error it throws failure.
|
||||
task_result task( bool succeed )
|
||||
// This is our task function. It produces objects of type task_result, but it may fail...
|
||||
task_result task()
|
||||
{
|
||||
bool succeed = (rand()%4) !=0; //...at random.
|
||||
if( succeed )
|
||||
return task_result(); //Simulate successful result.
|
||||
return task_result { };
|
||||
else
|
||||
throw leaf::exception(
|
||||
failure(),
|
||||
throw leaf::exception( std::exception(),
|
||||
e_thread_id{std::this_thread::get_id()},
|
||||
e_failure_info1{"info"},
|
||||
e_failure_info2{42},
|
||||
e_failure_info4{42} );
|
||||
}
|
||||
|
||||
//Launch the specified number of asynchronous tasks. In case an asynchronous task throws, its e-objects
|
||||
//(of the type list used to instantiate leaf::capture_exception) are captured and wrapped in a different
|
||||
//exception, which transports it to the main thread. The original exception is then recovered by leaf::get.
|
||||
template <class... E>
|
||||
std::vector<std::future<task_result>> launch_async_tasks( int thread_count )
|
||||
{
|
||||
std::vector<std::future<task_result>> fut;
|
||||
std::generate_n( std::inserter(fut,fut.end()), thread_count, [ ]
|
||||
{
|
||||
return std::async( std::launch::async,
|
||||
leaf::capture_exception<E...>( [ ] //returns a wrapper function for the lambda...
|
||||
{
|
||||
return task((rand()%4)!=0); //...which transports the E... objects.
|
||||
} ) );
|
||||
} );
|
||||
return fut;
|
||||
}
|
||||
e_failure_info2{42} );
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
//Launch tasks, transport the specified e-types. For demonstration, note that the task provides
|
||||
//failure_info4 which we don't care about, and that we say we could use failure_info3, but which the
|
||||
//task doesn't provide. So, we'll only get failed_thread_id, failure_info1 and failure_info2.
|
||||
auto fut = launch_async_tasks<e_thread_id, e_failure_info1, e_failure_info2, e_failure_info3>(42);
|
||||
int const task_count = 42;
|
||||
|
||||
//Collect results or deal with failures.
|
||||
// Container to collect the generated std::future objects.
|
||||
std::vector<std::future<task_result>> fut;
|
||||
|
||||
// Launch the tasks, but rather than launching the task function directly, we launch the
|
||||
// wrapper function returned by leaf::capture_result. It captures the specified error object
|
||||
// types and automatically transports them in the leaf::result<task_result> it returns.
|
||||
std::generate_n( std::inserter(fut,fut.end()), task_count,
|
||||
[ ]
|
||||
{
|
||||
return std::async(
|
||||
std::launch::async,
|
||||
leaf::capture_exception<e_thread_id, e_failure_info1, e_failure_info2>(&task) );
|
||||
} );
|
||||
|
||||
// Wait on the futures, get the task results, handle errors.
|
||||
for( auto & f : fut )
|
||||
{
|
||||
f.wait();
|
||||
|
||||
//Storage for e-objects.
|
||||
leaf::expect<e_thread_id, e_failure_info1, e_failure_info2, e_failure_info3> exp;
|
||||
leaf::try_(
|
||||
[&]
|
||||
{
|
||||
task_result r = f.get();
|
||||
|
||||
try
|
||||
{
|
||||
//Instead of calling future::get we pass the future object to leaf::get. In case the future finished with an exception,
|
||||
//this will rethrow that exception, after dropping any captured e-objects into exp.
|
||||
task_result r = leaf::get(f);
|
||||
// Success! Use r to access task_result.
|
||||
std::cout << "Success!" << std::endl;
|
||||
(void) r;
|
||||
|
||||
//Success!
|
||||
std::cout << "Success!" << std::endl;
|
||||
}
|
||||
catch( failure const & e )
|
||||
{
|
||||
//Failure! Handle the error, print failure info.
|
||||
handle_exception( exp, e,
|
||||
[ ] ( e_failure_info1 const & v1, e_failure_info2 const & v2, e_thread_id const & tid )
|
||||
{
|
||||
std::cerr << "Error in thread " << tid.value << "! failure_info1: " << v1.value << ", failure_info2: " << v2.value << std::endl;
|
||||
} );
|
||||
}
|
||||
},
|
||||
|
||||
[ ]( e_failure_info1 const & v1, e_failure_info2 const & v2, e_thread_id const & tid )
|
||||
{
|
||||
std::cerr << "Error in thread " << tid.value << "! failure_info1: " << v1.value << ", failure_info2: " << v2.value << std::endl;
|
||||
},
|
||||
|
||||
[ ]( leaf::error_info const & unmatched )
|
||||
{
|
||||
std::cerr <<
|
||||
"Unknown failure detected" << std::endl <<
|
||||
"Cryptic diagnostic information follows" << std::endl <<
|
||||
unmatched;
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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 is a simple program that demonstrates the use of LEAF to transport e-objects between threads,
|
||||
//without using exception handling. See capture_eh.cpp for the exception-handling variant.
|
||||
// This is a simple program that demonstrates the use of LEAF to transport e-objects between threads,
|
||||
// without using exception handling. See capture_eh.cpp for the exception-handling variant.
|
||||
|
||||
#include <boost/leaf/capture_result.hpp>
|
||||
#include <boost/leaf/handle.hpp>
|
||||
|
||||
#include <boost/leaf/all.hpp>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <future>
|
||||
@@ -17,76 +19,72 @@
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
//Define several e-types.
|
||||
// Define several e-types.
|
||||
struct e_thread_id { std::thread::id value; };
|
||||
struct e_failure_info1 { std::string value; };
|
||||
struct e_failure_info2 { int value; };
|
||||
struct e_failure_info3 { long value; };
|
||||
struct e_failure_info4 { float value; };
|
||||
|
||||
//A type that represents a successfully returned result from a task.
|
||||
// A type that represents a successfully returned result from a task.
|
||||
struct task_result { };
|
||||
|
||||
//This is a test task which succeeds or fails depending on its argument.
|
||||
leaf::result<task_result> task( bool succeed )
|
||||
// This is our task function. It produces objects of type task_result, but it may fail...
|
||||
leaf::result<task_result> task()
|
||||
{
|
||||
bool succeed = (rand()%4) !=0; //...at random.
|
||||
if( succeed )
|
||||
return task_result(); //Simulate successful result.
|
||||
return task_result { };
|
||||
else
|
||||
return leaf::error(
|
||||
return leaf::new_error(
|
||||
e_thread_id{std::this_thread::get_id()},
|
||||
e_failure_info1{"info"},
|
||||
e_failure_info2{42},
|
||||
e_failure_info4{42} );
|
||||
}
|
||||
|
||||
//Launch the specified number of asynchronous tasks. In case an asynchronous task fails, its e-objects
|
||||
//(initially stored in exp) are captured in a leaf::result<task_result>, which transports them to the main thread.
|
||||
template <class... E>
|
||||
std::vector<std::future<leaf::result<task_result>>> launch_async_tasks( int thread_count )
|
||||
{
|
||||
std::vector<std::future<leaf::result<task_result>>> fut;
|
||||
std::generate_n( std::inserter(fut,fut.end()), thread_count, [ ]
|
||||
{
|
||||
return std::async( std::launch::async, [ ]
|
||||
{
|
||||
leaf::expect<E...> exp;
|
||||
return capture(exp,task((rand()%4)!=0));
|
||||
} );
|
||||
} );
|
||||
return fut;
|
||||
}
|
||||
e_failure_info2{42} );
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
//Launch tasks, transport the specified e-types. For demonstration, note that the task provides
|
||||
//failure_info4 which we don't care about, and that we say we could use failure_info3, but which
|
||||
//the task doesn't provide. So, we'll only get failed_thread_id, failure_info1 and failure_info2.
|
||||
auto fut = launch_async_tasks<e_thread_id, e_failure_info1, e_failure_info2, e_failure_info3>(42);
|
||||
int const task_count = 42;
|
||||
|
||||
//Collect results or deal with failures.
|
||||
// Container to collect the generated std::future objects.
|
||||
std::vector<std::future<leaf::result<task_result>>> fut;
|
||||
|
||||
// Launch the tasks, but rather than launching the task function directly, we launch the
|
||||
// wrapper function returned by leaf::capture_result. It captures the specified error object
|
||||
// types and automatically transports them in the leaf::result<task_result> it returns.
|
||||
std::generate_n( std::inserter(fut,fut.end()), task_count,
|
||||
[ ]
|
||||
{
|
||||
return std::async(
|
||||
std::launch::async,
|
||||
leaf::capture_result<e_thread_id, e_failure_info1, e_failure_info2>(&task) );
|
||||
} );
|
||||
|
||||
// Wait on the futures, get the task results, handle errors.
|
||||
for( auto & f : fut )
|
||||
{
|
||||
f.wait();
|
||||
|
||||
//Storage for e-objects.
|
||||
leaf::expect<e_thread_id, e_failure_info1, e_failure_info2, e_failure_info3> exp;
|
||||
leaf::handle_all(
|
||||
[&]() -> leaf::result<void>
|
||||
{
|
||||
LEAF_AUTO(r,f.get());
|
||||
|
||||
//Get the task result, check for success.
|
||||
if( leaf::result<task_result> r = f.get() )
|
||||
{
|
||||
//Success! Use *r to access task_result.
|
||||
std::cout << "Success!" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Failure! Handle error, print failure info.
|
||||
bool matched = handle_error( exp, r,
|
||||
[ ] ( e_failure_info1 const & v1, e_failure_info2 const & v2, e_thread_id const & tid )
|
||||
{
|
||||
std::cerr << "Error in thread " << tid.value << "! failure_info1: " << v1.value << ", failure_info2: " << v2.value << std::endl;
|
||||
} );
|
||||
assert(matched);
|
||||
}
|
||||
// Success! Use r to access task_result.
|
||||
std::cout << "Success!" << std::endl;
|
||||
(void) r;
|
||||
return { };
|
||||
},
|
||||
|
||||
[ ]( e_failure_info1 const & v1, e_failure_info2 const & v2, e_thread_id const & tid )
|
||||
{
|
||||
std::cerr << "Error in thread " << tid.value << "! failure_info1: " << v1.value << ", failure_info2: " << v2.value << std::endl;
|
||||
},
|
||||
|
||||
[ ]( leaf::error_info const & unmatched )
|
||||
{
|
||||
std::cerr <<
|
||||
"Unknown failure detected" << std::endl <<
|
||||
"Cryptic diagnostic information follows" << std::endl <<
|
||||
unmatched;
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
112
example/exception_to_result.cpp
Normal file
112
example/exception_to_result.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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 example demonstrates how to transport exceptions thrown by a low level function
|
||||
// through an intermediate context that is not exception-safe, to be handled in a high level
|
||||
// function which may or may not be exception-safe.
|
||||
|
||||
// An real-world example for this use case is when a C API (which may not throw) is implemented
|
||||
// using a C++ library that throws exceptions. As demonstrated below, these exception objects are
|
||||
// intercepted and reported by leaf::result<>.
|
||||
|
||||
#include <boost/leaf/all.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
|
||||
class error_base: public virtual std::exception { };
|
||||
class error_a: public virtual error_base { };
|
||||
class error_b: public virtual error_base { };
|
||||
class error_c: public virtual error_base { };
|
||||
|
||||
|
||||
// Lower-level library function which throws exceptions.
|
||||
int compute_answer_throws()
|
||||
{
|
||||
switch( rand()%4 )
|
||||
{
|
||||
default: return 42;
|
||||
case 1: throw error_a();
|
||||
case 2: throw error_b();
|
||||
case 3: throw error_c();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Calls compute_answer_throws, switches to result<int> for error handling.
|
||||
leaf::result<int> compute_answer() noexcept
|
||||
{
|
||||
// Convert exceptions of types error_a and error_b to be communicated by leaf::result.
|
||||
// Any other exception will be communicated as a std::exception_ptr.
|
||||
return leaf::exception_to_result<error_a, error_b>(
|
||||
[ ]
|
||||
{
|
||||
return compute_answer_throws();
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
// Print the answer if the call to compute_answer is successful.
|
||||
leaf::result<void> print_answer() noexcept
|
||||
{
|
||||
LEAF_AUTO( answer, compute_answer());
|
||||
std::cout << "Answer: " << answer << std::endl;
|
||||
return { };
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// Exercise print_answer a few times and handle errors. Note that the exception objects that
|
||||
// compute_answer_throws throws are handled as regular LEAF error objects...
|
||||
for( int i=0; i!=42; ++i )
|
||||
{
|
||||
leaf::handle_all(
|
||||
[ ]() -> leaf::result<void>
|
||||
{
|
||||
LEAF_CHECK(print_answer());
|
||||
return { };
|
||||
},
|
||||
|
||||
[ ]( error_a const & e )
|
||||
{
|
||||
std::cerr << "Error A!" << std::endl;
|
||||
},
|
||||
|
||||
[ ]( error_b const & e )
|
||||
{
|
||||
std::cerr << "Error B!" << std::endl;
|
||||
},
|
||||
|
||||
//...except for error_c errors, which (for demonstration) are captured as exceptions
|
||||
// into std::exception_ptr as "unknown" exception. Presumably this should not
|
||||
// happen, therefore at this point we treat this situation a logic error: we print
|
||||
// diagnostic information and bail out.
|
||||
[ ]( std::exception_ptr const * ep )
|
||||
{
|
||||
std::cerr << "Got unknown error!" << std::endl;
|
||||
|
||||
// Why do we take std::exception_ptr as a pointer? Because handle_all requires
|
||||
// that the last handler matches any error -- taken as a pointer, if there isn't a
|
||||
// std::exception_ptr associated with the error, the handler will still be matched
|
||||
//(with 0 passed for ep). Had we taken it by value or by const &, the program
|
||||
// would not compile.
|
||||
if( ep )
|
||||
leaf::try_(
|
||||
[&]
|
||||
{
|
||||
std::rethrow_exception(*ep);
|
||||
},
|
||||
[ ]( leaf::error_info const & unmatched )
|
||||
{
|
||||
std::cerr << unmatched << std::endl;
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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 is a simple program that shows how to propagate leaf::error objects out
|
||||
//of a C-callback, and converting them to leaf::result<T> as soon as control
|
||||
//reaches C++.
|
||||
// This is a simple program that shows how to propagate error objects out
|
||||
// of a C-callback, and converting them to leaf::result<T> as soon as control
|
||||
// reaches C++.
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
@@ -18,8 +18,6 @@ extern "C" {
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
struct lua_failure: std::exception { };
|
||||
|
||||
enum do_work_error_code
|
||||
{
|
||||
ec1=1,
|
||||
@@ -33,40 +31,40 @@ struct e_lua_pcall_error { int value; };
|
||||
struct e_lua_error_message { std::string value; };
|
||||
|
||||
|
||||
//This is a C callback function with a specific signature, made accessible to programs
|
||||
//written in Lua.
|
||||
// This is a C callback function with a specific signature, made accessible to programs
|
||||
// written in Lua.
|
||||
|
||||
//If it succeeds, it returns an int answer, by pushing it onto the Lua stack. But "sometimes"
|
||||
//it fails, in which case it calls luaL_error. This causes the Lua interpreter to abort and pop
|
||||
//back into the C++ code which called it (see call_lua below).
|
||||
// If it succeeds, it returns an int answer, by pushing it onto the Lua stack. But "sometimes"
|
||||
// it fails, in which case it calls luaL_error. This causes the Lua interpreter to abort and pop
|
||||
// back into the C++ code which called it (see call_lua below).
|
||||
int do_work( lua_State * L )
|
||||
{
|
||||
bool success=rand()%2;
|
||||
if( success )
|
||||
{
|
||||
lua_pushnumber(L,42); //Return 42 to the calling Lua program.
|
||||
lua_pushnumber(L,42); // Return 42 to the calling Lua program.
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Remarkably, the Lua interpreter is exception-safe. So, just throw.
|
||||
throw leaf::exception(lua_failure(),ec1);
|
||||
// Remarkably, the Lua interpreter is exception-safe. So, just throw.
|
||||
throw leaf::exception(std::exception(),ec1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<lua_State> init_lua_state()
|
||||
{
|
||||
//Create a new lua_State, we'll use std::shared_ptr for automatic cleanup.
|
||||
// Create a new lua_State, we'll use std::shared_ptr for automatic cleanup.
|
||||
std::shared_ptr<lua_State> L(lua_open(),&lua_close);
|
||||
|
||||
//Register the do_work function (above) as a C callback, under the global
|
||||
//Lua name "do_work". With this, calls from Lua programs to do_work
|
||||
//will land in the do_work C function we've registered.
|
||||
// Register the do_work function (above) as a C callback, under the global
|
||||
// Lua name "do_work". With this, calls from Lua programs to do_work
|
||||
// will land in the do_work C function we've registered.
|
||||
lua_register( &*L, "do_work", &do_work );
|
||||
|
||||
//Pass some Lua code as a C string literal to Lua. This creates a global Lua
|
||||
//function called "call_do_work", which we will later ask Lua to execute.
|
||||
// Pass some Lua code as a C string literal to Lua. This creates a global Lua
|
||||
// function called "call_do_work", which we will later ask Lua to execute.
|
||||
luaL_dostring( &*L, "\
|
||||
\n function call_do_work()\
|
||||
\n return do_work()\
|
||||
@@ -76,27 +74,27 @@ std::shared_ptr<lua_State> init_lua_state()
|
||||
}
|
||||
|
||||
|
||||
//Here we will ask Lua to execute the function call_do_work, which is written
|
||||
//in Lua, and returns the value from do_work, which is written in C++ and
|
||||
//registered with the Lua interpreter as a C callback.
|
||||
// Here we will ask Lua to execute the function call_do_work, which is written
|
||||
// in Lua, and returns the value from do_work, which is written in C++ and
|
||||
// registered with the Lua interpreter as a C callback.
|
||||
|
||||
//If do_work succeeds, we return the resulting int answer. If it fails, we'll
|
||||
//communicate that failure to our caller.
|
||||
// If do_work succeeds, we return the resulting int answer.
|
||||
// If it fails, we'll communicate that failure to our caller.
|
||||
int call_lua( lua_State * L )
|
||||
{
|
||||
//Ask the Lua interpreter to call the global Lua function call_do_work.
|
||||
// Ask the Lua interpreter to call the global Lua function call_do_work.
|
||||
lua_getfield( L, LUA_GLOBALSINDEX, "call_do_work" );
|
||||
if( int err=lua_pcall(L,0,1,0) )
|
||||
{
|
||||
//Something went wrong with the call, so we'll throw lua_failure.
|
||||
//This is definitely not a do_work failure, because it throws on error.
|
||||
// Something went wrong with the call, so we'll throw std::exception.
|
||||
// This is definitely not a do_work failure, because it throws on error.
|
||||
auto propagate = leaf::preload( e_lua_error_message{lua_tostring(L,1)} );
|
||||
lua_pop(L,1);
|
||||
throw leaf::exception( lua_failure(), e_lua_pcall_error{err} );
|
||||
throw leaf::exception( std::exception(), e_lua_pcall_error{err} );
|
||||
}
|
||||
else
|
||||
{
|
||||
//Success! Just return the int answer.
|
||||
// Success! Just return the int answer.
|
||||
int answer=lua_tonumber(L,-1);
|
||||
lua_pop(L,1);
|
||||
return answer;
|
||||
@@ -106,29 +104,35 @@ int call_lua( lua_State * L )
|
||||
int main() noexcept
|
||||
{
|
||||
std::shared_ptr<lua_State> L=init_lua_state();
|
||||
leaf::expect<do_work_error_code,e_lua_pcall_error,e_lua_error_message> exp;
|
||||
|
||||
for( int i=0; i!=10; ++i )
|
||||
try
|
||||
{
|
||||
int r = call_lua(&*L);
|
||||
std::cout << "do_work succeeded, answer=" << r << '\n';
|
||||
}
|
||||
catch( lua_failure const & e )
|
||||
{
|
||||
handle_exception( exp, e,
|
||||
{
|
||||
leaf::try_(
|
||||
|
||||
//Handle do_work failures:
|
||||
[ ]( do_work_error_code const & e )
|
||||
{
|
||||
std::cout << "Got do_work_error_code = " << e << "!\n";
|
||||
},
|
||||
[&]
|
||||
{
|
||||
int answer = call_lua(&*L);
|
||||
std::cout << "do_work succeeded, answer=" << answer << '\n';
|
||||
},
|
||||
|
||||
[ ]( do_work_error_code e )
|
||||
{
|
||||
std::cout << "Got do_work_error_code = " << e << "!\n";
|
||||
},
|
||||
|
||||
[ ]( e_lua_pcall_error const & err, e_lua_error_message const & msg )
|
||||
{
|
||||
std::cout << "Got e_lua_pcall_error, Lua error code = " << err.value << ", " << msg.value << "\n";
|
||||
},
|
||||
|
||||
[ ]( leaf::error_info const & unmatched )
|
||||
{
|
||||
std::cerr <<
|
||||
"Unknown failure detected" << std::endl <<
|
||||
"Cryptic diagnostic information follows" << std::endl <<
|
||||
unmatched;
|
||||
} );
|
||||
}
|
||||
|
||||
//Handle all other lua_pcall failures:
|
||||
[ ]( e_lua_pcall_error const & err, e_lua_error_message const & msg )
|
||||
{
|
||||
std::cout << "Got e_lua_pcall_error, Lua error code = " << err.value << ", " << msg.value << "\n";
|
||||
}
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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 is a simple program that shows how to propagate leaf::error objects out
|
||||
//of a C-callback, and converting them to leaf::result<T> as soon as control
|
||||
//reaches C++.
|
||||
// This is a simple program that shows how to propagate error objects out
|
||||
// of a C-callback, and converting them to leaf::result<T> as soon as control
|
||||
// reaches C++.
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
@@ -31,25 +31,25 @@ struct e_lua_pcall_error { int value; };
|
||||
struct e_lua_error_message { std::string value; };
|
||||
|
||||
|
||||
//This is a C callback function with a specific signature, made accessible to programs
|
||||
//written in Lua.
|
||||
// This is a C callback function with a specific signature, made accessible to programs
|
||||
// written in Lua.
|
||||
|
||||
//If it succeeds, it returns an int answer, by pushing it onto the Lua stack. But "sometimes"
|
||||
//it fails, in which case it calls luaL_error. This causes the Lua interpreter to abort and pop
|
||||
//back into the C++ code which called it (see call_lua below).
|
||||
// If it succeeds, it returns an int answer, by pushing it onto the Lua stack. But "sometimes"
|
||||
// it fails, in which case it calls luaL_error. This causes the Lua interpreter to abort and pop
|
||||
// back into the C++ code which called it (see call_lua below).
|
||||
int do_work( lua_State * L ) noexcept
|
||||
{
|
||||
bool success=rand()%2;
|
||||
if( success )
|
||||
{
|
||||
lua_pushnumber(L,42); //Return 42 to the calling Lua program.
|
||||
lua_pushnumber(L,42); // Return 42 to the calling Lua program.
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Associate an do_work_error_code object with the *next* leaf::error object we will
|
||||
//definitely return from the call_lua function...
|
||||
leaf::next_error_value().propagate(ec1);
|
||||
// Associate an do_work_error_code object with the *next* leaf::error_id object we will
|
||||
// definitely return from the call_lua function...
|
||||
leaf::next_error().propagate(ec1);
|
||||
|
||||
//...once control reaches it, after we tell the Lua interpreter to abort the program.
|
||||
return luaL_error(L,"do_work_error");
|
||||
@@ -59,16 +59,16 @@ int do_work( lua_State * L ) noexcept
|
||||
|
||||
std::shared_ptr<lua_State> init_lua_state() noexcept
|
||||
{
|
||||
//Create a new lua_State, we'll use std::shared_ptr for automatic cleanup.
|
||||
// Create a new lua_State, we'll use std::shared_ptr for automatic cleanup.
|
||||
std::shared_ptr<lua_State> L(lua_open(),&lua_close);
|
||||
|
||||
//Register the do_work function (above) as a C callback, under the global
|
||||
//Lua name "do_work". With this, calls from Lua programs to do_work
|
||||
//will land in the do_work C function we've registered.
|
||||
// Register the do_work function (above) as a C callback, under the global
|
||||
// Lua name "do_work". With this, calls from Lua programs to do_work
|
||||
// will land in the do_work C function we've registered.
|
||||
lua_register( &*L, "do_work", &do_work );
|
||||
|
||||
//Pass some Lua code as a C string literal to Lua. This creates a global Lua
|
||||
//function called "call_do_work", which we will later ask Lua to execute.
|
||||
// Pass some Lua code as a C string literal to Lua. This creates a global Lua
|
||||
// function called "call_do_work", which we will later ask Lua to execute.
|
||||
luaL_dostring( &*L, "\
|
||||
\n function call_do_work()\
|
||||
\n return do_work()\
|
||||
@@ -78,30 +78,30 @@ std::shared_ptr<lua_State> init_lua_state() noexcept
|
||||
}
|
||||
|
||||
|
||||
//Here we will ask Lua to execute the function call_do_work, which is written
|
||||
//in Lua, and returns the value from do_work, which is written in C++ and
|
||||
//registered with the Lua interpreter as a C callback.
|
||||
// Here we will ask Lua to execute the function call_do_work, which is written
|
||||
// in Lua, and returns the value from do_work, which is written in C++ and
|
||||
// registered with the Lua interpreter as a C callback.
|
||||
|
||||
//If do_work succeeds, we return the resulting int answer in leaf::result<int>.
|
||||
//If it fails, we'll communicate that failure to our caller.
|
||||
// If do_work succeeds, we return the resulting int answer in leaf::result<int>.
|
||||
// If it fails, we'll communicate that failure to our caller.
|
||||
leaf::result<int> call_lua( lua_State * L )
|
||||
{
|
||||
//Ask the Lua interpreter to call the global Lua function call_do_work.
|
||||
// Ask the Lua interpreter to call the global Lua function call_do_work.
|
||||
lua_getfield( L, LUA_GLOBALSINDEX, "call_do_work" );
|
||||
if( int err=lua_pcall(L,0,1,0) )
|
||||
{
|
||||
//Something went wrong with the call, so we'll return a leaf::error.
|
||||
//If this is a do_work failure, the do_work_error_code object prepared in
|
||||
//do_work will become associated with this leaf::error value. If not,
|
||||
//we will still need to communicate that the lua_pcall failed with an
|
||||
//error code and an error message.
|
||||
// Something went wrong with the call, so we'll return a new_error.
|
||||
// If this is a do_work failure, the do_work_error_code object prepared in
|
||||
// do_work will become associated with this leaf::error_id value. If not,
|
||||
// we will still need to communicate that the lua_pcall failed with an
|
||||
// error code and an error message.
|
||||
auto propagate = leaf::preload( e_lua_error_message{lua_tostring(L,1)} );
|
||||
lua_pop(L,1);
|
||||
return leaf::error( e_lua_pcall_error{err} );
|
||||
return leaf::new_error( e_lua_pcall_error{err} );
|
||||
}
|
||||
else
|
||||
{
|
||||
//Success! Just return the int answer.
|
||||
// Success! Just return the int answer.
|
||||
int answer=lua_tonumber(L,-1);
|
||||
lua_pop(L,1);
|
||||
return answer;
|
||||
@@ -112,28 +112,35 @@ int main() noexcept
|
||||
{
|
||||
std::shared_ptr<lua_State> L=init_lua_state();
|
||||
|
||||
leaf::expect<do_work_error_code,e_lua_pcall_error,e_lua_error_message> exp;
|
||||
|
||||
for( int i=0; i!=10; ++i )
|
||||
if( leaf::result<int> r = call_lua(&*L) )
|
||||
std::cout << "do_work succeeded, answer=" << *r << '\n';
|
||||
else
|
||||
{
|
||||
bool matched = handle_error( exp, r,
|
||||
{
|
||||
leaf::handle_all(
|
||||
|
||||
//Handle e_do_work failures:
|
||||
[ ]( do_work_error_code e )
|
||||
{
|
||||
std::cout << "Got do_work_error_code = " << e << "!\n";
|
||||
},
|
||||
[&]() -> leaf::result<void>
|
||||
{
|
||||
LEAF_AUTO(answer, call_lua(&*L));
|
||||
std::cout << "do_work succeeded, answer=" << answer << '\n';
|
||||
return { };
|
||||
},
|
||||
|
||||
[ ]( do_work_error_code e )
|
||||
{
|
||||
std::cout << "Got do_work_error_code = " << e << "!\n";
|
||||
},
|
||||
|
||||
[ ]( e_lua_pcall_error const & err, e_lua_error_message const & msg )
|
||||
{
|
||||
std::cout << "Got e_lua_pcall_error, Lua error code = " << err.value << ", " << msg.value << "\n";
|
||||
},
|
||||
|
||||
[ ]( leaf::error_info const & unmatched )
|
||||
{
|
||||
std::cerr <<
|
||||
"Unknown failure detected" << std::endl <<
|
||||
"Cryptic diagnostic information follows" << std::endl <<
|
||||
unmatched;
|
||||
} );
|
||||
}
|
||||
|
||||
//Handle all other lua_pcall failures:
|
||||
[ ]( e_lua_pcall_error const & err, e_lua_error_message const & msg )
|
||||
{
|
||||
std::cout << "Got e_lua_pcall_error, Lua error code = " << err.value << ", " << msg.value << "\n";
|
||||
}
|
||||
);
|
||||
assert(matched);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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 example demonstrates the basic use of LEAF to augment error conditions with
|
||||
//additional information when using exceptions to report failures. See print_file_result.cpp
|
||||
//for the variant that doesn't use exceptions.
|
||||
// This is a short but complete program that reads a text file in a buffer and prints it to std::cout,
|
||||
// using LEAF to handle errors. It uses exception handling.
|
||||
|
||||
#include <boost/leaf/all.hpp>
|
||||
#include <boost/leaf/throw.hpp>
|
||||
#include <boost/leaf/try.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <stdio.h>
|
||||
@@ -16,13 +17,7 @@
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
|
||||
//We could define our own e-types, but for this example the ones defined in
|
||||
//<boost/leaf/common.hpp> are a perfect match.
|
||||
using leaf::e_file_name;
|
||||
using leaf::e_errno;
|
||||
|
||||
|
||||
//Exception type hierarchy.
|
||||
// Exception type hierarchy.
|
||||
struct print_file_error : virtual std::exception { };
|
||||
struct command_line_error : virtual print_file_error { };
|
||||
struct bad_command_line : virtual command_line_error { };
|
||||
@@ -34,152 +29,162 @@ struct input_file_read_error : virtual input_file_error { };
|
||||
struct input_eof_error : virtual input_file_error { };
|
||||
|
||||
|
||||
// We will handle all failures in our main function, but first, here are the declarations of the functions it calls, each
|
||||
// communicating failures by throwing exceptions
|
||||
|
||||
// Parse the command line, return the file name.
|
||||
char const * parse_command_line( int argc, char const * argv[ ] );
|
||||
|
||||
// Open a file for reading.
|
||||
std::shared_ptr<FILE> file_open( char const * file_name );
|
||||
|
||||
// Return the size of the file.
|
||||
int file_size( FILE & f );
|
||||
|
||||
// Read size bytes from f into buf.
|
||||
void file_read( FILE & f, void * buf, int size );
|
||||
|
||||
|
||||
int main( int argc, char const * argv[ ] )
|
||||
{
|
||||
// Configure std::cout to throw on error.
|
||||
std::cout.exceptions(std::ostream::failbit | std::ostream::badbit);
|
||||
|
||||
return leaf::try_(
|
||||
[&]
|
||||
{
|
||||
char const * file_name = parse_command_line(argc,argv);
|
||||
|
||||
auto propagate = leaf::preload( leaf::e_file_name{file_name} );
|
||||
|
||||
std::shared_ptr<FILE> f = file_open( file_name );
|
||||
|
||||
int s = file_size(*f);
|
||||
|
||||
std::string buffer( 1 + s, '\0' );
|
||||
file_read(*f,&buffer[0],buffer.size()-1);
|
||||
|
||||
auto propagate2 = leaf::defer([ ] { return leaf::e_errno{errno}; } );
|
||||
std::cout << buffer;
|
||||
std::cout.flush();
|
||||
|
||||
return 0;
|
||||
},
|
||||
|
||||
// Each of the lambdas below is an error handler. LEAF will consider them, in order, and call the first one that matches
|
||||
// the available error information.
|
||||
|
||||
// This handler will be called if the error includes:
|
||||
// - a caught exception of type input_file_open_error, and
|
||||
// - an object of type leaf::e_errno that has .value equal to ENOENT, and
|
||||
// - an object of type leaf::e_file_name.
|
||||
[ ]( leaf::catch_<input_file_open_error>, leaf::match<leaf::e_errno,ENOENT>, leaf::e_file_name const & fn )
|
||||
{
|
||||
std::cerr << "File not found: " << fn.value << std::endl;
|
||||
return 1;
|
||||
},
|
||||
|
||||
// This handler will be called if the error includes:
|
||||
// - a caught exception of type input_file_open_error, and
|
||||
// - an object of type leaf::e_errno (regardless of its .value), and
|
||||
// - an object of type leaf::e_file_name.
|
||||
[ ]( leaf::catch_<input_file_open_error>, leaf::e_errno const & errn, leaf::e_file_name const & fn )
|
||||
{
|
||||
std::cerr << "Failed to open " << fn.value << ", errno=" << errn << std::endl;
|
||||
return 2;
|
||||
},
|
||||
|
||||
// This handler will be called if the error includes:
|
||||
// - a caught exception of type input_error, and
|
||||
// - an object of type leaf::e_errno (regardless of its .value), and
|
||||
// - an object of type leaf::e_file_name.
|
||||
[ ]( leaf::catch_<input_error>, leaf::e_errno const & errn, leaf::e_file_name const & fn )
|
||||
{
|
||||
std::cerr << "Failed to access " << fn.value << ", errno=" << errn << std::endl;
|
||||
return 3;
|
||||
},
|
||||
|
||||
// This handler will be called if the error includes:
|
||||
// - a caught exception of type std::ostream::failure, and
|
||||
// - an object of type leaf::e_errno (regardless of its .value),
|
||||
[ ]( leaf::catch_<std::ostream::failure>, leaf::e_errno const & errn )
|
||||
{
|
||||
std::cerr << "Output error, errno=" << errn << std::endl;
|
||||
return 4;
|
||||
},
|
||||
|
||||
// This handler will be called if the error includes a caught exception of type bad_command_line.
|
||||
[ ]( leaf::catch_<bad_command_line> )
|
||||
{
|
||||
std::cout << "Bad command line argument" << std::endl;
|
||||
return 5;
|
||||
},
|
||||
|
||||
// This last handler matches any error: it prints diagnostic information to help debug logic errors in the program, since it
|
||||
// failed to match an appropriate error handler to the error condition it encountered. In this program this handler will
|
||||
// never be called.
|
||||
[ ]( leaf::error_info const & unmatched )
|
||||
{
|
||||
std::cerr <<
|
||||
"Unknown failure detected" << std::endl <<
|
||||
"Cryptic diagnostic information follows" << std::endl <<
|
||||
unmatched;
|
||||
return 6;
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
// Implementations of the functions called by main:
|
||||
|
||||
|
||||
// Parse the command line, return the file name.
|
||||
char const * parse_command_line( int argc, char const * argv[ ] )
|
||||
{
|
||||
if( argc==2 )
|
||||
return argv[1];
|
||||
else
|
||||
throw leaf::exception(bad_command_line());
|
||||
}
|
||||
|
||||
|
||||
// Open a file for reading.
|
||||
std::shared_ptr<FILE> file_open( char const * file_name )
|
||||
{
|
||||
if( FILE * f = fopen(file_name,"rb") )
|
||||
return std::shared_ptr<FILE>(f,&fclose);
|
||||
else
|
||||
throw leaf::exception( input_file_open_error(), e_file_name{file_name}, e_errno{errno} );
|
||||
throw leaf::exception(input_file_open_error(), leaf::e_errno{errno});
|
||||
}
|
||||
|
||||
|
||||
// Return the size of the file.
|
||||
int file_size( FILE & f )
|
||||
{
|
||||
//All exceptions escaping this function will automatically propagate errno.
|
||||
auto propagate = leaf::defer( [ ] { return e_errno{errno}; } );
|
||||
// All exceptions escaping this function will automatically propagate errno.
|
||||
auto propagate = leaf::defer( [ ] { return leaf::e_errno{errno}; } );
|
||||
|
||||
if( fseek(&f,0,SEEK_END) )
|
||||
throw input_file_size_error();
|
||||
throw leaf::exception(input_file_size_error());
|
||||
|
||||
int s = ftell(&f);
|
||||
if( s==-1L )
|
||||
throw input_file_size_error();
|
||||
throw leaf::exception(input_file_size_error());
|
||||
|
||||
if( fseek(&f,0,SEEK_SET) )
|
||||
throw input_file_size_error();
|
||||
throw leaf::exception(input_file_size_error());
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
// Read size bytes from f into buf.
|
||||
void file_read( FILE & f, void * buf, int size )
|
||||
{
|
||||
int n = fread(buf,1,size,&f);
|
||||
|
||||
if( ferror(&f) )
|
||||
throw leaf::exception( input_file_read_error(), e_errno{errno} );
|
||||
throw leaf::exception( input_file_read_error(), leaf::e_errno{errno} );
|
||||
|
||||
if( n!=size )
|
||||
throw input_eof_error();
|
||||
}
|
||||
|
||||
|
||||
void print_file( char const * file_name )
|
||||
{
|
||||
std::shared_ptr<FILE> f = file_open( file_name );
|
||||
|
||||
auto propagate1 = leaf::preload( e_file_name{file_name} );
|
||||
|
||||
std::string buffer( 1+file_size(*f), '\0' );
|
||||
file_read(*f,&buffer[0],buffer.size()-1);
|
||||
|
||||
auto propagate2 = leaf::defer([ ] { return e_errno{errno}; } );
|
||||
std::cout << buffer;
|
||||
std::cout.flush();
|
||||
}
|
||||
|
||||
|
||||
char const * parse_command_line( int argc, char const * argv[ ] )
|
||||
{
|
||||
if( argc!=2 )
|
||||
throw bad_command_line();
|
||||
return argv[1];
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char const * argv[ ] )
|
||||
{
|
||||
//Configure std::cout to throw on error.
|
||||
std::cout.exceptions ( std::ostream::failbit | std::ostream::badbit );
|
||||
|
||||
//We expect e_file_name and e_errno objects to be associated with errors
|
||||
//handled in this function. They will be stored inside of exp.
|
||||
leaf::expect<e_file_name, e_errno> exp;
|
||||
|
||||
try
|
||||
{
|
||||
print_file(parse_command_line(argc,argv));
|
||||
return 0;
|
||||
}
|
||||
catch( bad_command_line const & )
|
||||
{
|
||||
std::cout << "Bad command line argument" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch( input_file_open_error const & e )
|
||||
{
|
||||
//handle_exception takes a list of functions (in this case only one). It attempts to
|
||||
//match each function (in order) to objects currently available in exp, which
|
||||
//are associated with the error value stored in e. If no function can be matched,
|
||||
//handle_exception returns false. Otherwise the matched function is invoked with
|
||||
//the corresponding available error objects.
|
||||
leaf::handle_exception( exp, e,
|
||||
|
||||
[ ] ( e_file_name const & fn, e_errno const & errn )
|
||||
{
|
||||
if( errn.value==ENOENT )
|
||||
std::cerr << "File not found: " << fn.value << std::endl;
|
||||
else
|
||||
std::cerr << "Failed to open " << fn.value << ", errno=" << errn << std::endl;
|
||||
}
|
||||
|
||||
);
|
||||
return 2;
|
||||
}
|
||||
catch( input_error const & e )
|
||||
{
|
||||
//In this case handle_exception is given 3 functions. It will first check if both
|
||||
//e_file_name and e_errno, associated with e, are avialable in exp; if not, it will
|
||||
//next check if just e_errno is available; and if not, the last function (which
|
||||
//takes no arguments) will always match to print a generic error message.
|
||||
leaf::handle_exception( exp, e,
|
||||
|
||||
[ ] ( e_file_name const & fn, e_errno const & errn )
|
||||
{
|
||||
std::cerr << "Input error, " << fn.value << ", errno=" << errn << std::endl;
|
||||
},
|
||||
|
||||
[ ] ( e_errno const & errn )
|
||||
{
|
||||
std::cerr << "Input error, errno=" << errn << std::endl;
|
||||
},
|
||||
|
||||
[ ]
|
||||
{
|
||||
std::cerr << "Input error" << std::endl;
|
||||
}
|
||||
|
||||
);
|
||||
return 3;
|
||||
}
|
||||
catch( std::ostream::failure const & e )
|
||||
{
|
||||
//Report failure to write to std::cout, print the relevant errno.
|
||||
leaf::handle_exception( exp, e,
|
||||
|
||||
[ ] ( e_errno const & errn )
|
||||
{
|
||||
std::cerr << "Output error, errno=" << errn << std::endl;
|
||||
}
|
||||
|
||||
);
|
||||
return 4;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
//This catch-all case helps diagnose logic errors (presumably, missing catch).
|
||||
std::cerr << "Unknown error, cryptic information follows." << std::endl;
|
||||
leaf::diagnostic_output_current_exception(std::cerr,exp);
|
||||
return 5;
|
||||
}
|
||||
throw leaf::exception(input_eof_error());
|
||||
}
|
||||
|
||||
@@ -1,207 +1,196 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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 example demonstrates the basic use of LEAF to augment error conditions with
|
||||
//additional information when using result<T> to report failures. See print_file_eh.cpp
|
||||
//for the variant that uses exception handling.
|
||||
// This is a short but complete program that reads a text file in a buffer and prints it to std::cout,
|
||||
// using LEAF to handle errors. It does not use exception handling.
|
||||
|
||||
#include <boost/leaf/all.hpp>
|
||||
#include <boost/leaf/handle.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
|
||||
//We could define our own e-types, but for this example the ones
|
||||
//defined in <boost/leaf/common.hpp> are a perfect match.
|
||||
using leaf::e_file_name;
|
||||
using leaf::e_errno;
|
||||
|
||||
|
||||
//Error codes
|
||||
// First, we need an enum to define our error codes:
|
||||
enum error_code
|
||||
{
|
||||
input_file_open_error=1,
|
||||
bad_command_line = 1,
|
||||
input_file_open_error,
|
||||
input_file_size_error,
|
||||
input_file_read_error,
|
||||
input_eof_error,
|
||||
cout_error
|
||||
};
|
||||
|
||||
// To enable LEAF to work with our error_code enum, we need to specialize the is_error_type template:
|
||||
namespace boost { namespace leaf {
|
||||
template<> struct is_error_type<error_code>: std::true_type { };
|
||||
} }
|
||||
|
||||
|
||||
// We will handle all failures in our main function, but first, here are the declarations of the functions it calls, each
|
||||
// communicating failures using leaf::result<T>:
|
||||
|
||||
// Parse the command line, return the file name.
|
||||
leaf::result<char const *> parse_command_line( int argc, char const * argv[ ] );
|
||||
|
||||
// Open a file for reading.
|
||||
leaf::result<std::shared_ptr<FILE>> file_open( char const * file_name );
|
||||
|
||||
// Return the size of the file.
|
||||
leaf::result<int> file_size( FILE & f );
|
||||
|
||||
// Read size bytes from f into buf.
|
||||
leaf::result<void> file_read( FILE & f, void * buf, int size );
|
||||
|
||||
|
||||
// The main function, which handles all errors.
|
||||
int main( int argc, char const * argv[ ] )
|
||||
{
|
||||
return leaf::handle_all(
|
||||
|
||||
[&]() -> leaf::result<int>
|
||||
{
|
||||
LEAF_AUTO(file_name, parse_command_line(argc,argv));
|
||||
|
||||
auto propagate = leaf::preload( leaf::e_file_name{file_name} );
|
||||
|
||||
LEAF_AUTO(f, file_open(file_name));
|
||||
|
||||
LEAF_AUTO(s, file_size(*f));
|
||||
|
||||
std::string buffer( 1 + s, '\0' );
|
||||
LEAF_CHECK(file_read(*f, &buffer[0], buffer.size()-1));
|
||||
|
||||
auto propagate2 = leaf::defer([ ] { return leaf::e_errno{errno}; } );
|
||||
std::cout << buffer;
|
||||
std::cout.flush();
|
||||
if( std::cout.fail() )
|
||||
return leaf::new_error( cout_error );
|
||||
|
||||
return 0;
|
||||
},
|
||||
|
||||
// Each of the lambdas below is an error handler. LEAF will consider them, in order, and call the first one that matches
|
||||
// the available error information.
|
||||
|
||||
// This handler will be called if the error includes:
|
||||
// - an object of type error_code equal to input_file_open_error, and
|
||||
// - an object of type leaf::e_errno that has .value equal to ENOENT, and
|
||||
// - an object of type leaf::e_file_name.
|
||||
[ ]( leaf::match<error_code, input_file_open_error>, leaf::match<leaf::e_errno, ENOENT>, leaf::e_file_name const & fn )
|
||||
{
|
||||
std::cerr << "File not found: " << fn.value << std::endl;
|
||||
return 1;
|
||||
},
|
||||
|
||||
// This handler will be called if the error includes:
|
||||
// - an object of type error_code equal to input_file_open_error, and
|
||||
// - an object of type leaf::e_errno (regardless of its .value), and
|
||||
// - an object of type leaf::e_file_name.
|
||||
[ ]( leaf::match<error_code, input_file_open_error>, leaf::e_errno const & errn, leaf::e_file_name const & fn )
|
||||
{
|
||||
std::cerr << "Failed to open " << fn.value << ", errno=" << errn << std::endl;
|
||||
return 2;
|
||||
},
|
||||
|
||||
// This handler will be called if the error includes:
|
||||
// - an object of type error_code equal to any of input_file_size_error, input_file_read_error, input_eof_error, and
|
||||
// - an object of type leaf::e_errno (regardless of its .value), and
|
||||
// - an object of type leaf::e_file_name.
|
||||
[ ]( leaf::match<error_code, input_file_size_error, input_file_read_error, input_eof_error>, leaf::e_errno const & errn, leaf::e_file_name const & fn )
|
||||
{
|
||||
std::cerr << "Failed to access " << fn.value << ", errno=" << errn << std::endl;
|
||||
return 3;
|
||||
},
|
||||
|
||||
// This handler will be called if the error includes:
|
||||
// - an object of type error_code equal to cout_error, and
|
||||
// - an object of type leaf::e_errno (regardless of its .value),
|
||||
[ ]( leaf::match<error_code, cout_error>, leaf::e_errno const & errn )
|
||||
{
|
||||
std::cerr << "Output error, errno=" << errn << std::endl;
|
||||
return 4;
|
||||
},
|
||||
|
||||
// This handler will be called if the error includes an object of type error_code equal to bad_command_line.
|
||||
[ ]( leaf::match<error_code, bad_command_line> )
|
||||
{
|
||||
std::cout << "Bad command line argument" << std::endl;
|
||||
return 5;
|
||||
},
|
||||
|
||||
// This last handler matches any error: it prints diagnostic information to help debug logic errors in the program, since it
|
||||
// failed to match an appropriate error handler to the error condition it encountered. In this program this handler will
|
||||
// never be called.
|
||||
[ ]( leaf::error_info const & unmatched )
|
||||
{
|
||||
std::cerr <<
|
||||
"Unknown failure detected" << std::endl <<
|
||||
"Cryptic diagnostic information follows" << std::endl <<
|
||||
unmatched;
|
||||
return 6;
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
// Implementations of the functions called by main:
|
||||
|
||||
|
||||
// Parse the command line, return the file name.
|
||||
leaf::result<char const *> parse_command_line( int argc, char const * argv[ ] )
|
||||
{
|
||||
if( argc==2 )
|
||||
return argv[1];
|
||||
else
|
||||
return leaf::new_error(bad_command_line);
|
||||
}
|
||||
|
||||
|
||||
// Open a file for reading.
|
||||
leaf::result<std::shared_ptr<FILE>> file_open( char const * file_name )
|
||||
{
|
||||
if( FILE * f = fopen(file_name,"rb") )
|
||||
return std::shared_ptr<FILE>(f,&fclose);
|
||||
else
|
||||
return leaf::error( input_file_open_error, e_file_name{file_name}, e_errno{errno} );
|
||||
return leaf::new_error(input_file_open_error, leaf::e_errno{errno});
|
||||
}
|
||||
|
||||
|
||||
// Return the size of the file.
|
||||
leaf::result<int> file_size( FILE & f )
|
||||
{
|
||||
auto propagate = leaf::defer([ ] { return e_errno{errno}; } );
|
||||
// All exceptions escaping this function will automatically propagate errno.
|
||||
auto propagate = leaf::defer([ ] { return leaf::e_errno{errno}; });
|
||||
|
||||
if( fseek(&f,0,SEEK_END) )
|
||||
return leaf::error( input_file_size_error );
|
||||
return leaf::new_error(input_file_size_error);
|
||||
|
||||
int s = ftell(&f);
|
||||
if( s==-1L )
|
||||
return leaf::error( input_file_size_error );
|
||||
return leaf::new_error(input_file_size_error);
|
||||
|
||||
if( fseek(&f,0,SEEK_SET) )
|
||||
return leaf::error( input_file_size_error );
|
||||
return leaf::new_error(input_file_size_error);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
// Read size bytes from f into buf.
|
||||
leaf::result<void> file_read( FILE & f, void * buf, int size )
|
||||
{
|
||||
int n = fread(buf,1,size,&f);
|
||||
|
||||
if( ferror(&f) )
|
||||
return leaf::error( input_file_read_error, e_errno{errno} );
|
||||
return leaf::new_error(input_file_read_error, leaf::e_errno{errno});
|
||||
|
||||
if( n!=size )
|
||||
return leaf::error( input_eof_error );
|
||||
return leaf::new_error(input_eof_error);
|
||||
|
||||
return { };
|
||||
}
|
||||
|
||||
|
||||
leaf::result<void> print_file( char const * file_name )
|
||||
{
|
||||
LEAF_AUTO(f,file_open(file_name));
|
||||
|
||||
auto propagate = leaf::preload( e_file_name{file_name} );
|
||||
|
||||
LEAF_AUTO(s,file_size(*f));
|
||||
|
||||
std::string buffer( 1+s, '\0' );
|
||||
LEAF_CHECK(file_read(*f,&buffer[0],buffer.size()-1));
|
||||
|
||||
std::cout << buffer;
|
||||
std::cout.flush();
|
||||
if( std::cout.fail() )
|
||||
return leaf::error( cout_error );
|
||||
|
||||
return { };
|
||||
}
|
||||
|
||||
|
||||
char const * parse_command_line( int argc, char const * argv[ ] )
|
||||
{
|
||||
if( argc!=2 )
|
||||
return 0;
|
||||
else
|
||||
return argv[1];
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char const * argv[ ] )
|
||||
{
|
||||
char const * fn = parse_command_line(argc,argv);
|
||||
if( !fn )
|
||||
{
|
||||
std::cout << "Bad command line argument" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//We expect error_code, e_file_name and e_errno objects to be associated
|
||||
//with errors handled in this function. They will be stored inside of exp.
|
||||
leaf::expect<error_code, e_file_name, e_errno> exp;
|
||||
|
||||
if( auto r = print_file(fn) )
|
||||
{
|
||||
return 0; //Success, we're done!
|
||||
}
|
||||
else
|
||||
{
|
||||
//Probe exp for the error_code object associated with the error stored in r.
|
||||
switch( auto ec = *leaf::peek<error_code>(exp,r) )
|
||||
{
|
||||
case input_file_open_error:
|
||||
{
|
||||
//handle_error takes a list of functions (in this case only one). It attempts to
|
||||
//match each function (in order) to objects currently available in exp, which
|
||||
//are associated with the error value stored in r. If no function can be matched,
|
||||
//handle_error returns false. Otherwise the matched function is invoked with
|
||||
//the matching corresponding error objects.
|
||||
bool matched = leaf::handle_error( exp, r,
|
||||
|
||||
[ ] ( e_file_name const & fn, e_errno const & errn )
|
||||
{
|
||||
if( errn.value==ENOENT )
|
||||
std::cerr << "File not found: " << fn.value << std::endl;
|
||||
else
|
||||
std::cerr << "Failed to open " << fn.value << ", errno=" << errn << std::endl;
|
||||
}
|
||||
|
||||
);
|
||||
assert(matched);
|
||||
return 2;
|
||||
}
|
||||
|
||||
case input_file_size_error:
|
||||
case input_file_read_error:
|
||||
case input_eof_error:
|
||||
{
|
||||
//In this case handle_error is given 3 functions. It will first check if both
|
||||
//e_file_name and e_errno, associated with r, are avialable in exp; if not, it will
|
||||
//next check if just e_errno is available; and if not, the last function (which
|
||||
//takes no arguments) will always match to print a generic error message.
|
||||
bool matched = leaf::handle_error( exp, r,
|
||||
|
||||
[ ] ( e_file_name const & fn, e_errno const & errn )
|
||||
{
|
||||
std::cerr << "Failed to access " << fn.value << ", errno=" << errn << std::endl;
|
||||
},
|
||||
|
||||
[ ] ( e_errno const & errn )
|
||||
{
|
||||
std::cerr << "I/O error, errno=" << errn << std::endl;
|
||||
},
|
||||
|
||||
[ ]
|
||||
{
|
||||
std::cerr << "I/O error" << std::endl;
|
||||
}
|
||||
|
||||
);
|
||||
assert(matched);
|
||||
return 3;
|
||||
}
|
||||
|
||||
case cout_error:
|
||||
{
|
||||
//Report failure to write to std::cout, print the relevant errno.
|
||||
bool matched = leaf::handle_error( exp, r,
|
||||
|
||||
[ ] ( e_errno const & errn )
|
||||
{
|
||||
std::cerr << "Output error, errno=" << errn << std::endl;
|
||||
}
|
||||
|
||||
);
|
||||
assert(matched);
|
||||
return 4;
|
||||
}
|
||||
|
||||
//This catch-all case helps diagnose logic errors (presumably, missing case labels
|
||||
//in the switch statement).
|
||||
default:
|
||||
{
|
||||
std::cerr << "Unknown error code " << ec << ", cryptic information follows." << std::endl; //<7>
|
||||
leaf::diagnostic_output(std::cerr,exp,r);
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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 program is an adaptation of the following Boost Outcome example:
|
||||
//https://github.com/ned14/outcome/blob/master/doc/src/snippets/using_result.cpp
|
||||
// This program is an adaptation of the following Boost Outcome example:
|
||||
// https://github.com/ned14/outcome/blob/master/doc/src/snippets/using_result.cpp
|
||||
|
||||
#include <boost/leaf/result.hpp>
|
||||
#include <boost/leaf/expect.hpp>
|
||||
#include <boost/leaf/handle.hpp>
|
||||
#include <algorithm>
|
||||
#include <ctype.h>
|
||||
#include <string>
|
||||
@@ -30,18 +29,18 @@ namespace boost { namespace leaf {
|
||||
leaf::result<int> convert(const std::string& str) noexcept
|
||||
{
|
||||
if (str.empty())
|
||||
return leaf::error(ConversionErrc::EmptyString);
|
||||
return leaf::new_error(ConversionErrc::EmptyString);
|
||||
|
||||
if (!std::all_of(str.begin(), str.end(), ::isdigit))
|
||||
return leaf::error(ConversionErrc::IllegalChar);
|
||||
return leaf::new_error(ConversionErrc::IllegalChar);
|
||||
|
||||
if (str.length() > 9)
|
||||
return leaf::error(ConversionErrc::TooLong);
|
||||
return leaf::new_error(ConversionErrc::TooLong);
|
||||
|
||||
return atoi(str.c_str());
|
||||
}
|
||||
|
||||
//Do not expect BigInt to actually work -- it's a stub.
|
||||
// Do not static_store BigInt to actually work -- it's a stub.
|
||||
struct BigInt
|
||||
{
|
||||
static leaf::result<BigInt> fromString(const std::string& s) { return BigInt{s}; }
|
||||
@@ -50,61 +49,54 @@ struct BigInt
|
||||
friend std::ostream& operator<<(std::ostream& o, const BigInt&) { return o << "big int half"; }
|
||||
};
|
||||
|
||||
//This function handles ConversionErrc::TooLong errors, forwards any other error to the caller.
|
||||
// This function handles ConversionErrc::TooLong errors, forwards any other error to the caller.
|
||||
leaf::result<void> print_half(const std::string& text)
|
||||
{
|
||||
leaf::expect<ConversionErrc> exp;
|
||||
if (leaf::result<int> r = convert(text))
|
||||
{
|
||||
std::cout << (r.value() / 2) << std::endl;
|
||||
return { };
|
||||
}
|
||||
else
|
||||
{
|
||||
return leaf::handle_error( exp, r,
|
||||
[&]( ConversionErrc ec ) -> leaf::result<void>
|
||||
{
|
||||
if( ec != ConversionErrc::TooLong )
|
||||
return r.error();
|
||||
LEAF_AUTO(i, BigInt::fromString(text));
|
||||
std::cout << i.half() << std::endl;
|
||||
return { };
|
||||
} );
|
||||
}
|
||||
return leaf::handle_some(
|
||||
[&]() -> leaf::result<void>
|
||||
{
|
||||
LEAF_AUTO(r,convert(text));
|
||||
std::cout << r / 2 << std::endl;
|
||||
return { };
|
||||
},
|
||||
[&]( leaf::match<ConversionErrc,ConversionErrc::TooLong> ) -> leaf::result<void>
|
||||
{
|
||||
LEAF_AUTO(i, BigInt::fromString(text));
|
||||
std::cout << i.half() << std::endl;
|
||||
return { };
|
||||
} );
|
||||
}
|
||||
|
||||
int main( int argc, char const * argv[ ] )
|
||||
{
|
||||
leaf::expect<ConversionErrc> exp;
|
||||
if( leaf::result<void> r = print_half(argc<2 ? "" : argv[1]) )
|
||||
{
|
||||
std::cout << "ok" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return handle_error( exp, r,
|
||||
[ ]( ConversionErrc ec )
|
||||
{
|
||||
switch(ec)
|
||||
{
|
||||
case ConversionErrc::EmptyString:
|
||||
std::cerr << "Empty string!" << std::endl;
|
||||
break;
|
||||
default:
|
||||
assert(ec==ConversionErrc::IllegalChar); //Because print_half deals with ConversionErrc::TooLong.
|
||||
std::cerr << "Illegal char!" << std::endl;
|
||||
}
|
||||
return 1;
|
||||
},
|
||||
[&exp,&r]
|
||||
{
|
||||
//This will never execute in this program, but it would detect logic errors where an unknown error reaches main.
|
||||
//In this case, we print diagnostic information. Consider using leaf::unexpected_diagnostic_output in the
|
||||
//definition of exp.
|
||||
std::cerr << "Unknown error, cryptic diagnostic information follows." << std::endl;
|
||||
leaf::diagnostic_output(std::cerr,exp,r);
|
||||
return 2;
|
||||
} );
|
||||
}
|
||||
return leaf::handle_all(
|
||||
[&]() -> leaf::result<int>
|
||||
{
|
||||
LEAF_CHECK( print_half(argc<2 ? "" : argv[1]) );
|
||||
std::cout << "ok" << std::endl;
|
||||
return 0;
|
||||
},
|
||||
|
||||
[ ]( leaf::match<ConversionErrc,ConversionErrc::EmptyString> )
|
||||
{
|
||||
std::cerr << "Empty string!" << std::endl;
|
||||
return 1;
|
||||
},
|
||||
|
||||
[ ]( leaf::match<ConversionErrc,ConversionErrc::IllegalChar> )
|
||||
{
|
||||
std::cerr << "Illegal char!" << std::endl;
|
||||
return 2;
|
||||
},
|
||||
|
||||
[ ]( leaf::error_info const & unmatched )
|
||||
{
|
||||
// This will never execute in this program, but it would detect logic errors where an unknown error reaches main.
|
||||
// In this case, we print diagnostic information.
|
||||
std::cerr <<
|
||||
"Unknown failure detected" << std::endl <<
|
||||
"Cryptic diagnostic information follows" << std::endl <<
|
||||
unmatched;
|
||||
return 3;
|
||||
} );
|
||||
}
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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 example demonstrates how to transport exceptions thrown by a low level function
|
||||
//through an intermediate context that is not exception-safe, to be handled in a high level
|
||||
//function which may or may not be exception-safe.
|
||||
|
||||
//An real-world example for this use case is when a C API (which may not throw) is implemented
|
||||
//using a C++ library that throws exceptions. As demonstrated below, these exception objects are
|
||||
//intercepted and reported by leaf::result<>.
|
||||
|
||||
#include <boost/leaf/all.hpp>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
class error_base: public virtual std::exception { };
|
||||
class error_a: public virtual error_base { };
|
||||
class error_b: public virtual error_base { };
|
||||
class error_c: public virtual error_base { };
|
||||
|
||||
//Lower-level library function which throws exceptions.
|
||||
int compute_answer_throws()
|
||||
{
|
||||
switch( rand()%4 )
|
||||
{
|
||||
default: return 42;
|
||||
case 1: throw error_a();
|
||||
case 2: throw error_b();
|
||||
case 3: throw error_c();
|
||||
}
|
||||
}
|
||||
|
||||
//A wrapper function that provides a noexcept interface to compute_answer_throws (above),
|
||||
//by transporting different exception types using leaf::result<int>.
|
||||
leaf::result<int> compute_answer() noexcept
|
||||
{
|
||||
//We define special handling for error_a and error_b: exception objects of these types
|
||||
//will be returned directly as LEAF errors...
|
||||
try
|
||||
{
|
||||
return compute_answer_throws();
|
||||
}
|
||||
catch( error_a const & e )
|
||||
{
|
||||
return leaf::error(e);
|
||||
}
|
||||
catch( error_b const & e )
|
||||
{
|
||||
return leaf::error(e);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
//...but "unknown" exceptions are still captured and transported using std::exception_ptr.
|
||||
//This is less efficient, because it will likely allocate memory dynamically.
|
||||
return leaf::error(std::current_exception());
|
||||
}
|
||||
}
|
||||
|
||||
//Intermediate caller of compute_answer.
|
||||
leaf::result<void> print_answer() noexcept
|
||||
{
|
||||
if( leaf::result<int> r = compute_answer() )
|
||||
{
|
||||
std::cout << "Answer: " << r.value() << std::endl;
|
||||
return { };
|
||||
}
|
||||
else
|
||||
return r.error();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
//Exercise print_answer a few times and handle errors. Note that the exception objects that
|
||||
//compute_answer_throws throws will land in the exp object, rather than arrive as exceptions...
|
||||
for( int i=0; i!=10; ++i )
|
||||
{
|
||||
leaf::expect<error_a,error_b,std::exception_ptr> exp;
|
||||
if( leaf::result<void> r = print_answer() )
|
||||
continue;
|
||||
else
|
||||
{
|
||||
leaf::handle_error( exp, r,
|
||||
|
||||
[ ]( error_a const & e )
|
||||
{
|
||||
std::cerr << "Error A!" << std::endl;
|
||||
},
|
||||
|
||||
[ ]( error_b const & e )
|
||||
{
|
||||
std::cerr << "Error B!" << std::endl;
|
||||
},
|
||||
|
||||
//...except for error_c errors, which (for demonstration) are captured as exceptions into
|
||||
//std::exception_ptr, together with any other unknow exception. Presumably this should
|
||||
//never happen, therefore at this point we treat this situation a a logic error: we print
|
||||
//diagnostic information and bail out.
|
||||
[&exp]( std::exception_ptr const & ep )
|
||||
{
|
||||
assert(ep);
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(ep);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
leaf::diagnostic_output_current_exception(std::cerr,exp);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,20 +1,21 @@
|
||||
#ifndef BOOST_LEAF_3382F652FCDD11E8AAD1CCB3642D5A5F
|
||||
#define BOOST_LEAF_3382F652FCDD11E8AAD1CCB3642D5A5F
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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/capture_exception.hpp>
|
||||
#include <boost/leaf/capture_result.hpp>
|
||||
#include <boost/leaf/common.hpp>
|
||||
#include <boost/leaf/diagnostic_output_current_exception.hpp>
|
||||
#include <boost/leaf/error_capture.hpp>
|
||||
#include <boost/leaf/error.hpp>
|
||||
#include <boost/leaf/exception_capture.hpp>
|
||||
#include <boost/leaf/exception.hpp>
|
||||
#include <boost/leaf/expect.hpp>
|
||||
#include <boost/leaf/exception_to_result.hpp>
|
||||
#include <boost/leaf/handle.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
#include <boost/leaf/result.hpp>
|
||||
#include <boost/leaf/throw.hpp>
|
||||
#include <boost/leaf/try.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
134
include/boost/leaf/capture_exception.hpp
Normal file
134
include/boost/leaf/capture_exception.hpp
Normal file
@@ -0,0 +1,134 @@
|
||||
#ifndef BOOST_LEAF_BC24FB98B2DE11E884419CF5AD35F1A2
|
||||
#define BOOST_LEAF_BC24FB98B2DE11E884419CF5AD35F1A2
|
||||
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/dynamic_store_impl.hpp>
|
||||
#include <boost/leaf/detail/captured_exception.hpp>
|
||||
#include <typeinfo>
|
||||
#include <memory>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
class captured_exception_impl:
|
||||
public captured_exception,
|
||||
public error_id
|
||||
{
|
||||
std::exception_ptr ex_;
|
||||
std::shared_ptr<dynamic_store> ds_;
|
||||
bool had_error_;
|
||||
void (*print_captured_types_)(std::ostream &);
|
||||
|
||||
public:
|
||||
|
||||
captured_exception_impl( std::exception_ptr && ex, std::shared_ptr<dynamic_store> && ds, bool had_error, void (*print_captured_types)(std::ostream &) ) noexcept:
|
||||
error_id(ds->error()),
|
||||
ex_(std::move(ex)),
|
||||
ds_(std::move(ds)),
|
||||
had_error_(had_error),
|
||||
print_captured_types_(print_captured_types)
|
||||
{
|
||||
assert(ex_);
|
||||
assert(print_captured_types_!=0);
|
||||
}
|
||||
|
||||
[[noreturn]] void unload_and_rethrow_original_exception()
|
||||
{
|
||||
std::shared_ptr<dynamic_store> ds; ds.swap(ds_);
|
||||
assert(ds);
|
||||
if( had_error_ )
|
||||
{
|
||||
error_id id = ds->unload();
|
||||
assert(id==*this);
|
||||
(void) id;
|
||||
}
|
||||
else
|
||||
ds->unload(next_error());
|
||||
std::rethrow_exception(ex_);
|
||||
}
|
||||
|
||||
void print( std::ostream & os ) const
|
||||
{
|
||||
print_captured_types_(os);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class... T>
|
||||
struct print_types;
|
||||
|
||||
template <class Car, class... Cdr>
|
||||
struct print_types<Car,Cdr...>
|
||||
{
|
||||
static void print( std::ostream & os )
|
||||
{
|
||||
os << '\t' << type<Car>() << std::endl;
|
||||
print_types<Cdr...>::print(os);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct print_types<>
|
||||
{
|
||||
static void print( std::ostream & )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class F, class mp_args, class... E>
|
||||
struct exception_trap;
|
||||
|
||||
template <class F, template<class...> class L, class... A, class... E>
|
||||
struct exception_trap<F, L<A...>,E...>
|
||||
{
|
||||
F f_;
|
||||
|
||||
explicit exception_trap( F && f ) noexcept:
|
||||
f_(std::forward<F>(f))
|
||||
{
|
||||
}
|
||||
|
||||
decltype(std::declval<F>()(std::declval<A>()...)) operator()( A... a ) const
|
||||
{
|
||||
static_store<E...> ss;
|
||||
ss.set_reset(true);
|
||||
try
|
||||
{
|
||||
return f_(std::forward<A>(a)...);
|
||||
}
|
||||
catch( captured_exception const & )
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch( error_id const & id )
|
||||
{
|
||||
throw captured_exception_impl( std::current_exception(), std::make_shared<dynamic_store_impl<E...>>(id,std::move(ss)), true, &print_types<E...>::print );
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
throw captured_exception_impl( std::current_exception(), std::make_shared<dynamic_store_impl<E...>>(new_error(),std::move(ss)), false, &print_types<E...>::print );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // leaf_detail
|
||||
|
||||
template <class... E, class F>
|
||||
leaf_detail::exception_trap<F,typename leaf_detail::function_traits<F>::mp_args,E...> capture_exception( F && f ) noexcept
|
||||
{
|
||||
using namespace leaf_detail;
|
||||
return exception_trap<F,typename function_traits<F>::mp_args,E...>(std::move(f));
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
65
include/boost/leaf/capture_result.hpp
Normal file
65
include/boost/leaf/capture_result.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifndef BOOST_LEAF_2416C558123711E9B9D9691F8C7F4AFC
|
||||
#define BOOST_LEAF_2416C558123711E9B9D9691F8C7F4AFC
|
||||
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/result.hpp>
|
||||
#include <boost/leaf/detail/dynamic_store_impl.hpp>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class T>
|
||||
result<T>::result( std::shared_ptr<leaf_detail::dynamic_store> && cap ) noexcept:
|
||||
cap_(std::move(cap)),
|
||||
which_(leaf_detail::result_variant::cap)
|
||||
{
|
||||
}
|
||||
|
||||
inline result<void>::result( std::shared_ptr<leaf_detail::dynamic_store> && cap ) noexcept:
|
||||
base(std::move(cap))
|
||||
{
|
||||
}
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class F, class mp_args, class... E>
|
||||
struct result_trap;
|
||||
|
||||
template <class F, template<class...> class L, class... A, class... E>
|
||||
struct result_trap<F, L<A...>,E...>
|
||||
{
|
||||
F f_;
|
||||
|
||||
public:
|
||||
|
||||
explicit result_trap( F && f ) noexcept:
|
||||
f_(std::move(f))
|
||||
{
|
||||
}
|
||||
|
||||
decltype(std::declval<F>()(std::declval<A>()...)) operator()( A ... a ) const
|
||||
{
|
||||
static_store<E...> ss;
|
||||
ss.set_reset(true);
|
||||
if( auto r = f_(std::forward<A>(a)...) )
|
||||
return r;
|
||||
else
|
||||
return decltype(r)( std::make_shared<dynamic_store_impl<E...>>(r.error(),std::move(ss)) );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <class... E, class F>
|
||||
leaf_detail::result_trap<F,typename leaf_detail::function_traits<F>::mp_args,E...> capture_result( F && f ) noexcept
|
||||
{
|
||||
using namespace leaf_detail;
|
||||
return result_trap<F,typename function_traits<F>::mp_args,E...>(std::move(f));
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
@@ -1,19 +1,19 @@
|
||||
#ifndef EBA7EF10B6F311E8AAD493990D39171A
|
||||
#define EBA7EF10B6F311E8AAD493990D39171A
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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/print.hpp>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <cassert>
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <cstring>
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
39
include/boost/leaf/detail/captured_exception.hpp
Normal file
39
include/boost/leaf/detail/captured_exception.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef BOOST_LEAF_E32F3CCC139011E995085E318C7F4AFC
|
||||
#define BOOST_LEAF_E32F3CCC139011E995085E318C7F4AFC
|
||||
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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 <exception>
|
||||
#include <ostream>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
class captured_exception:
|
||||
public std::exception
|
||||
{
|
||||
protected:
|
||||
|
||||
captured_exception() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
~captured_exception() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
[[noreturn]] virtual void unload_and_rethrow_original_exception() = 0;
|
||||
virtual void print( std::ostream & ) const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef BOOST_LEAF_E7999136FCD911E8B7F308A7642D5A5F
|
||||
#define BOOST_LEAF_E7999136FCD911E8B7F308A7642D5A5F
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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)
|
||||
|
||||
// core::demangle
|
||||
//
|
||||
|
||||
40
include/boost/leaf/detail/dynamic_store.hpp
Normal file
40
include/boost/leaf/detail/dynamic_store.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef BOOST_LEAF_6CCC5F56124B11E9B6C4CB8C8C7F4AFC
|
||||
#define BOOST_LEAF_6CCC5F56124B11E9B6C4CB8C8C7F4AFC
|
||||
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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 <ostream>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
class error_id;
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
class dynamic_store
|
||||
{
|
||||
protected:
|
||||
|
||||
dynamic_store() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
~dynamic_store() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
virtual error_id const & error() const noexcept = 0;
|
||||
virtual error_id unload() noexcept = 0;
|
||||
virtual error_id unload( error_id const & ) noexcept = 0;
|
||||
};
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
83
include/boost/leaf/detail/dynamic_store_impl.hpp
Normal file
83
include/boost/leaf/detail/dynamic_store_impl.hpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef BOOST_LEAF_C86E4C4ED0F011E8BB777EB8A659E189
|
||||
#define BOOST_LEAF_C86E4C4ED0F011E8BB777EB8A659E189
|
||||
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/static_store.hpp>
|
||||
#include <boost/leaf/detail/dynamic_store.hpp>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
namespace dynamic_store_internal
|
||||
{
|
||||
template <int I, class Tuple>
|
||||
struct tuple_for_each
|
||||
{
|
||||
static void unload( error_id const & id, Tuple && tup ) noexcept
|
||||
{
|
||||
tuple_for_each<I-1,Tuple>::unload(id,std::move(tup));
|
||||
auto && opt = std::get<I-1>(std::move(tup));
|
||||
if( opt.has_value() )
|
||||
(void) id.propagate(std::move(opt).value());
|
||||
}
|
||||
|
||||
static void print( std::ostream & os, Tuple const & tup )
|
||||
{
|
||||
typedef typename std::tuple_element<I-1,Tuple>::type ith_type;
|
||||
tuple_for_each<I-1,Tuple>::print(os,tup);
|
||||
auto & opt = std::get<I-1>(tup);
|
||||
if( opt.has_value() && diagnostic<typename ith_type::value_type>::print(os,opt.value()) )
|
||||
os << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Tuple>
|
||||
struct tuple_for_each<0, Tuple>
|
||||
{
|
||||
static void unload( error_id const &, Tuple && ) noexcept { }
|
||||
static void print( std::ostream &, Tuple const & ) noexcept { }
|
||||
};
|
||||
}
|
||||
|
||||
template <class... E>
|
||||
class dynamic_store_impl:
|
||||
public dynamic_store
|
||||
{
|
||||
error_id id_;
|
||||
std::tuple<leaf_detail::optional<E>...> s_;
|
||||
|
||||
error_id const & error() const noexcept
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
|
||||
error_id unload() noexcept
|
||||
{
|
||||
return unload(id_);
|
||||
}
|
||||
|
||||
error_id unload( error_id const & id ) noexcept
|
||||
{
|
||||
dynamic_store_internal::tuple_for_each<sizeof...(E),decltype(s_)>::unload(id,std::move(s_));
|
||||
return id;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
dynamic_store_impl( error_id const & id, static_store<E...> && ss ) noexcept:
|
||||
id_(id),
|
||||
s_(std::make_tuple( std::get<static_store_internal::tuple_type_index<static_store_internal::static_store_slot<E>,decltype(ss.s_)>::value>(std::move(ss.s_)).extract_optional(id)... ))
|
||||
{
|
||||
}
|
||||
};
|
||||
} // leaf_detail
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
@@ -1,14 +1,14 @@
|
||||
#ifndef BOOST_LEAF_14440B9CF07011E88377FD4B0ABE8030
|
||||
#define BOOST_LEAF_14440B9CF07011E88377FD4B0ABE8030
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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/mp11.hpp>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
@@ -17,10 +17,6 @@ namespace boost { namespace leaf {
|
||||
template <class...>
|
||||
using void_t = void;
|
||||
|
||||
template <class... T> struct mp_list { };
|
||||
template <class L> struct mp_rest { };
|
||||
template <class Car, class... Cdr> struct mp_rest<mp_list<Car, Cdr...>> { using type = mp_list<Cdr...>; };
|
||||
|
||||
template<class F,class V=void>
|
||||
struct function_traits
|
||||
{
|
||||
@@ -30,11 +26,15 @@ namespace boost { namespace leaf {
|
||||
struct function_traits<F,void_t<decltype(&F::operator())>>
|
||||
{
|
||||
private:
|
||||
|
||||
typedef function_traits<decltype(&F::operator())> tr;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename tr::return_type return_type;
|
||||
static constexpr int arity = tr::arity - 1;
|
||||
using mp_args = typename mp_rest<typename tr::mp_args>::type;
|
||||
|
||||
using mp_args = typename leaf_detail_mp11::mp_rest<typename tr::mp_args>;
|
||||
|
||||
template <int I>
|
||||
struct arg:
|
||||
@@ -49,14 +49,13 @@ namespace boost { namespace leaf {
|
||||
typedef R return_type;
|
||||
static constexpr int arity = sizeof...(A);
|
||||
|
||||
using mp_args = mp_list<A...>;
|
||||
using mp_args = leaf_detail_mp11::mp_list<A...>;
|
||||
|
||||
template <int I>
|
||||
struct arg
|
||||
{
|
||||
static_assert(I < arity, "I out of range");
|
||||
typedef typename std::tuple_element<I,std::tuple<A...>>::type type;
|
||||
typedef typename std::remove_cv<typename std::remove_reference<type>::type>::type type_;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -66,7 +65,7 @@ namespace boost { namespace leaf {
|
||||
template<class C, class R, class... A> struct function_traits<R(C::*)(A...)> : function_traits<R(C&,A...)> { };
|
||||
template<class C, class R, class... A> struct function_traits<R(C::*)(A...) const> : function_traits<R(C const &,A...)> { };
|
||||
template<class C, class R> struct function_traits<R(C::*)> : function_traits<R(C&)> { };
|
||||
} //namespace leaf_detail
|
||||
} // namespace leaf_detail
|
||||
|
||||
} }
|
||||
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
#ifndef BOOST_LEAF_F55070940BFF11E9A3EB73FBF47612F3
|
||||
#define BOOST_LEAF_F55070940BFF11E9A3EB73FBF47612F3
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/error.hpp>
|
||||
#include <boost/leaf/detail/function_traits.hpp>
|
||||
#include <tuple>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class R,bool IsIntegral=std::is_integral<R>::value>
|
||||
struct unhandled_error_base_helper;
|
||||
|
||||
template <class R>
|
||||
struct unhandled_error_base_helper<R,true>
|
||||
{
|
||||
static constexpr R value( leaf::error const & ) noexcept { return static_cast<R>(-1); }
|
||||
};
|
||||
|
||||
template <class R>
|
||||
struct unhandled_error_base_helper<R,false>
|
||||
{
|
||||
static constexpr R value( leaf::error const & ) noexcept { return R(); }
|
||||
};
|
||||
|
||||
template <class R>
|
||||
struct unhandled_error_base: unhandled_error_base_helper<R>
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct unhandled_error_base<bool>
|
||||
{
|
||||
static constexpr bool value( leaf::error const & ) noexcept { return false; }
|
||||
};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct uhnandled_error: leaf_detail::unhandled_error_base<T>
|
||||
{
|
||||
};
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class F,class R=typename function_traits<F>::return_type>
|
||||
struct handler_wrapper_base
|
||||
{
|
||||
typedef typename function_traits<F>::return_type return_type;
|
||||
|
||||
F f_;
|
||||
|
||||
explicit handler_wrapper_base( F && f ) noexcept:
|
||||
f_(std::forward<F>(f))
|
||||
{
|
||||
}
|
||||
|
||||
template <class... E>
|
||||
return_type operator()( E && ... e ) const
|
||||
{
|
||||
return f_(std::forward<E>(e)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class F>
|
||||
struct handler_wrapper_base<F,void>
|
||||
{
|
||||
typedef bool return_type;
|
||||
|
||||
F f_;
|
||||
|
||||
explicit handler_wrapper_base( F && f ) noexcept:
|
||||
f_(std::forward<F>(f))
|
||||
{
|
||||
}
|
||||
|
||||
template <class... E>
|
||||
return_type operator()( E && ... e ) const
|
||||
{
|
||||
f_(std::forward<E>(e)...);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class F, class R=void>
|
||||
struct handler_wrapper
|
||||
{
|
||||
typedef void return_type;
|
||||
};
|
||||
|
||||
template <class F>
|
||||
struct handler_wrapper<F,void_t<typename function_traits<F>::return_type>>: handler_wrapper_base<F>
|
||||
{
|
||||
explicit handler_wrapper( F && f ) noexcept:
|
||||
handler_wrapper_base<F>(std::forward<F>(f))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <class R1, class R2>
|
||||
struct handler_pack_return_type_helper
|
||||
{
|
||||
struct type;
|
||||
};
|
||||
|
||||
template <class R>
|
||||
struct handler_pack_return_type_helper<R,R>
|
||||
{
|
||||
typedef R type;
|
||||
};
|
||||
|
||||
template <class... F>
|
||||
struct handler_pack_return_type;
|
||||
|
||||
template <class F>
|
||||
struct handler_pack_return_type<F>
|
||||
{
|
||||
typedef typename handler_wrapper<F>::return_type return_type;
|
||||
};
|
||||
|
||||
template <class F1,class F2>
|
||||
struct handler_pack_return_type<F1,F2>
|
||||
{
|
||||
typedef typename handler_pack_return_type_helper<
|
||||
typename handler_wrapper<F1>::return_type,
|
||||
typename handler_wrapper<F2>::return_type>::type return_type;
|
||||
};
|
||||
|
||||
template <class F1,class F2,class... Rest>
|
||||
struct handler_pack_return_type<F1,F2,Rest...>
|
||||
{
|
||||
typedef typename handler_pack_return_type_helper<
|
||||
typename handler_wrapper<F1>::return_type,
|
||||
typename handler_pack_return_type<F2,Rest...>::return_type>::type return_type;
|
||||
};
|
||||
} //leaf_detail
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
211
include/boost/leaf/detail/mp11.hpp
Normal file
211
include/boost/leaf/detail/mp11.hpp
Normal file
@@ -0,0 +1,211 @@
|
||||
#ifndef BOOST_LEAF_91843B04108711E9AA4E56D98C7F4AFC
|
||||
#define BOOST_LEAF_91843B04108711E9AA4E56D98C7F4AFC
|
||||
|
||||
// Copyright 2015-2017 Peter Dimov.
|
||||
// Copyright 2019 Emil Dotchevski.
|
||||
//
|
||||
// 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 <type_traits>
|
||||
#include <cstddef>
|
||||
|
||||
namespace boost { namespace leaf { namespace leaf_detail_mp11 {
|
||||
|
||||
// mp_list<T...>
|
||||
template<class... T> struct mp_list
|
||||
{
|
||||
};
|
||||
|
||||
// mp_identity
|
||||
template<class T> struct mp_identity
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
// mp_inherit
|
||||
template<class... T> struct mp_inherit: T... {};
|
||||
|
||||
// mp_if, mp_if_c
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<bool C, class T, class... E> struct mp_if_c_impl
|
||||
{
|
||||
};
|
||||
|
||||
template<class T, class... E> struct mp_if_c_impl<true, T, E...>
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template<class T, class E> struct mp_if_c_impl<false, T, E>
|
||||
{
|
||||
using type = E;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<bool C, class T, class... E> using mp_if_c = typename detail::mp_if_c_impl<C, T, E...>::type;
|
||||
template<class C, class T, class... E> using mp_if = typename detail::mp_if_c_impl<static_cast<bool>(C::value), T, E...>::type;
|
||||
|
||||
// mp_bool
|
||||
template<bool B> using mp_bool = std::integral_constant<bool, B>;
|
||||
|
||||
using mp_true = mp_bool<true>;
|
||||
using mp_false = mp_bool<false>;
|
||||
|
||||
// mp_to_bool
|
||||
template<class T> using mp_to_bool = mp_bool<static_cast<bool>( T::value )>;
|
||||
|
||||
// mp_not<T>
|
||||
template<class T> using mp_not = mp_bool< !T::value >;
|
||||
|
||||
// mp_int
|
||||
template<int I> using mp_int = std::integral_constant<int, I>;
|
||||
|
||||
// mp_size_t
|
||||
template<std::size_t N> using mp_size_t = std::integral_constant<std::size_t, N>;
|
||||
|
||||
// mp_set_contains<S, V>
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class S, class V> struct mp_set_contains_impl;
|
||||
|
||||
template<template<class...> class L, class... T, class V> struct mp_set_contains_impl<L<T...>, V>
|
||||
{
|
||||
using type = mp_to_bool<std::is_base_of<mp_identity<V>, mp_inherit<mp_identity<T>...> > >;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class S, class V> using mp_set_contains = typename detail::mp_set_contains_impl<S, V>::type;
|
||||
|
||||
// mp_set_push_back<S, T...>
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class S, class... T> struct mp_set_push_back_impl;
|
||||
|
||||
template<template<class...> class L, class... U> struct mp_set_push_back_impl<L<U...>>
|
||||
{
|
||||
using type = L<U...>;
|
||||
};
|
||||
|
||||
template<template<class...> class L, class... U, class T1, class... T> struct mp_set_push_back_impl<L<U...>, T1, T...>
|
||||
{
|
||||
using S = mp_if<mp_set_contains<L<U...>, T1>, L<U...>, L<U..., T1>>;
|
||||
using type = typename mp_set_push_back_impl<S, T...>::type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class S, class... T> using mp_set_push_back = typename detail::mp_set_push_back_impl<S, T...>::type;
|
||||
|
||||
// mp_unique<L>
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class L> struct mp_unique_impl;
|
||||
|
||||
template<template<class...> class L, class... T> struct mp_unique_impl<L<T...>>
|
||||
{
|
||||
using type = mp_set_push_back<L<>, T...>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class L> using mp_unique = typename detail::mp_unique_impl<L>::type;
|
||||
|
||||
// mp_append<L...>
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class... L> struct mp_append_impl;
|
||||
|
||||
template<> struct mp_append_impl<>
|
||||
{
|
||||
using type = mp_list<>;
|
||||
};
|
||||
|
||||
template<template<class...> class L, class... T> struct mp_append_impl<L<T...>>
|
||||
{
|
||||
using type = L<T...>;
|
||||
};
|
||||
|
||||
template<template<class...> class L1, class... T1, template<class...> class L2, class... T2, class... Lr> struct mp_append_impl<L1<T1...>, L2<T2...>, Lr...>
|
||||
{
|
||||
using type = typename mp_append_impl<L1<T1..., T2...>, Lr...>::type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<class... L> using mp_append = typename detail::mp_append_impl<L...>::type;
|
||||
|
||||
// mp_front<L>
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class L> struct mp_front_impl
|
||||
{
|
||||
// An error "no type named 'type'" here means that the argument to mp_front
|
||||
// is either not a list, or is an empty list
|
||||
};
|
||||
|
||||
template<template<class...> class L, class T1, class... T> struct mp_front_impl<L<T1, T...>>
|
||||
{
|
||||
using type = T1;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class L> using mp_front = typename detail::mp_front_impl<L>::type;
|
||||
|
||||
// mp_pop_front<L>
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class L> struct mp_pop_front_impl
|
||||
{
|
||||
// An error "no type named 'type'" here means that the argument to mp_pop_front
|
||||
// is either not a list, or is an empty list
|
||||
};
|
||||
|
||||
template<template<class...> class L, class T1, class... T> struct mp_pop_front_impl<L<T1, T...>>
|
||||
{
|
||||
using type = L<T...>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class L> using mp_pop_front = typename detail::mp_pop_front_impl<L>::type;
|
||||
|
||||
// mp_first<L>
|
||||
template<class L> using mp_first = mp_front<L>;
|
||||
|
||||
// mp_rest<L>
|
||||
template<class L> using mp_rest = mp_pop_front<L>;
|
||||
|
||||
// mp_remove_if<L, P>
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class L, template<class...> class P> struct mp_remove_if_impl;
|
||||
|
||||
template<template<class...> class L, class... T, template<class...> class P> struct mp_remove_if_impl<L<T...>, P>
|
||||
{
|
||||
template<class U> using _f = mp_if<P<U>, mp_list<>, mp_list<U>>;
|
||||
using type = mp_append<L<>, _f<T>...>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class L, template<class...> class P> using mp_remove_if = typename detail::mp_remove_if_impl<L, P>::type;
|
||||
|
||||
} } }
|
||||
|
||||
#endif
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef BOOST_LEAF_47258FCCB6B411E8A1F35AA00C39171A
|
||||
#define BOOST_LEAF_47258FCCB6B411E8A1F35AA00C39171A
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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 <new>
|
||||
@@ -89,6 +89,15 @@ namespace boost { namespace leaf {
|
||||
}
|
||||
}
|
||||
|
||||
template <class... A>
|
||||
T & emplace( A && ... a )
|
||||
{
|
||||
reset();
|
||||
(void) new(&value_) T(std::forward<A>(a)...);
|
||||
has_value_=true;
|
||||
return value_;
|
||||
}
|
||||
|
||||
T & put( T const & v )
|
||||
{
|
||||
reset();
|
||||
@@ -105,39 +114,44 @@ namespace boost { namespace leaf {
|
||||
return value_;
|
||||
}
|
||||
|
||||
bool has_value() const noexcept
|
||||
T const * has_value() const noexcept
|
||||
{
|
||||
return has_value_;
|
||||
return has_value_ ? &value_ : 0;
|
||||
}
|
||||
|
||||
T * has_value() noexcept
|
||||
{
|
||||
return has_value_ ? &value_ : 0;
|
||||
}
|
||||
|
||||
T const & value() const & noexcept
|
||||
{
|
||||
assert(has_value());
|
||||
assert(has_value()!=0);
|
||||
return value_;
|
||||
}
|
||||
|
||||
T & value() & noexcept
|
||||
{
|
||||
assert(has_value());
|
||||
assert(has_value()!=0);
|
||||
return value_;
|
||||
}
|
||||
|
||||
T const && value() const && noexcept
|
||||
{
|
||||
assert(has_value());
|
||||
assert(has_value()!=0);
|
||||
return value_;
|
||||
}
|
||||
|
||||
T value() && noexcept
|
||||
{
|
||||
assert(has_value());
|
||||
assert(has_value()!=0);
|
||||
T tmp(std::move(value_));
|
||||
reset();
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
} //leaf_detail
|
||||
} // leaf_detail
|
||||
|
||||
} }
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef BOOST_LEAF_3BAB50A2B87E11E89EEB30600C39171A
|
||||
#define BOOST_LEAF_3BAB50A2B87E11E89EEB30600C39171A
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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 <ostream>
|
||||
#include <cstring>
|
||||
@@ -51,29 +51,25 @@ namespace boost { namespace leaf {
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class T, class E = void>
|
||||
struct is_printable
|
||||
struct is_printable: std::false_type
|
||||
{
|
||||
static constexpr bool value=false;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_printable<T, decltype(std::declval<std::ostream&>()<<std::declval<T const &>(), void())>
|
||||
struct is_printable<T, decltype(std::declval<std::ostream&>()<<std::declval<T const &>(), void())>: std::true_type
|
||||
{
|
||||
static constexpr bool value=true;
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class T, class E = void>
|
||||
struct has_printable_member_value
|
||||
struct has_printable_member_value: std::false_type
|
||||
{
|
||||
static constexpr bool value=false;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct has_printable_member_value<T, decltype(std::declval<std::ostream&>()<<std::declval<T const &>().value, void())>
|
||||
struct has_printable_member_value<T, decltype(std::declval<std::ostream&>()<<std::declval<T const &>().value, void())>: std::true_type
|
||||
{
|
||||
static constexpr bool value=true;
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
@@ -110,7 +106,16 @@ namespace boost { namespace leaf {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} //leaf_detail
|
||||
|
||||
template <>
|
||||
struct diagnostic<std::exception_ptr, false, false>
|
||||
{
|
||||
static bool print( std::ostream & os, std::exception_ptr const & )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} // leaf_detail
|
||||
|
||||
} }
|
||||
|
||||
|
||||
40
include/boost/leaf/detail/print_exception_info.hpp
Normal file
40
include/boost/leaf/detail/print_exception_info.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef BOOST_LEAF_E823AAD6151311E9A430DDBB67511AEB
|
||||
#define BOOST_LEAF_E823AAD6151311E9A430DDBB67511AEB
|
||||
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/error.hpp>
|
||||
#include <boost/leaf/detail/captured_exception.hpp>
|
||||
#include <boost/leaf/detail/demangle.hpp>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
void print_exception_info( std::ostream & os, std::exception const * ex, captured_exception const * cap )
|
||||
{
|
||||
if( cap )
|
||||
{
|
||||
os << "Detected exception_capture of the following error types:" << std::endl;
|
||||
cap->print(os);
|
||||
os << "Diagnostic Information about the original exception follows" << std::endl;
|
||||
}
|
||||
if( ex )
|
||||
{
|
||||
assert(!dynamic_cast<leaf_detail::captured_exception const *>(ex));
|
||||
os <<
|
||||
"Exception dynamic type: " << leaf_detail::demangle(typeid(*ex).name()) << std::endl <<
|
||||
"std::exception::what(): " << ex->what() << std::endl;
|
||||
}
|
||||
else
|
||||
os << "Unknown exception type (not a std::exception)" << std::endl;
|
||||
}
|
||||
} // namespace leaf_detail
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
513
include/boost/leaf/detail/static_store.hpp
Normal file
513
include/boost/leaf/detail/static_store.hpp
Normal file
@@ -0,0 +1,513 @@
|
||||
#ifndef BOOST_LEAF_AFBBD676B2FF11E8984C7976AE35F1A2
|
||||
#define BOOST_LEAF_AFBBD676B2FF11E8984C7976AE35F1A2
|
||||
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/error.hpp>
|
||||
#include <boost/leaf/detail/function_traits.hpp>
|
||||
#include <boost/leaf/detail/mp11.hpp>
|
||||
#include <tuple>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class E,bool HasValue = has_data_member_value<E>::value>
|
||||
struct match_type;
|
||||
|
||||
template <class E>
|
||||
struct match_type<E,true>
|
||||
{
|
||||
using type = decltype(E::value);
|
||||
|
||||
static type const & get( E const & e ) noexcept
|
||||
{
|
||||
return e.value;
|
||||
}
|
||||
};
|
||||
|
||||
template <class E>
|
||||
struct match_type<E,false>
|
||||
{
|
||||
using type = E;
|
||||
|
||||
static type const & get( E const & e ) noexcept
|
||||
{
|
||||
return e;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
bool check_value_pack( T const & x, T const & v ) noexcept
|
||||
{
|
||||
return x==v;
|
||||
}
|
||||
|
||||
template <class T, class... VRest>
|
||||
bool check_value_pack( T const & x, T const & v1, VRest const & ... v_rest ) noexcept
|
||||
{
|
||||
return x==v1 || check_value_pack(x,v_rest...);
|
||||
}
|
||||
|
||||
template <class Ex>
|
||||
bool check_exception_pack( std::exception const * ex, Ex const * ) noexcept
|
||||
{
|
||||
return dynamic_cast<Ex const *>(ex)!=0;
|
||||
}
|
||||
|
||||
template <class Ex, class... ExRest>
|
||||
bool check_exception_pack( std::exception const * ex, Ex const *, ExRest const * ... ex_rest ) noexcept
|
||||
{
|
||||
return dynamic_cast<Ex const *>(ex)!=0 || check_exception_pack(ex, ex_rest...);
|
||||
}
|
||||
}
|
||||
|
||||
template <class E, typename leaf_detail::match_type<E>::type... V>
|
||||
struct match
|
||||
{
|
||||
using type = typename leaf_detail::match_type<E>::type;
|
||||
type const & value;
|
||||
|
||||
explicit match( E const & e ):
|
||||
value(leaf_detail::match_type<E>::get(e))
|
||||
{
|
||||
}
|
||||
|
||||
bool operator()() const noexcept
|
||||
{
|
||||
return leaf_detail::check_value_pack(value,V...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class... Ex>
|
||||
struct catch_
|
||||
{
|
||||
std::exception const & value;
|
||||
|
||||
explicit catch_( std::exception const & ex ):
|
||||
value(ex)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator()() const noexcept
|
||||
{
|
||||
return leaf_detail::check_exception_pack(&value,static_cast<Ex const *>(0)...);
|
||||
}
|
||||
};
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
namespace static_store_internal
|
||||
{
|
||||
template <int I, class Tuple>
|
||||
struct tuple_for_each
|
||||
{
|
||||
static void reset( Tuple & tup ) noexcept
|
||||
{
|
||||
tuple_for_each<I-1,Tuple>::reset(tup);
|
||||
std::get<I-1>(tup).reset();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Tuple>
|
||||
struct tuple_for_each<0, Tuple>
|
||||
{
|
||||
static void reset( Tuple & ) noexcept { }
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
class enable_any
|
||||
{
|
||||
protected:
|
||||
|
||||
enable_any() noexcept
|
||||
{
|
||||
++tl_unexpected_enabled_counter();
|
||||
}
|
||||
|
||||
~enable_any() noexcept
|
||||
{
|
||||
--tl_unexpected_enabled_counter();
|
||||
}
|
||||
};
|
||||
|
||||
template <class E>
|
||||
class static_store_slot:
|
||||
public slot<E>
|
||||
{
|
||||
public:
|
||||
optional<E> extract_optional( error_id const & id ) && noexcept
|
||||
{
|
||||
slot<E> const & s = *this;
|
||||
if( s.has_value() && s.value().id==id )
|
||||
return optional<E>(std::move(*this).value().e);
|
||||
else
|
||||
return optional<E>();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class static_store_slot<diagnostic_info>:
|
||||
public slot<diagnostic_info>,
|
||||
enable_any
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
class static_store_slot<verbose_diagnostic_info>:
|
||||
public slot<verbose_diagnostic_info>,
|
||||
enable_any
|
||||
{
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class T, class... List>
|
||||
struct type_index;
|
||||
|
||||
template <class T, class... Cdr>
|
||||
struct type_index<T, T, Cdr...>
|
||||
{
|
||||
static const int value = 0;
|
||||
};
|
||||
|
||||
template <class T, class Car, class... Cdr>
|
||||
struct type_index<T, Car, Cdr...>
|
||||
{
|
||||
static const int value = 1 + type_index<T,Cdr...>::value;
|
||||
};
|
||||
|
||||
template <class T, class Tuple>
|
||||
struct tuple_type_index;
|
||||
|
||||
template <class T, class... TupleTypes>
|
||||
struct tuple_type_index<T,std::tuple<TupleTypes...>>
|
||||
{
|
||||
static const int value = type_index<T,TupleTypes...>::value;
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class SlotsTuple,class T>
|
||||
struct check_one_argument
|
||||
{
|
||||
static bool check( SlotsTuple const & tup, error_info const & ei ) noexcept
|
||||
{
|
||||
auto & sl = std::get<tuple_type_index<static_store_slot<T>,SlotsTuple>::value>(tup);
|
||||
return sl.has_value() && sl.value().id==ei.error();
|
||||
}
|
||||
};
|
||||
|
||||
template <class SlotsTuple,class T>
|
||||
struct check_one_argument<SlotsTuple,T *>
|
||||
{
|
||||
static bool check( SlotsTuple const &, error_info const & ) noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class SlotsTuple, class E, typename match_type<E>::type... V>
|
||||
struct check_one_argument<SlotsTuple,match<E,V...>>
|
||||
{
|
||||
static bool check( SlotsTuple const & tup, error_info const & ei ) noexcept
|
||||
{
|
||||
auto & sl = std::get<tuple_type_index<static_store_slot<E>,SlotsTuple>::value>(tup);
|
||||
if( sl.has_value() )
|
||||
{
|
||||
auto const & v = sl.value();
|
||||
return v.id==ei.error() && match<E,V...>(v.e)();
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class SlotsTuple, class... Ex>
|
||||
struct check_one_argument<SlotsTuple,catch_<Ex...>>
|
||||
{
|
||||
static bool check( SlotsTuple const &, error_info const & ei ) noexcept
|
||||
{
|
||||
if( std::exception const * ex = ei.exception() )
|
||||
return catch_<Ex...>(*ex)();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class SlotsTuple>
|
||||
struct check_one_argument<SlotsTuple,error_info>
|
||||
{
|
||||
static constexpr bool check( SlotsTuple const &, error_info const & )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class SlotsTuple, class... List>
|
||||
struct check_arguments;
|
||||
|
||||
template <class SlotsTuple, class Car, class... Cdr>
|
||||
struct check_arguments<SlotsTuple, Car, Cdr...>
|
||||
{
|
||||
static bool check( SlotsTuple const & tup, error_info const & ei ) noexcept
|
||||
{
|
||||
return check_one_argument<SlotsTuple,Car>::check(tup,ei) && check_arguments<SlotsTuple,Cdr...>::check(tup,ei);
|
||||
}
|
||||
};
|
||||
|
||||
template <class SlotsTuple>
|
||||
struct check_arguments<SlotsTuple>
|
||||
{
|
||||
static constexpr bool check( SlotsTuple const &, error_info const & ) noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
struct get_one_argument
|
||||
{
|
||||
template <class StaticStore>
|
||||
static T const & get( StaticStore const & ss, error_info const & ei ) noexcept
|
||||
{
|
||||
T const * arg = ss.template peek<T>(ei.error());
|
||||
assert(arg!=0);
|
||||
return *arg;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct get_one_argument<T const *>
|
||||
{
|
||||
template <class StaticStore>
|
||||
static T const * get( StaticStore const & ss, error_info const & ei ) noexcept
|
||||
{
|
||||
return ss.template peek<T>(ei.error());
|
||||
}
|
||||
};
|
||||
|
||||
template <class E, typename match_type<E>::type... V>
|
||||
struct get_one_argument<match<E,V...>>
|
||||
{
|
||||
template <class StaticStore>
|
||||
static match<E,V...> get( StaticStore const & ss, error_info const & ei ) noexcept
|
||||
{
|
||||
E const * arg = ss.template peek<E>(ei.error());
|
||||
assert(arg!=0);
|
||||
return match<E,V...>(*arg);
|
||||
}
|
||||
};
|
||||
|
||||
template <class... Ex>
|
||||
struct get_one_argument<catch_<Ex...>>
|
||||
{
|
||||
template <class StaticStore>
|
||||
static catch_<Ex...> get( StaticStore const &, error_info const & ei ) noexcept
|
||||
{
|
||||
std::exception const * ex = ei.exception();
|
||||
assert(ex!=0);
|
||||
return catch_<Ex...>(*ex);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct get_one_argument<error_info>
|
||||
{
|
||||
template <class StaticStore>
|
||||
static error_info const & get( StaticStore const &, error_info const & ei ) noexcept
|
||||
{
|
||||
return ei;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct get_one_argument<diagnostic_info>
|
||||
{
|
||||
template <class StaticStore>
|
||||
static diagnostic_info const & get( StaticStore const & ss, error_info const & ei ) noexcept
|
||||
{
|
||||
diagnostic_info const * uei = ss.template peek<diagnostic_info>(ei.error());
|
||||
assert(uei!=0);
|
||||
uei->set_error_info(ei);
|
||||
return *uei;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct get_one_argument<verbose_diagnostic_info>
|
||||
{
|
||||
template <class StaticStore>
|
||||
static verbose_diagnostic_info const & get( StaticStore const & ss, error_info const & ei ) noexcept
|
||||
{
|
||||
verbose_diagnostic_info const * vdi = ss.template peek<verbose_diagnostic_info>(ei.error());
|
||||
assert(vdi!=0);
|
||||
vdi->set_error_info(ei);
|
||||
return *vdi;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class T> struct argument_matches_any_error: std::false_type { };
|
||||
template <class T> struct argument_matches_any_error<T const *>: is_error_type<T> { };
|
||||
template <> struct argument_matches_any_error<error_info const &>: std::true_type { };
|
||||
template <> struct argument_matches_any_error<diagnostic_info const &>: std::true_type { };
|
||||
template <> struct argument_matches_any_error<verbose_diagnostic_info const &>: std::true_type { };
|
||||
|
||||
template <class>
|
||||
struct handler_matches_any_error: std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <template<class...> class L, class Car, class... Cdr>
|
||||
struct handler_matches_any_error<L<Car,Cdr...>>
|
||||
{
|
||||
constexpr static bool value = argument_matches_any_error<Car>::value && handler_matches_any_error<L<Cdr...>>::value;
|
||||
};
|
||||
|
||||
template <template<class...> class L>
|
||||
struct handler_matches_any_error<L<>>: std::true_type
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
template <class... T>
|
||||
class dynamic_store_impl;
|
||||
|
||||
template <class... E>
|
||||
class static_store
|
||||
{
|
||||
template <class... T>
|
||||
friend class dynamic_store_impl;
|
||||
|
||||
static_store( static_store const & ) = delete;
|
||||
static_store & operator=( static_store const & ) = delete;
|
||||
|
||||
std::tuple<static_store_internal::static_store_slot<E>...> s_;
|
||||
bool reset_;
|
||||
|
||||
template <class... T>
|
||||
bool check_handler( error_info const & ei, leaf_detail_mp11::mp_list<T...> ) const noexcept
|
||||
{
|
||||
using namespace static_store_internal;
|
||||
return check_arguments<decltype(s_),typename std::remove_cv<typename std::remove_reference<T>::type>::type...>::check(s_,ei);
|
||||
}
|
||||
|
||||
template <class F,class... T>
|
||||
typename function_traits<F>::return_type call_handler( error_info const & ei, F && f, leaf_detail_mp11::mp_list<T...> ) const
|
||||
{
|
||||
using namespace static_store_internal;
|
||||
return std::forward<F>(f)( get_one_argument<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::get(*this,ei)... );
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
constexpr explicit static_store() noexcept:
|
||||
reset_(false)
|
||||
{
|
||||
}
|
||||
|
||||
~static_store() noexcept
|
||||
{
|
||||
if( reset_&& !std::uncaught_exception() )
|
||||
static_store_internal::tuple_for_each<sizeof...(E),decltype(s_)>::reset(s_);
|
||||
}
|
||||
|
||||
void set_reset( bool r ) noexcept
|
||||
{
|
||||
reset_ = r;
|
||||
}
|
||||
|
||||
template <class P>
|
||||
P const * peek( error_id const & id ) const noexcept
|
||||
{
|
||||
auto & opt = std::get<static_store_internal::type_index<P,E...>::value>(s_);
|
||||
if( opt.has_value() )
|
||||
{
|
||||
auto & v = opt.value();
|
||||
if( v.id==id )
|
||||
return &v.e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
typename function_traits<F>::return_type handle_error( error_info const & ei, F && f ) const
|
||||
{
|
||||
using namespace static_store_internal;
|
||||
static_assert( handler_matches_any_error<typename function_traits<F>::mp_args>::value, "The last handler passed to handle_all must match any error." );
|
||||
return call_handler( ei, std::forward<F>(f), typename function_traits<F>::mp_args{ } );
|
||||
}
|
||||
|
||||
template <class CarF, class CdarF, class... CddrF>
|
||||
typename function_traits<CarF>::return_type handle_error( error_info const & ei, CarF && car_f, CdarF && cdar_f, CddrF && ... cddr_f ) const
|
||||
{
|
||||
using namespace static_store_internal;
|
||||
if( handler_matches_any_error<typename function_traits<CarF>::mp_args>::value || check_handler( ei, typename function_traits<CarF>::mp_args{ } ) )
|
||||
return call_handler( ei, std::forward<CarF>(car_f), typename function_traits<CarF>::mp_args{ } );
|
||||
else
|
||||
return handle_error( ei, std::forward<CdarF>(cdar_f), std::forward<CddrF>(cddr_f)...);
|
||||
}
|
||||
};
|
||||
|
||||
// Static store deduction
|
||||
|
||||
template <class T> struct translate_expect_deduction { typedef T type; };
|
||||
template <class T> struct translate_expect_deduction<T const> { typedef T type; };
|
||||
template <class T> struct translate_expect_deduction<T const &> { typedef T type; };
|
||||
template <class T> struct translate_expect_deduction<T const *> { typedef T type; };
|
||||
template <class E,typename match_type<E>::type... V> struct translate_expect_deduction<match<E,V...>> { typedef E type; };
|
||||
template <class... Exceptions> struct translate_expect_deduction<catch_<Exceptions...>> { typedef void type; };
|
||||
|
||||
template <class... T>
|
||||
struct translate_list_impl;
|
||||
|
||||
template <template<class...> class L, class... T>
|
||||
struct translate_list_impl<L<T...>>
|
||||
{
|
||||
using type = leaf_detail_mp11::mp_list<typename translate_expect_deduction<T>::type...>;
|
||||
};
|
||||
|
||||
template <class... T> using translate_list = typename translate_list_impl<T...>::type;
|
||||
|
||||
template <class T> struct does_not_participate_in_expect_deduction: std::false_type { };
|
||||
template <> struct does_not_participate_in_expect_deduction<error_info>: std::true_type { };
|
||||
template <> struct does_not_participate_in_expect_deduction<void>: std::true_type { };
|
||||
|
||||
template <class... Handler>
|
||||
struct handler_args_set
|
||||
{
|
||||
using type =
|
||||
leaf_detail_mp11::mp_remove_if<
|
||||
leaf_detail_mp11::mp_unique<
|
||||
translate_list<
|
||||
leaf_detail_mp11::mp_append<
|
||||
typename function_traits<Handler>::mp_args...
|
||||
>
|
||||
>
|
||||
>,
|
||||
does_not_participate_in_expect_deduction
|
||||
>;
|
||||
};
|
||||
|
||||
template <class L>
|
||||
struct deduce_static_store;
|
||||
|
||||
template <template<class...> class L, class... T>
|
||||
struct deduce_static_store<L<T...>>
|
||||
{
|
||||
typedef static_store<T...> type;
|
||||
};
|
||||
} // leaf_detail
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
@@ -1,55 +0,0 @@
|
||||
#ifndef BOOST_LEAF_17228D24F83C11E8AAC53F8F652D5A5F
|
||||
#define BOOST_LEAF_17228D24F83C11E8AAC53F8F652D5A5F
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/exception_capture.hpp>
|
||||
#include <boost/leaf/detail/demangle.hpp>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class... E>
|
||||
void diagnostic_output_current_exception( std::ostream & os, expect<E...> const & exp )
|
||||
{
|
||||
os << "Current Exception Diagnostic Information:" << std::endl;
|
||||
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch( std::exception const & ex )
|
||||
{
|
||||
os <<
|
||||
"Exception dynamic type: " << leaf_detail::demangle(typeid(ex).name()) << std::endl <<
|
||||
"std::exception::what(): " << ex.what() << std::endl;
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
os << "Unknown exception type (not a std::exception)" << std::endl;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch( leaf_detail::captured_exception const & e )
|
||||
{
|
||||
diagnostic_output_(os,e);
|
||||
}
|
||||
catch( error const & e )
|
||||
{
|
||||
diagnostic_output(os,exp,e);
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
diagnostic_output(os,exp);
|
||||
}
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef BOOST_LEAF_BA049396D0D411E8B45DF7D4A759E189
|
||||
#define BOOST_LEAF_BA049396D0D411E8B45DF7D4A759E189
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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/optional.hpp>
|
||||
#include <boost/leaf/detail/print.hpp>
|
||||
@@ -22,84 +22,21 @@ namespace boost { namespace system { class error_code; } }
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
struct e_source_location
|
||||
class error_id;
|
||||
|
||||
error_id next_error() noexcept;
|
||||
error_id last_error() noexcept;
|
||||
|
||||
class error_id
|
||||
{
|
||||
char const * const file;
|
||||
int const line;
|
||||
char const * const function;
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, e_source_location const & x )
|
||||
{
|
||||
return os << leaf::type<e_source_location>() << ": " << x.file << '(' << x.line << ") in function " << x.function;
|
||||
}
|
||||
};
|
||||
|
||||
struct e_unexpected
|
||||
{
|
||||
char const * (*first_type)() noexcept;
|
||||
int count;
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, e_unexpected const & x )
|
||||
{
|
||||
assert(x.first_type!=0);
|
||||
assert(x.count>0);
|
||||
if( x.count==1 )
|
||||
os << "Detected 1 attempt to communicate an unexpected error object of type ";
|
||||
else
|
||||
os << "Detected " << x.count << " attempts to communicate unexpected error objects, the first one of type ";
|
||||
return os << x.first_type();
|
||||
}
|
||||
};
|
||||
|
||||
struct e_unexpected_diagnostic_output
|
||||
{
|
||||
std::string value;
|
||||
std::set<char const *(*)()> already;
|
||||
friend std::ostream & operator<<( std::ostream & os, e_unexpected_diagnostic_output const & x ) noexcept { return os; }
|
||||
};
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class T, class E = void>
|
||||
struct has_data_member_value
|
||||
{
|
||||
static constexpr bool value=false;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct has_data_member_value<T, decltype(std::declval<T const &>().value, void())>
|
||||
{
|
||||
static constexpr bool value=std::is_member_object_pointer<decltype(&T::value)>::value;
|
||||
};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct is_error_type
|
||||
{
|
||||
static constexpr bool value = leaf_detail::has_data_member_value<T>::value || std::is_base_of<std::exception,T>::value;
|
||||
};
|
||||
|
||||
template <> struct is_error_type<std::exception_ptr>: std::true_type { };
|
||||
template <> struct is_error_type<std::error_code>: std::true_type { };
|
||||
template <> struct is_error_type<system::error_code>: std::true_type { };
|
||||
template <> struct is_error_type<e_unexpected>: std::true_type { };
|
||||
template <> struct is_error_type<e_source_location>: std::true_type { };
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
class error;
|
||||
|
||||
error next_error_value() noexcept;
|
||||
error last_error_value() noexcept;
|
||||
|
||||
class error
|
||||
{
|
||||
friend error leaf::next_error_value() noexcept;
|
||||
friend error leaf::last_error_value() noexcept;
|
||||
template <class... E>
|
||||
friend error_id new_error( E && ... ) noexcept;
|
||||
friend error_id leaf::next_error() noexcept;
|
||||
friend error_id leaf::last_error() noexcept;
|
||||
|
||||
unsigned id_;
|
||||
|
||||
explicit error( unsigned id ) noexcept:
|
||||
explicit error_id( unsigned id ) noexcept:
|
||||
id_(id)
|
||||
{
|
||||
}
|
||||
@@ -152,51 +89,342 @@ namespace boost { namespace leaf {
|
||||
|
||||
public:
|
||||
|
||||
error() noexcept:
|
||||
id_(id_factory::tl_instance().get())
|
||||
{
|
||||
}
|
||||
|
||||
template <class... E>
|
||||
explicit error( E && ... e ) noexcept:
|
||||
id_(id_factory::tl_instance().get())
|
||||
{
|
||||
propagate(std::forward<E>(e)...);
|
||||
}
|
||||
|
||||
friend bool operator==( error const & e1, error const & e2 ) noexcept
|
||||
friend bool operator==( error_id const & e1, error_id const & e2 ) noexcept
|
||||
{
|
||||
return e1.id_==e2.id_;
|
||||
}
|
||||
|
||||
friend bool operator!=( error const & e1, error const & e2 ) noexcept
|
||||
friend bool operator!=( error_id const & e1, error_id const & e2 ) noexcept
|
||||
{
|
||||
return e1.id_!=e2.id_;
|
||||
}
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, error const & e )
|
||||
{
|
||||
os << e.id_;
|
||||
return os;
|
||||
}
|
||||
|
||||
error propagate() const noexcept
|
||||
error_id propagate() const noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, error_id const & id )
|
||||
{
|
||||
os << id.id_;
|
||||
return os;
|
||||
}
|
||||
|
||||
template <class... E>
|
||||
error propagate( E && ... ) const noexcept;
|
||||
error_id propagate( E && ... ) const noexcept;
|
||||
};
|
||||
|
||||
inline error next_error_value() noexcept
|
||||
template <class... E>
|
||||
error_id new_error( E && ... e ) noexcept
|
||||
{
|
||||
return error(error::id_factory::tl_instance().next_id());
|
||||
return error_id(error_id::id_factory::tl_instance().get()).propagate(std::forward<E>(e)...);
|
||||
}
|
||||
|
||||
inline error last_error_value() noexcept
|
||||
inline error_id next_error() noexcept
|
||||
{
|
||||
return error(error::id_factory::tl_instance().last_id());
|
||||
return error_id(error_id::id_factory::tl_instance().next_id());
|
||||
}
|
||||
|
||||
inline error_id last_error() noexcept
|
||||
{
|
||||
return error_id(error_id::id_factory::tl_instance().last_id());
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
class slot_base
|
||||
{
|
||||
slot_base( slot_base const & ) = delete;
|
||||
slot_base & operator=( slot_base const & ) = delete;
|
||||
|
||||
virtual bool slot_print( std::ostream &, error_id const & ) const = 0;
|
||||
|
||||
public:
|
||||
|
||||
static void print( std::ostream & os, error_id const & id )
|
||||
{
|
||||
for( slot_base const * p = first(); p; p=p->next_ )
|
||||
if( p->slot_print(os,id) )
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static slot_base const * & first() noexcept
|
||||
{
|
||||
static thread_local slot_base const * p = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
slot_base const * const next_;
|
||||
|
||||
slot_base() noexcept:
|
||||
next_(first())
|
||||
{
|
||||
first() = this;
|
||||
}
|
||||
|
||||
~slot_base() noexcept
|
||||
{
|
||||
slot_base const * & p = first();
|
||||
assert(p==this);
|
||||
p = next_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace leaf_detail { class captured_exception; }
|
||||
|
||||
class error_info
|
||||
{
|
||||
error_info( error_info const & ) = delete;
|
||||
error_info & operator=( error_info const & ) = delete;
|
||||
|
||||
error_id const id_;
|
||||
std::exception const * const ex_;
|
||||
leaf_detail::captured_exception const * const cap_;
|
||||
void (* const print_ex_)( std::ostream &, std::exception const *, leaf_detail::captured_exception const * );
|
||||
|
||||
public:
|
||||
|
||||
explicit error_info( error_id const & id ) noexcept:
|
||||
id_(id),
|
||||
ex_(0),
|
||||
cap_(0),
|
||||
print_ex_(0)
|
||||
{
|
||||
}
|
||||
|
||||
error_info( error_id const & id, std::exception const * ex, void (*print_ex)(std::ostream &, std::exception const *, leaf_detail::captured_exception const *) ) noexcept:
|
||||
id_(id),
|
||||
ex_(ex),
|
||||
cap_(0),
|
||||
print_ex_(print_ex)
|
||||
{
|
||||
assert(print_ex_!=0);
|
||||
}
|
||||
|
||||
error_info( error_id const & id, std::exception const * ex, leaf_detail::captured_exception const * cap, void (*print_ex)(std::ostream &, std::exception const *, leaf_detail::captured_exception const *) ) noexcept:
|
||||
id_(id),
|
||||
ex_(ex),
|
||||
cap_(cap),
|
||||
print_ex_(print_ex)
|
||||
{
|
||||
assert(print_ex_!=0);
|
||||
}
|
||||
|
||||
error_id const & error() const noexcept
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
|
||||
bool exception_caught() const noexcept
|
||||
{
|
||||
return print_ex_!=0;
|
||||
}
|
||||
|
||||
std::exception const * exception() const noexcept
|
||||
{
|
||||
assert(exception_caught());
|
||||
return ex_;
|
||||
}
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, error_info const & x )
|
||||
{
|
||||
os << "leaf::error_id: " << x.id_ << std::endl;
|
||||
if( x.print_ex_ )
|
||||
x.print_ex_(os,x.ex_,x.cap_);
|
||||
leaf_detail::slot_base::print(os,x.id_);
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class T, class E = void>
|
||||
struct has_data_member_value
|
||||
{
|
||||
static constexpr bool value=false;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct has_data_member_value<T, decltype(std::declval<T const &>().value, void())>
|
||||
{
|
||||
static constexpr bool value=std::is_member_object_pointer<decltype(&T::value)>::value;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_error_type_default
|
||||
{
|
||||
static constexpr bool value = has_data_member_value<T>::value || std::is_base_of<std::exception,T>::value;
|
||||
};
|
||||
|
||||
template <> struct is_error_type_default<std::exception_ptr>: std::true_type { };
|
||||
template <> struct is_error_type_default<std::error_code>: std::true_type { };
|
||||
template <> struct is_error_type_default<system::error_code>: std::true_type { };
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct is_error_type: leaf_detail::is_error_type_default<T>
|
||||
{
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
struct e_source_location
|
||||
{
|
||||
char const * const file;
|
||||
int const line;
|
||||
char const * const function;
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, e_source_location const & x )
|
||||
{
|
||||
return os << leaf::type<e_source_location>() << ": " << x.file << '(' << x.line << ") in function " << x.function;
|
||||
}
|
||||
};
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <> struct is_error_type_default<e_source_location>: std::true_type { };
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
class monitor_base
|
||||
{
|
||||
monitor_base( monitor_base const & ) = delete;
|
||||
monitor_base & operator=( monitor_base const & ) = delete;
|
||||
|
||||
mutable error_info const * ei_;
|
||||
|
||||
protected:
|
||||
|
||||
monitor_base() noexcept:
|
||||
ei_(0)
|
||||
{
|
||||
}
|
||||
|
||||
monitor_base( monitor_base && x ) noexcept:
|
||||
ei_(0)
|
||||
{
|
||||
x.ei_ = 0;
|
||||
}
|
||||
|
||||
void set_error_info( error_info const & ei ) const noexcept
|
||||
{
|
||||
ei_ = &ei;
|
||||
}
|
||||
|
||||
error_info const & get_error_info() const noexcept
|
||||
{
|
||||
assert(ei_!=0);
|
||||
return *ei_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class diagnostic_info: leaf_detail::monitor_base
|
||||
{
|
||||
public:
|
||||
|
||||
char const * (*first_type)();
|
||||
int count;
|
||||
|
||||
explicit diagnostic_info( char const * (*first_type)() ) noexcept:
|
||||
first_type(first_type),
|
||||
count(1)
|
||||
{
|
||||
}
|
||||
|
||||
using monitor_base::set_error_info;
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, diagnostic_info const & x )
|
||||
{
|
||||
assert(x.first_type!=0);
|
||||
assert(x.count>0);
|
||||
os << x.get_error_info() << "diagnostic_info: Detected ";
|
||||
if( x.count==1 )
|
||||
os << "1 attempt to communicate an E-object";
|
||||
else
|
||||
os << x.count << " attempts to communicate unexpected E-objects, the first one";
|
||||
return os << " of type " << x.first_type() << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <> struct is_error_type_default<diagnostic_info>: std::true_type { };
|
||||
|
||||
template <>
|
||||
struct diagnostic<diagnostic_info,true,false>
|
||||
{
|
||||
static bool print( std::ostream & os, diagnostic_info const & ) noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class verbose_diagnostic_info: leaf_detail::monitor_base
|
||||
{
|
||||
std::string s_;
|
||||
std::set<char const *(*)()> already_;
|
||||
|
||||
public:
|
||||
|
||||
verbose_diagnostic_info() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
using monitor_base::set_error_info;
|
||||
|
||||
void reset() noexcept
|
||||
{
|
||||
s_.clear();
|
||||
already_.clear();
|
||||
}
|
||||
|
||||
template <class E>
|
||||
void add( E const & e )
|
||||
{
|
||||
std::stringstream s;
|
||||
if( leaf_detail::diagnostic<E>::print(s,e) && already_.insert(&type<E>).second )
|
||||
{
|
||||
s << std::endl;
|
||||
s_ += s.str();
|
||||
}
|
||||
}
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, verbose_diagnostic_info const & x )
|
||||
{
|
||||
os <<
|
||||
x.get_error_info() <<
|
||||
"verbose_diagnostic_info:" << std::endl <<
|
||||
x.s_;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <> struct is_error_type_default<verbose_diagnostic_info>: std::true_type { };
|
||||
|
||||
template <>
|
||||
struct diagnostic<verbose_diagnostic_info,true,false>
|
||||
{
|
||||
static bool print( std::ostream & os, verbose_diagnostic_info const & ) noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
@@ -204,10 +432,27 @@ namespace boost { namespace leaf {
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class E>
|
||||
struct error_info
|
||||
struct id_e_pair
|
||||
{
|
||||
E v;
|
||||
error e;
|
||||
error_id id;
|
||||
E e;
|
||||
|
||||
explicit id_e_pair( error_id const & id ) noexcept:
|
||||
id(id)
|
||||
{
|
||||
}
|
||||
|
||||
id_e_pair( error_id const & id, E const & e ):
|
||||
id(id),
|
||||
e(e)
|
||||
{
|
||||
}
|
||||
|
||||
id_e_pair( error_id const & id, E && e ) noexcept:
|
||||
id(id),
|
||||
e(std::forward<E>(e))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline int & tl_unexpected_enabled_counter() noexcept
|
||||
@@ -215,24 +460,37 @@ namespace boost { namespace leaf {
|
||||
static thread_local int c;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class E>
|
||||
class slot:
|
||||
optional<error_info<E>>
|
||||
slot_base,
|
||||
optional<id_e_pair<E>>
|
||||
{
|
||||
slot( slot const & ) = delete;
|
||||
slot & operator=( slot const & ) = delete;
|
||||
typedef optional<error_info<E>> base;
|
||||
typedef optional<id_e_pair<E>> base;
|
||||
slot<E> * prev_;
|
||||
static_assert(is_error_type<E>::value,"Not an error type");
|
||||
|
||||
bool slot_print( std::ostream &, error_id const & ) const;
|
||||
|
||||
protected:
|
||||
|
||||
slot() noexcept;
|
||||
~slot() noexcept;
|
||||
|
||||
public:
|
||||
|
||||
using base::put;
|
||||
using base::has_value;
|
||||
using base::value;
|
||||
using base::reset;
|
||||
using base::emplace;
|
||||
};
|
||||
|
||||
template <class E>
|
||||
@@ -243,69 +501,61 @@ namespace boost { namespace leaf {
|
||||
}
|
||||
|
||||
template <class E>
|
||||
void put_unexpected( error_info<E> const & ev ) noexcept
|
||||
void put_unexpected( id_e_pair<E> const & id_e ) noexcept
|
||||
{
|
||||
if( slot<e_unexpected> * p = tl_slot_ptr<e_unexpected>() )
|
||||
if( slot<diagnostic_info> * p = tl_slot_ptr<diagnostic_info>() )
|
||||
{
|
||||
if( p->has_value() )
|
||||
{
|
||||
auto & p_ev = p->value();
|
||||
if( p_ev.e==ev.e )
|
||||
auto & p_id_e = p->value();
|
||||
if( p_id_e.id==id_e.id )
|
||||
{
|
||||
++p_ev.v.count;
|
||||
++p_id_e.e.count;
|
||||
return;
|
||||
}
|
||||
}
|
||||
(void) p->put( error_info<e_unexpected>{e_unexpected{&type<E>,1},ev.e} );
|
||||
(void) p->put( id_e_pair<diagnostic_info>(id_e.id,diagnostic_info(&type<E>)) );
|
||||
}
|
||||
}
|
||||
|
||||
template <class E>
|
||||
void put_unexpected_diagnostic_output( error_info<E> const & ev ) noexcept
|
||||
void put_verbose_diagnostic_info( id_e_pair<E> const & id_e ) noexcept
|
||||
{
|
||||
if( slot<e_unexpected_diagnostic_output> * p = tl_slot_ptr<e_unexpected_diagnostic_output>() )
|
||||
if( slot<verbose_diagnostic_info> * sl = tl_slot_ptr<verbose_diagnostic_info>() )
|
||||
{
|
||||
std::stringstream s;
|
||||
if( !diagnostic<decltype(ev.v)>::print(s,ev.v) )
|
||||
return;
|
||||
if( p->has_value() )
|
||||
if( auto * pv = sl->has_value() )
|
||||
{
|
||||
auto & p_ev = p->value();
|
||||
if( p_ev.e==ev.e )
|
||||
if( pv->id!=id_e.id )
|
||||
{
|
||||
if( p_ev.v.already.insert(&type<E>).second )
|
||||
{
|
||||
std::string & value = p_ev.v.value;
|
||||
value += '\n';
|
||||
value += s.str();
|
||||
value += " {unexpected}";
|
||||
}
|
||||
return;
|
||||
pv->id = id_e.id;
|
||||
pv->e.reset();
|
||||
}
|
||||
pv->e.add(id_e.e);
|
||||
}
|
||||
(void) p->put( error_info<e_unexpected_diagnostic_output>{e_unexpected_diagnostic_output{s.str()+" {unexpected}"},ev.e} );
|
||||
else
|
||||
sl->emplace(id_e.id).e.add(id_e.e);
|
||||
}
|
||||
}
|
||||
|
||||
template <class E>
|
||||
void no_expect_slot( error_info<E> const & ev ) noexcept
|
||||
void no_expect_slot( id_e_pair<E> const & id_e ) noexcept
|
||||
{
|
||||
put_unexpected(ev);
|
||||
put_unexpected_diagnostic_output(ev);
|
||||
put_unexpected(id_e);
|
||||
put_verbose_diagnostic_info(id_e);
|
||||
}
|
||||
|
||||
template <class E>
|
||||
int put_slot( E && v, error const & e ) noexcept
|
||||
int put_slot( E && e, error_id const & id ) noexcept
|
||||
{
|
||||
using T = typename std::remove_cv<typename std::remove_reference<E>::type>::type;
|
||||
if( slot<T> * p = tl_slot_ptr<T>() )
|
||||
(void) p->put( error_info<T>{std::forward<E>(v),e} );
|
||||
(void) p->put( id_e_pair<T>(id,std::forward<E>(e)) );
|
||||
else
|
||||
{
|
||||
int c = tl_unexpected_enabled_counter();
|
||||
assert(c>=0);
|
||||
if( c )
|
||||
no_expect_slot( error_info<T>{std::forward<E>(v),e} );
|
||||
no_expect_slot( id_e_pair<T>(id,std::forward<E>(e)) );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -323,7 +573,7 @@ namespace boost { namespace leaf {
|
||||
{
|
||||
if( prev_ )
|
||||
{
|
||||
optional<error_info<E>> & p = *prev_;
|
||||
optional<id_e_pair<E>> & p = *prev_;
|
||||
p = std::move(*this);
|
||||
}
|
||||
else
|
||||
@@ -336,28 +586,36 @@ namespace boost { namespace leaf {
|
||||
tl_slot_ptr<E>() = prev_;
|
||||
}
|
||||
|
||||
template <class E>
|
||||
bool slot<E>::slot_print( std::ostream & os, error_id const & id ) const
|
||||
{
|
||||
if( tl_slot_ptr<E>()==this )
|
||||
if( id_e_pair<E> const * id_e = has_value() )
|
||||
if( id_e->id==id )
|
||||
return diagnostic<decltype(id_e->e)>::print(os,id_e->e);
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class... E>
|
||||
error make_error( char const * file, int line, char const * function, E && ... e )
|
||||
error_id make_error( char const * file, int line, char const * function, E && ... e ) noexcept
|
||||
{
|
||||
assert(file&&*file);
|
||||
assert(line>0);
|
||||
assert(function&&*function);
|
||||
e_source_location sl { file, line, function }; //Temp object MSVC workaround
|
||||
return error( std::move(sl), std::forward<E>(e)... );
|
||||
e_source_location sl { file, line, function }; // Temp object MSVC workaround
|
||||
return error_id( std::move(sl), std::forward<E>(e)... );
|
||||
}
|
||||
|
||||
inline void diagnostic_output_prefix( std::ostream & os, leaf::error const * e )
|
||||
enum class result_variant
|
||||
{
|
||||
if( e )
|
||||
os << "leaf::error serial number: " << *e << std::endl;
|
||||
if( leaf_detail::slot<e_unexpected_diagnostic_output> const * unx = leaf_detail::tl_slot_ptr<e_unexpected_diagnostic_output>() )
|
||||
if( unx->has_value() )
|
||||
os << unx->value().v.value << std::endl;
|
||||
}
|
||||
} //leaf_detail
|
||||
value,
|
||||
err,
|
||||
cap
|
||||
};
|
||||
} // leaf_detail
|
||||
|
||||
template <class... E>
|
||||
error error::propagate( E && ... e ) const noexcept
|
||||
error_id error_id::propagate( E && ... e ) const noexcept
|
||||
{
|
||||
auto _ = { leaf_detail::put_slot(std::forward<E>(e),*this)... };
|
||||
(void) _;
|
||||
|
||||
@@ -1,315 +0,0 @@
|
||||
#ifndef BOOST_LEAF_C86E4C4ED0F011E8BB777EB8A659E189
|
||||
#define BOOST_LEAF_C86E4C4ED0F011E8BB777EB8A659E189
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/handle_error.hpp>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
class error_capture;
|
||||
|
||||
template <class... F>
|
||||
typename leaf_detail::handler_pack_return_type<F...>::return_type handle_error( error_capture const &, F && ... ) noexcept;
|
||||
|
||||
template <class P>
|
||||
P const * peek( error_capture const & ) noexcept;
|
||||
|
||||
void diagnostic_output( std::ostream &, error_capture const & );
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class... List>
|
||||
struct all_available;
|
||||
|
||||
template <class Car, class... Cdr>
|
||||
struct all_available<Car, Cdr...>
|
||||
{
|
||||
static bool check( error_capture const & cap ) noexcept
|
||||
{
|
||||
return peek<Car>(cap) && all_available<Cdr...>::check(cap);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct all_available<>
|
||||
{
|
||||
constexpr static bool check( error_capture const & ) noexcept { return true; }
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <int I, class Tuple>
|
||||
struct tuple_for_each_capture
|
||||
{
|
||||
static void const * dynamic_bind( Tuple const & tup, char const * (*type_id)() ) noexcept
|
||||
{
|
||||
assert(type_id!=0);
|
||||
typedef typename std::tuple_element<I-1,Tuple>::type ith_type;
|
||||
if( &type<typename ith_type::value_type> == type_id )
|
||||
return &std::get<I-1>(tup);
|
||||
return tuple_for_each_capture<I-1,Tuple>::dynamic_bind(tup,type_id);
|
||||
}
|
||||
|
||||
static void print( std::ostream & os, Tuple const & tup )
|
||||
{
|
||||
typedef typename std::tuple_element<I-1,Tuple>::type ith_type;
|
||||
tuple_for_each_capture<I-1,Tuple>::print(os,tup);
|
||||
auto & opt = std::get<I-1>(tup);
|
||||
if( opt.has_value() && diagnostic<typename ith_type::value_type>::print(os,opt.value()) )
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
static void unload( error const & e, Tuple && tup ) noexcept
|
||||
{
|
||||
tuple_for_each_capture<I-1,Tuple>::unload(e,std::move(tup));
|
||||
auto && opt = std::get<I-1>(std::move(tup));
|
||||
if( opt.has_value() )
|
||||
(void) e.propagate(std::move(opt).value());
|
||||
}
|
||||
};
|
||||
|
||||
template <class Tuple>
|
||||
struct tuple_for_each_capture<0, Tuple>
|
||||
{
|
||||
static void const * dynamic_bind( Tuple const &, char const * (*)() ) noexcept { return 0; }
|
||||
static void print( std::ostream &, Tuple const & ) noexcept { }
|
||||
static void unload( error const &, Tuple && ) noexcept { }
|
||||
};
|
||||
|
||||
} //leaf_detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
class error_capture
|
||||
{
|
||||
template <class... F>
|
||||
friend typename leaf_detail::handler_pack_return_type<F...>::return_type handle_error( error_capture const &, F && ... ) noexcept;
|
||||
|
||||
template <class P>
|
||||
friend P const * leaf::peek( error_capture const & ) noexcept;
|
||||
|
||||
friend void leaf::diagnostic_output( std::ostream &, error_capture const & );
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
class dynamic_store
|
||||
{
|
||||
mutable std::atomic<int> refcount_;
|
||||
|
||||
virtual void const * bind_( char const * (*)() ) const noexcept = 0;
|
||||
|
||||
protected:
|
||||
|
||||
dynamic_store() noexcept:
|
||||
refcount_(0)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
virtual ~dynamic_store() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void addref() const noexcept
|
||||
{
|
||||
++refcount_;
|
||||
}
|
||||
|
||||
void release() const noexcept
|
||||
{
|
||||
if( !--refcount_ )
|
||||
delete this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
leaf_detail::optional<T> const * bind() const noexcept
|
||||
{
|
||||
if( void const * p = bind_(&type<T>) )
|
||||
return static_cast<leaf_detail::optional<T> const *>(p);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void diagnostic_output_( std::ostream & ) const = 0;
|
||||
virtual void unload_( error const & ) noexcept = 0;
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class... T>
|
||||
class dynamic_store_impl:
|
||||
public dynamic_store
|
||||
{
|
||||
std::tuple<leaf_detail::optional<T>...> s_;
|
||||
public:
|
||||
|
||||
explicit dynamic_store_impl( std::tuple<leaf_detail::optional<T>...> && s ) noexcept:
|
||||
s_(std::move(s))
|
||||
{
|
||||
}
|
||||
|
||||
void const * bind_( char const * (*type_id)() ) const noexcept
|
||||
{
|
||||
using namespace leaf_detail;
|
||||
assert(type_id!=0);
|
||||
return tuple_for_each_capture<sizeof...(T),std::tuple<optional<T>...>>::dynamic_bind(s_,type_id);
|
||||
}
|
||||
|
||||
void diagnostic_output_( std::ostream & os ) const
|
||||
{
|
||||
leaf_detail::diagnostic_output_prefix(os,0);
|
||||
leaf_detail::tuple_for_each_capture<sizeof...(T),decltype(s_)>::print(os,s_);
|
||||
}
|
||||
|
||||
void unload_( error const & e ) noexcept
|
||||
{
|
||||
leaf_detail::tuple_for_each_capture<sizeof...(T),decltype(s_)>::unload(e,std::move(s_));
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
void free() noexcept
|
||||
{
|
||||
if( ds_ )
|
||||
{
|
||||
ds_->release();
|
||||
ds_=0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class F,class... T>
|
||||
std::pair<bool, typename leaf_detail::handler_wrapper<F>::return_type> check_handler_( F && f, leaf_detail::mp_list<T...> ) const
|
||||
{
|
||||
using namespace leaf_detail;
|
||||
typedef typename handler_wrapper<F>::return_type return_type;
|
||||
if( leaf_detail::all_available<typename std::remove_cv<typename std::remove_reference<T>::type>::type...>::check(*this) )
|
||||
return std::make_pair(true, handler_wrapper<F>(std::forward<F>(f))( *leaf::peek<typename std::remove_cv<typename std::remove_reference<T>::type>::type>(*this)... ));
|
||||
else
|
||||
return std::make_pair(false, return_type(uhnandled_error<return_type>::value(e_)));
|
||||
}
|
||||
|
||||
template <class F>
|
||||
std::pair<bool, typename leaf_detail::handler_wrapper<F>::return_type> find_handler_( F && f ) const
|
||||
{
|
||||
return check_handler_( std::forward<F>(f), typename leaf_detail::function_traits<F>::mp_args{ } );
|
||||
}
|
||||
|
||||
template <class CarF,class... CdrF>
|
||||
std::pair<bool, typename leaf_detail::handler_wrapper<CarF>::return_type> find_handler_( CarF && car_f, CdrF && ... cdr_f ) const
|
||||
{
|
||||
using namespace leaf_detail;
|
||||
auto r = check_handler_( std::forward<CarF>(car_f), typename leaf_detail::function_traits<CarF>::mp_args{ } );
|
||||
return r.first ? r : find_handler_(std::forward<CdrF>(cdr_f)...);
|
||||
}
|
||||
|
||||
dynamic_store * ds_;
|
||||
error e_;
|
||||
|
||||
protected:
|
||||
|
||||
void set_error( error const & e )
|
||||
{
|
||||
e_ = e;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
error_capture() noexcept:
|
||||
ds_(0)
|
||||
{
|
||||
}
|
||||
|
||||
template <class... E>
|
||||
error_capture( error const & e, std::tuple<leaf_detail::optional<E>...> && s ) noexcept:
|
||||
ds_(new dynamic_store_impl<E...>(std::move(s))),
|
||||
e_(e)
|
||||
{
|
||||
ds_->addref();
|
||||
}
|
||||
|
||||
~error_capture() noexcept
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
error_capture( error_capture const & x ) noexcept:
|
||||
ds_(x.ds_),
|
||||
e_(x.e_)
|
||||
{
|
||||
if( ds_ )
|
||||
ds_->addref();
|
||||
}
|
||||
|
||||
error_capture( error_capture && x ) noexcept:
|
||||
ds_(x.ds_),
|
||||
e_(std::move(x.e_))
|
||||
{
|
||||
x.ds_ = 0;
|
||||
}
|
||||
|
||||
error_capture & operator=( error_capture const & x ) noexcept
|
||||
{
|
||||
ds_ = x.ds_;
|
||||
ds_->addref();
|
||||
e_ = x.e_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
error_capture & operator=( error_capture && x ) noexcept
|
||||
{
|
||||
ds_ = x.ds_;
|
||||
x.ds_ = 0;
|
||||
e_ = x.e_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return ds_!=0;
|
||||
}
|
||||
|
||||
error unload() noexcept
|
||||
{
|
||||
if( ds_ )
|
||||
{
|
||||
ds_->unload_(e_);
|
||||
free();
|
||||
}
|
||||
return e_;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class... F>
|
||||
typename leaf_detail::handler_pack_return_type<F...>::return_type handle_error( error_capture const & ec, F && ... f ) noexcept
|
||||
{
|
||||
return ec.find_handler_( std::forward<F>(f)... ).second;
|
||||
}
|
||||
|
||||
template <class P>
|
||||
P const * peek( error_capture const & e ) noexcept
|
||||
{
|
||||
if( e )
|
||||
if( auto * opt = e.ds_->bind<P>() )
|
||||
if( opt->has_value() )
|
||||
return &opt->value();
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void diagnostic_output( std::ostream & os, error_capture const & e )
|
||||
{
|
||||
if( e )
|
||||
e.ds_->diagnostic_output_(os);
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
@@ -1,50 +0,0 @@
|
||||
#ifndef BOOST_LEAF_87F274C4D4BA11E89928D55AC82C3C47
|
||||
#define BOOST_LEAF_87F274C4D4BA11E89928D55AC82C3C47
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/expect.hpp>
|
||||
#include <boost/leaf/detail/throw.hpp>
|
||||
#include <boost/leaf/detail/demangle.hpp>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
inline error get_error( std::exception const & ex ) noexcept
|
||||
{
|
||||
if( auto e = dynamic_cast<error const *>(&ex) )
|
||||
return *e;
|
||||
else
|
||||
return next_error_value();
|
||||
}
|
||||
|
||||
template <class P, class... E>
|
||||
P const * peek( expect<E...> const & exp, std::exception const & ex ) noexcept
|
||||
{
|
||||
return peek<P>(exp,get_error(ex));
|
||||
}
|
||||
|
||||
template <class... E, class... F>
|
||||
void handle_exception( expect<E...> & exp, std::exception const & ex, F && ... f )
|
||||
{
|
||||
if( handle_error(exp,get_error(ex),f...) )
|
||||
(void) error();
|
||||
else
|
||||
throw;
|
||||
}
|
||||
|
||||
template <class... E>
|
||||
void diagnostic_output( std::ostream & os, expect<E...> const & exp, std::exception const & ex )
|
||||
{
|
||||
os <<
|
||||
"Exception dynamic type: " << leaf_detail::demangle(typeid(ex).name()) << std::endl <<
|
||||
"std::exception::what(): " << ex.what() << std::endl;
|
||||
diagnostic_output(os,exp,get_error(ex));
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
@@ -1,108 +0,0 @@
|
||||
#ifndef BOOST_LEAF_BC24FB98B2DE11E884419CF5AD35F1A2
|
||||
#define BOOST_LEAF_BC24FB98B2DE11E884419CF5AD35F1A2
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/error_capture.hpp>
|
||||
#include <boost/leaf/expect.hpp>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
class captured_exception:
|
||||
public std::exception,
|
||||
error_capture
|
||||
{
|
||||
std::exception_ptr ex_;
|
||||
bool has_error_;
|
||||
|
||||
public:
|
||||
|
||||
captured_exception( std::exception_ptr && ex, error_capture && cap, bool has_error ) noexcept:
|
||||
error_capture(std::move(cap)),
|
||||
ex_(std::move(ex)),
|
||||
has_error_(has_error)
|
||||
{
|
||||
assert(ex_);
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
void rethrow_original_exception()
|
||||
{
|
||||
if( !has_error_ )
|
||||
{
|
||||
set_error(next_error_value());
|
||||
has_error_ = true;
|
||||
}
|
||||
unload();
|
||||
std::rethrow_exception(ex_);
|
||||
}
|
||||
|
||||
friend void diagnostic_output_( std::ostream & os, captured_exception const & ce )
|
||||
{
|
||||
diagnostic_output(os,static_cast<error_capture const &>(ce));
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class F, class... E>
|
||||
class exception_trap
|
||||
{
|
||||
F f_;
|
||||
|
||||
public:
|
||||
|
||||
explicit exception_trap( F && f ) noexcept:
|
||||
f_(std::move(f))
|
||||
{
|
||||
}
|
||||
|
||||
template <class... A>
|
||||
decltype(std::declval<F>()(std::declval<A>()...)) operator()( A && ... a )
|
||||
{
|
||||
expect<E...> exp;
|
||||
try
|
||||
{
|
||||
return f_(std::forward<A>(a)...);
|
||||
}
|
||||
catch( error const & e )
|
||||
{
|
||||
throw captured_exception(std::current_exception(),capture(exp,e),true);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
throw captured_exception(std::current_exception(),capture(exp,error()),false);
|
||||
}
|
||||
}
|
||||
};
|
||||
} //leaf_detail
|
||||
|
||||
template <class... E, class F>
|
||||
leaf_detail::exception_trap<F,E...> capture_exception( F && f ) noexcept
|
||||
{
|
||||
return leaf_detail::exception_trap<F,E...>(std::move(f));
|
||||
}
|
||||
|
||||
template <class Future>
|
||||
decltype(std::declval<Future>().get()) get( Future && f )
|
||||
{
|
||||
try
|
||||
{
|
||||
return std::forward<Future>(f).get();
|
||||
}
|
||||
catch( leaf_detail::captured_exception & ex )
|
||||
{
|
||||
ex.rethrow_original_exception();
|
||||
}
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
54
include/boost/leaf/exception_to_result.hpp
Normal file
54
include/boost/leaf/exception_to_result.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef BOOST_LEAF_017BF91412EB11E9926CDCED8B7F4AFC
|
||||
#define BOOST_LEAF_017BF91412EB11E9926CDCED8B7F4AFC
|
||||
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/throw.hpp>
|
||||
#include <boost/leaf/result.hpp>
|
||||
#include <boost/leaf/detail/static_store.hpp>
|
||||
#include <boost/leaf/detail/demangle.hpp>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class F>
|
||||
leaf::result<typename leaf_detail::function_traits<F>::return_type> catch_exceptions_helper( F && f, leaf_detail_mp11::mp_list<> )
|
||||
{
|
||||
return std::forward<F>(f)();
|
||||
}
|
||||
|
||||
template <class Ex1, class... Ex, class F>
|
||||
leaf::result<typename leaf_detail::function_traits<F>::return_type> catch_exceptions_helper( F && f, leaf_detail_mp11::mp_list<Ex1,Ex...> )
|
||||
{
|
||||
try
|
||||
{
|
||||
return catch_exceptions_helper(std::forward<F>(f),leaf_detail_mp11::mp_list<Ex...>{ });
|
||||
}
|
||||
catch( Ex1 const & ex1 )
|
||||
{
|
||||
return leaf::new_error(ex1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class... Ex, class F>
|
||||
leaf::result<typename leaf_detail::function_traits<F>::return_type> exception_to_result( F && f ) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
return leaf_detail::catch_exceptions_helper(std::forward<F>(f), leaf_detail_mp11::mp_list<Ex...>());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return leaf::new_error(std::current_exception());
|
||||
}
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
@@ -1,286 +0,0 @@
|
||||
#ifndef BOOST_LEAF_AFBBD676B2FF11E8984C7976AE35F1A2
|
||||
#define BOOST_LEAF_AFBBD676B2FF11E8984C7976AE35F1A2
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/handle_error.hpp>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
class error_capture;
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class E>
|
||||
class expect_slot:
|
||||
public slot<E>
|
||||
{
|
||||
};
|
||||
|
||||
class expect_slot_enable_unexpected
|
||||
{
|
||||
protected:
|
||||
expect_slot_enable_unexpected() noexcept
|
||||
{
|
||||
++tl_unexpected_enabled_counter();
|
||||
}
|
||||
|
||||
~expect_slot_enable_unexpected() noexcept
|
||||
{
|
||||
--tl_unexpected_enabled_counter();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class expect_slot<e_unexpected>:
|
||||
public slot<e_unexpected>,
|
||||
expect_slot_enable_unexpected
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
class expect_slot<e_unexpected_diagnostic_output>:
|
||||
public slot<e_unexpected_diagnostic_output>,
|
||||
expect_slot_enable_unexpected
|
||||
{
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class T, class... List>
|
||||
struct type_index;
|
||||
|
||||
template <class T, class... Cdr>
|
||||
struct type_index<T, T, Cdr...>
|
||||
{
|
||||
static const int value = 0;
|
||||
};
|
||||
|
||||
template <class T, class Car, class... Cdr>
|
||||
struct type_index<T, Car, Cdr...>
|
||||
{
|
||||
static const int value = 1 + type_index<T,Cdr...>::value;
|
||||
};
|
||||
|
||||
template <class T, class Tuple>
|
||||
struct tuple_type_index;
|
||||
|
||||
template <class T, class... TupleTypes>
|
||||
struct tuple_type_index<T,std::tuple<TupleTypes...>>
|
||||
{
|
||||
static const int value = type_index<T,TupleTypes...>::value;
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class SlotsTuple, class... List>
|
||||
struct slots_subset;
|
||||
|
||||
template <class SlotsTuple, class Car, class... Cdr>
|
||||
struct slots_subset<SlotsTuple, Car, Cdr...>
|
||||
{
|
||||
static bool have_values( SlotsTuple const & tup, error const & e ) noexcept
|
||||
{
|
||||
auto & sl = std::get<tuple_type_index<Car,SlotsTuple>::value>(tup);
|
||||
return sl.has_value() && sl.value().e==e && slots_subset<SlotsTuple,Cdr...>::have_values(tup,e);
|
||||
}
|
||||
};
|
||||
|
||||
template <class SlotsTuple>
|
||||
struct slots_subset<SlotsTuple>
|
||||
{
|
||||
static constexpr bool have_values( SlotsTuple const &, error const & ) noexcept { return true; }
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <int I, class Tuple>
|
||||
struct tuple_for_each_expect
|
||||
{
|
||||
static void print( std::ostream & os, Tuple const & tup )
|
||||
{
|
||||
tuple_for_each_expect<I-1,Tuple>::print(os,tup);
|
||||
auto & opt = std::get<I-1>(tup);
|
||||
if( opt.has_value() )
|
||||
{
|
||||
auto & x = opt.value();
|
||||
if( diagnostic<decltype(x.v)>::print(os,x.v) )
|
||||
os << " {" << x.e << '}' << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void print( std::ostream & os, Tuple const & tup, error const & e )
|
||||
{
|
||||
tuple_for_each_expect<I-1,Tuple>::print(os,tup,e);
|
||||
auto & opt = std::get<I-1>(tup);
|
||||
if( opt.has_value() )
|
||||
{
|
||||
auto & x = opt.value();
|
||||
if( x.e==e && diagnostic<decltype(x.v)>::print(os,x.v) )
|
||||
os << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void clear( Tuple & tup ) noexcept
|
||||
{
|
||||
tuple_for_each_expect<I-1,Tuple>::clear(tup);
|
||||
std::get<I-1>(tup).reset();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Tuple>
|
||||
struct tuple_for_each_expect<0, Tuple>
|
||||
{
|
||||
static void print( std::ostream &, Tuple const & ) noexcept { }
|
||||
static void print( std::ostream &, Tuple const &, error const & ) noexcept { }
|
||||
static void clear( Tuple & ) noexcept { }
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
optional<T> convert_optional( expect_slot<T> && x, error const & e ) noexcept
|
||||
{
|
||||
if( x.has_value() && x.value().e==e )
|
||||
return optional<T>(std::move(x).value().v);
|
||||
else
|
||||
return optional<T>();
|
||||
}
|
||||
|
||||
template <class>
|
||||
struct dependent_type
|
||||
{
|
||||
typedef leaf::error_capture error_capture;
|
||||
};
|
||||
} //leaf_detail
|
||||
|
||||
template <class... E>
|
||||
class expect;
|
||||
|
||||
template <class... E, class... F>
|
||||
typename leaf_detail::handler_pack_return_type<F...>::return_type handle_error( expect<E...> const &, error const &, F && ... ) noexcept;
|
||||
|
||||
template <class P, class... E>
|
||||
P const * peek( expect<E...> const &, error const & ) noexcept;
|
||||
|
||||
template <class... E>
|
||||
void diagnostic_output( std::ostream &, expect<E...> const & );
|
||||
|
||||
template <class... E>
|
||||
void diagnostic_output( std::ostream &, expect<E...> const &, error const & );
|
||||
|
||||
template <class... E>
|
||||
typename leaf_detail::dependent_type<expect<E...>>::error_capture capture( expect<E...> &, error const & );
|
||||
|
||||
template <class... E>
|
||||
class expect
|
||||
{
|
||||
friend class error;
|
||||
|
||||
template <class... E_, class... F>
|
||||
friend typename leaf_detail::handler_pack_return_type<F...>::return_type leaf::handle_error( expect<E_...> const &, error const &, F && ... ) noexcept;
|
||||
|
||||
template <class P, class... E_>
|
||||
friend P const * leaf::peek( expect<E_...> const &, error const & ) noexcept;
|
||||
|
||||
template <class... E_>
|
||||
friend void leaf::diagnostic_output( std::ostream &, expect<E_...> const & );
|
||||
|
||||
template <class... E_>
|
||||
friend void leaf::diagnostic_output( std::ostream &, expect<E_...> const &, error const & );
|
||||
|
||||
template <class... E_>
|
||||
friend typename leaf_detail::dependent_type<expect<E_...>>::error_capture leaf::capture( expect<E_...> &, error const & );
|
||||
|
||||
expect( expect const & ) = delete;
|
||||
expect & operator=( expect const & ) = delete;
|
||||
|
||||
std::tuple<leaf_detail::expect_slot<E>...> s_;
|
||||
|
||||
template <class F,class... T>
|
||||
std::pair<bool, typename leaf_detail::handler_wrapper<F>::return_type> check_handler_( error const & e, F && f, leaf_detail::mp_list<T...> ) const
|
||||
{
|
||||
using namespace leaf_detail;
|
||||
typedef typename handler_wrapper<F>::return_type return_type;
|
||||
if( slots_subset<decltype(s_),expect_slot<typename std::remove_cv<typename std::remove_reference<T>::type>::type>...>::have_values(s_,e) )
|
||||
return std::make_pair(true, handler_wrapper<F>(std::forward<F>(f))( *leaf::peek<typename std::remove_cv<typename std::remove_reference<T>::type>::type>(*this,e)... ));
|
||||
else
|
||||
return std::make_pair(false, uhnandled_error<return_type>::value(e));
|
||||
}
|
||||
|
||||
template <class F>
|
||||
std::pair<bool, typename leaf_detail::handler_wrapper<F>::return_type> find_handler_( error const & e, F && f ) const
|
||||
{
|
||||
return check_handler_( e, std::forward<F>(f), typename leaf_detail::function_traits<F>::mp_args{ } );
|
||||
}
|
||||
|
||||
template <class CarF,class... CdrF>
|
||||
std::pair<bool, typename leaf_detail::handler_wrapper<CarF>::return_type> find_handler_( error const & e, CarF && car_f, CdrF && ... cdr_f ) const
|
||||
{
|
||||
using namespace leaf_detail;
|
||||
auto r = check_handler_( e, std::forward<CarF>(car_f), typename leaf_detail::function_traits<CarF>::mp_args{ } );
|
||||
return r.first ? r : find_handler_(e,std::forward<CdrF>(cdr_f)...);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
constexpr expect() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class... E, class... F>
|
||||
typename leaf_detail::handler_pack_return_type<F...>::return_type handle_error( expect<E...> const & exp, error const & e, F && ... f ) noexcept
|
||||
{
|
||||
return exp.find_handler_( e, std::forward<F>(f)... ).second;
|
||||
}
|
||||
|
||||
template <class P, class... E>
|
||||
P const * peek( expect<E...> const & exp, error const & e ) noexcept
|
||||
{
|
||||
auto & opt = std::get<leaf_detail::type_index<P,E...>::value>(exp.s_);
|
||||
if( opt.has_value() )
|
||||
{
|
||||
auto & x = opt.value();
|
||||
if( x.e==e )
|
||||
return &x.v;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class... E>
|
||||
void diagnostic_output( std::ostream & os, expect<E...> const & exp )
|
||||
{
|
||||
leaf_detail::diagnostic_output_prefix(os,0);
|
||||
leaf_detail::tuple_for_each_expect<sizeof...(E),decltype(exp.s_)>::print(os,exp.s_);
|
||||
}
|
||||
|
||||
template <class... E>
|
||||
void diagnostic_output( std::ostream & os, expect<E...> const & exp, error const & e )
|
||||
{
|
||||
leaf_detail::diagnostic_output_prefix(os,&e);
|
||||
leaf_detail::tuple_for_each_expect<sizeof...(E),decltype(exp.s_)>::print(os,exp.s_,e);
|
||||
}
|
||||
|
||||
template <class... E>
|
||||
typename leaf_detail::dependent_type<expect<E...>>::error_capture capture( expect<E...> & exp, error const & e )
|
||||
{
|
||||
using namespace leaf_detail;
|
||||
typename leaf_detail::dependent_type<expect<E...>>::error_capture cap(
|
||||
e,
|
||||
std::make_tuple(
|
||||
convert_optional(
|
||||
std::move(std::get<tuple_type_index<expect_slot<E>,decltype(exp.s_)>::value>(exp.s_)),e)...));
|
||||
return cap;
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
84
include/boost/leaf/handle.hpp
Normal file
84
include/boost/leaf/handle.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#ifndef BOOST_LEAF_73685B76115611E9950D61678B7F4AFC
|
||||
#define BOOST_LEAF_73685B76115611E9950D61678B7F4AFC
|
||||
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/result.hpp>
|
||||
#include <boost/leaf/detail/static_store.hpp>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
template <class TryBlock, class... Handler>
|
||||
typename std::remove_reference<decltype(std::declval<TryBlock>()().value())>::type handle_all( TryBlock && try_block, Handler && ... handler )
|
||||
{
|
||||
using namespace leaf_detail;
|
||||
typename deduce_static_store<typename handler_args_set<Handler...>::type>::type ss;
|
||||
ss.set_reset(true);
|
||||
if( auto r = std::forward<TryBlock>(try_block)() )
|
||||
return *r;
|
||||
else
|
||||
return ss.handle_error(error_info(r.error()), std::forward<Handler>(handler)...);
|
||||
}
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class R, class F, class = typename function_traits<F>::mp_args>
|
||||
struct handler_wrapper;
|
||||
|
||||
template <class R, class F, template<class...> class L, class... A>
|
||||
struct handler_wrapper<R, F, L<A...>>
|
||||
{
|
||||
F f_;
|
||||
explicit handler_wrapper( F && f ) noexcept:
|
||||
f_(std::forward<F>(f))
|
||||
{
|
||||
}
|
||||
R operator()( A... a ) const
|
||||
{
|
||||
return f_(a...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class F, template<class...> class L, class... A>
|
||||
struct handler_wrapper<result<void>, F, L<A...>>
|
||||
{
|
||||
F f_;
|
||||
explicit handler_wrapper( F && f ) noexcept:
|
||||
f_(std::forward<F>(f))
|
||||
{
|
||||
}
|
||||
result<void> operator()( A... a ) const
|
||||
{
|
||||
f_(a...);
|
||||
return { };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <class TryBlock, class... Handler>
|
||||
decltype(std::declval<TryBlock>()()) handle_some( TryBlock && try_block, Handler && ... handler )
|
||||
{
|
||||
using namespace leaf_detail;
|
||||
using R = typename function_traits<TryBlock>::return_type;
|
||||
typename deduce_static_store<typename handler_args_set<Handler...>::type>::type ss;
|
||||
if( auto r = std::forward<TryBlock>(try_block)() )
|
||||
{
|
||||
ss.set_reset(true);
|
||||
return r;
|
||||
}
|
||||
else if( auto rr = ss.handle_error(error_info(r.error()), handler_wrapper<R,Handler>(std::forward<Handler>(handler))..., [&r] { return r; } ) )
|
||||
{
|
||||
ss.set_reset(true);
|
||||
return rr;
|
||||
}
|
||||
else
|
||||
return rr;
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
@@ -1,13 +1,14 @@
|
||||
#ifndef BOOST_LEAF_25AF99F6DC6F11E8803DE9BC9723C688
|
||||
#define BOOST_LEAF_25AF99F6DC6F11E8803DE9BC9723C688
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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/error.hpp>
|
||||
#include <tuple>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
@@ -16,19 +17,19 @@ namespace boost { namespace leaf {
|
||||
template <int I, class Tuple>
|
||||
struct tuple_for_each_preload
|
||||
{
|
||||
static void trigger( Tuple & tup, error const & e ) noexcept
|
||||
static void trigger( Tuple & tup, error_id const & id ) noexcept
|
||||
{
|
||||
tuple_for_each_preload<I-1,Tuple>::trigger(tup,e);
|
||||
std::get<I-1>(tup).trigger(e);
|
||||
tuple_for_each_preload<I-1,Tuple>::trigger(tup,id);
|
||||
std::get<I-1>(tup).trigger(id);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Tuple>
|
||||
struct tuple_for_each_preload<0, Tuple>
|
||||
{
|
||||
static void trigger( Tuple const &, error const & ) noexcept { }
|
||||
static void trigger( Tuple const &, error_id const & ) noexcept { }
|
||||
};
|
||||
} //leaf_detail
|
||||
} // leaf_detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@@ -38,20 +39,22 @@ namespace boost { namespace leaf {
|
||||
class preloaded_item
|
||||
{
|
||||
slot<E> * s_;
|
||||
E v_;
|
||||
E e_;
|
||||
|
||||
public:
|
||||
explicit preloaded_item( E && v ) noexcept:
|
||||
|
||||
explicit preloaded_item( E && e ) noexcept:
|
||||
s_(tl_slot_ptr<E>()),
|
||||
v_(std::forward<E>(v))
|
||||
e_(std::forward<E>(e))
|
||||
{
|
||||
}
|
||||
|
||||
void trigger( error e ) noexcept
|
||||
void trigger( error_id const & id ) noexcept
|
||||
{
|
||||
if( s_ )
|
||||
{
|
||||
if( !s_->has_value() || s_->value().e!=e )
|
||||
s_->put( leaf_detail::error_info<E>{std::move(v_),e} );
|
||||
if( !s_->has_value() || s_->value().id!=id )
|
||||
s_->put( leaf_detail::id_e_pair<E>(id,std::move(e_)) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -59,7 +62,7 @@ namespace boost { namespace leaf {
|
||||
int c = tl_unexpected_enabled_counter();
|
||||
assert(c>=0);
|
||||
if( c )
|
||||
no_expect_slot( error_info<T>{std::forward<E>(v_),e} );
|
||||
no_expect_slot( id_e_pair<T>(id,std::forward<E>(e_)) );
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -70,21 +73,21 @@ namespace boost { namespace leaf {
|
||||
preloaded & operator=( preloaded const & ) = delete;
|
||||
|
||||
std::tuple<preloaded_item<E>...> p_;
|
||||
error e_;
|
||||
error_id id_;
|
||||
bool moved_;
|
||||
|
||||
public:
|
||||
|
||||
explicit preloaded( E && ... e ) noexcept:
|
||||
p_(preloaded_item<E>(std::forward<E>(e))...),
|
||||
e_(last_error_value()),
|
||||
id_(last_error()),
|
||||
moved_(false)
|
||||
{
|
||||
}
|
||||
|
||||
preloaded( preloaded && x ) noexcept:
|
||||
p_(std::move(x.p_)),
|
||||
e_(std::move(x.e_)),
|
||||
id_(std::move(x.id_)),
|
||||
moved_(false)
|
||||
{
|
||||
x.moved_ = true;
|
||||
@@ -94,17 +97,17 @@ namespace boost { namespace leaf {
|
||||
{
|
||||
if( moved_ )
|
||||
return;
|
||||
error const e = last_error_value();
|
||||
if( e==e_ )
|
||||
error_id const id = last_error();
|
||||
if( id==id_ )
|
||||
{
|
||||
if( std::uncaught_exception() )
|
||||
leaf_detail::tuple_for_each_preload<sizeof...(E),decltype(p_)>::trigger(p_,next_error_value());
|
||||
leaf_detail::tuple_for_each_preload<sizeof...(E),decltype(p_)>::trigger(p_,next_error());
|
||||
}
|
||||
else
|
||||
leaf_detail::tuple_for_each_preload<sizeof...(E),decltype(p_)>::trigger(p_,e);
|
||||
leaf_detail::tuple_for_each_preload<sizeof...(E),decltype(p_)>::trigger(p_,id);
|
||||
}
|
||||
};
|
||||
} //leaf_detail
|
||||
} // leaf_detail
|
||||
|
||||
template <class... E>
|
||||
leaf_detail::preloaded<E...> preload( E && ... e ) noexcept
|
||||
@@ -131,12 +134,12 @@ namespace boost { namespace leaf {
|
||||
{
|
||||
}
|
||||
|
||||
void trigger( error e ) noexcept
|
||||
void trigger( error_id const & id ) noexcept
|
||||
{
|
||||
if( s_ )
|
||||
{
|
||||
if( !s_->has_value() || s_->value().e!=e )
|
||||
s_->put( leaf_detail::error_info<E>{f_(),e} );
|
||||
if( !s_->has_value() || s_->value().id!=id )
|
||||
s_->put( leaf_detail::id_e_pair<E>(id,f_()) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -144,7 +147,7 @@ namespace boost { namespace leaf {
|
||||
int c = tl_unexpected_enabled_counter();
|
||||
assert(c>=0);
|
||||
if( c )
|
||||
no_expect_slot( error_info<T>{std::forward<E>(f_()),e} );
|
||||
no_expect_slot( id_e_pair<T>(id,std::forward<E>(f_())) );
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -154,21 +157,21 @@ namespace boost { namespace leaf {
|
||||
{
|
||||
deferred & operator=( deferred const & ) = delete;
|
||||
std::tuple<deferred_item<F>...> d_;
|
||||
error e_;
|
||||
error_id id_;
|
||||
bool moved_;
|
||||
|
||||
public:
|
||||
|
||||
explicit deferred( F && ... f ) noexcept:
|
||||
d_(deferred_item<F>(std::forward<F>(f))...),
|
||||
e_(last_error_value()),
|
||||
id_(last_error()),
|
||||
moved_(false)
|
||||
{
|
||||
}
|
||||
|
||||
deferred( deferred && x ) noexcept:
|
||||
d_(std::move(x.d_)),
|
||||
e_(std::move(x.e_)),
|
||||
id_(std::move(x.id_)),
|
||||
moved_(false)
|
||||
{
|
||||
x.moved_ = true;
|
||||
@@ -178,17 +181,17 @@ namespace boost { namespace leaf {
|
||||
{
|
||||
if( moved_ )
|
||||
return;
|
||||
error const e = last_error_value();
|
||||
if( e==e_ )
|
||||
error_id const id = last_error();
|
||||
if( id==id_ )
|
||||
{
|
||||
if( std::uncaught_exception() )
|
||||
leaf_detail::tuple_for_each_preload<sizeof...(F),decltype(d_)>::trigger(d_,next_error_value());
|
||||
leaf_detail::tuple_for_each_preload<sizeof...(F),decltype(d_)>::trigger(d_,next_error());
|
||||
}
|
||||
else
|
||||
leaf_detail::tuple_for_each_preload<sizeof...(F),decltype(d_)>::trigger(d_,e);
|
||||
leaf_detail::tuple_for_each_preload<sizeof...(F),decltype(d_)>::trigger(d_,id);
|
||||
}
|
||||
};
|
||||
} //leaf_detail
|
||||
} // leaf_detail
|
||||
|
||||
template <class... F>
|
||||
leaf_detail::deferred<F...> defer( F && ... f ) noexcept
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#ifndef BOOST_LEAF_2CD8E6B8CA8D11E8BD3B80D66CE5B91B
|
||||
#define BOOST_LEAF_2CD8E6B8CA8D11E8BD3B80D66CE5B91B
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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/error_capture.hpp>
|
||||
#include <boost/leaf/detail/throw.hpp>
|
||||
#include <boost/leaf/detail/dynamic_store.hpp>
|
||||
#include <boost/leaf/throw.hpp>
|
||||
#include <memory>
|
||||
|
||||
#define LEAF_AUTO(v,r) auto _r_##v = r; if( !_r_##v ) return _r_##v.error(); auto & v = *_r_##v
|
||||
#define LEAF_CHECK(r) {auto _r = r; if( !_r ) return _r.error();}
|
||||
@@ -17,59 +18,12 @@ namespace boost { namespace leaf {
|
||||
|
||||
class bad_result: public std::exception { };
|
||||
|
||||
template <class... E>
|
||||
class expect;
|
||||
|
||||
template <class T>
|
||||
class result;
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
template <class T>
|
||||
struct unhandled_error_base<result<T>>
|
||||
{
|
||||
static leaf::error value( leaf::error const & e ) noexcept { return e; }
|
||||
};
|
||||
}
|
||||
|
||||
template <class... E, class T, class... F>
|
||||
typename leaf_detail::handler_pack_return_type<F...>::return_type handle_error( expect<E...> const &, result<T> const &, F && ... ) noexcept;
|
||||
|
||||
template <class P, class... E, class T>
|
||||
P const * peek( expect<E...> const &, result<T> const & ) noexcept;
|
||||
|
||||
template <class... E, class T>
|
||||
void diagnostic_output( std::ostream &, expect<E...> const &, result<T> const & );
|
||||
|
||||
template <class... E, class T>
|
||||
result<T> capture( expect<E...> &, result<T> const & );
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
enum class result_variant
|
||||
{
|
||||
value,
|
||||
err,
|
||||
cap
|
||||
};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class result
|
||||
{
|
||||
template <class... E, class T_, class... F>
|
||||
friend typename leaf_detail::handler_pack_return_type<F...>::return_type leaf::handle_error( expect<E...> const &, result<T_> const &, F && ... ) noexcept;
|
||||
|
||||
template <class P, class... E, class T_>
|
||||
friend P const * leaf::peek( expect<E...> const &, result<T_> const & ) noexcept;
|
||||
|
||||
template <class... E, class T_>
|
||||
friend void leaf::diagnostic_output( std::ostream &, expect<E...> const &, result<T_> const & );
|
||||
|
||||
template <class... E, class T_>
|
||||
friend result<T_> leaf::capture( expect<E...> &, result<T_> const & );
|
||||
using dynamic_store_ptr = std::shared_ptr<leaf_detail::dynamic_store>;
|
||||
|
||||
template <class U>
|
||||
friend class result;
|
||||
@@ -77,8 +31,8 @@ namespace boost { namespace leaf {
|
||||
union
|
||||
{
|
||||
T value_;
|
||||
error err_;
|
||||
error_capture cap_;
|
||||
error_id err_;
|
||||
dynamic_store_ptr cap_;
|
||||
};
|
||||
|
||||
leaf_detail::result_variant which_;
|
||||
@@ -91,11 +45,11 @@ namespace boost { namespace leaf {
|
||||
value_.~T();
|
||||
break;
|
||||
case leaf_detail::result_variant::err:
|
||||
err_.~error();
|
||||
err_.~error_id();
|
||||
break;
|
||||
default:
|
||||
assert(which_==leaf_detail::result_variant::cap);
|
||||
cap_.~error_capture();
|
||||
cap_.~dynamic_store_ptr();
|
||||
}
|
||||
which_= (leaf_detail::result_variant)-1;
|
||||
}
|
||||
@@ -109,11 +63,11 @@ namespace boost { namespace leaf {
|
||||
(void) new(&value_) T(x.value_);
|
||||
break;
|
||||
case leaf_detail::result_variant::err:
|
||||
(void) new(&err_) leaf::error(x.err_);
|
||||
(void) new(&err_) error_id(x.err_);
|
||||
break;
|
||||
default:
|
||||
assert(x.which_==leaf_detail::result_variant::cap);
|
||||
(void) new(&cap_) error_capture(x.cap_);
|
||||
(void) new(&cap_) dynamic_store_ptr(x.cap_);
|
||||
};
|
||||
which_ = x.which_;
|
||||
}
|
||||
@@ -125,36 +79,42 @@ namespace boost { namespace leaf {
|
||||
{
|
||||
case leaf_detail::result_variant:: value:
|
||||
(void) new(&value_) T(std::move(x.value_));
|
||||
which_ = x.which_;
|
||||
break;
|
||||
case leaf_detail::result_variant::err:
|
||||
(void) new(&err_) leaf::error(std::move(x.err_));
|
||||
(void) new(&err_) error_id(std::move(x.err_));
|
||||
which_ = x.which_;
|
||||
break;
|
||||
default:
|
||||
assert(x.which_==leaf_detail::result_variant::cap);
|
||||
(void) new(&cap_) error_capture(std::move(x.cap_));
|
||||
if( dynamic_store_ptr cap = std::move(x.cap_) )
|
||||
{
|
||||
x.destroy();
|
||||
(void) new(&x.err_) error_id(cap->error());
|
||||
x.which_ = leaf_detail::result_variant::err;
|
||||
(void) new(&cap_) dynamic_store_ptr(std::move(cap));
|
||||
}
|
||||
else
|
||||
(void) new(&cap_) dynamic_store_ptr(std::move(x.cap_));
|
||||
which_ = leaf_detail::result_variant::cap;
|
||||
};
|
||||
which_ = x.which_;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
~result() noexcept
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
result( result const & x )
|
||||
{
|
||||
copy_from(x);
|
||||
}
|
||||
|
||||
result( result && x ) noexcept
|
||||
{
|
||||
move_from(std::move(x));
|
||||
}
|
||||
|
||||
template <class U>
|
||||
result( result<U> const & x )
|
||||
result( result const & x )
|
||||
{
|
||||
copy_from(x);
|
||||
}
|
||||
@@ -165,14 +125,14 @@ namespace boost { namespace leaf {
|
||||
move_from(std::move(x));
|
||||
}
|
||||
|
||||
result() noexcept:
|
||||
value_(T()),
|
||||
which_(leaf_detail::result_variant::value)
|
||||
template <class U>
|
||||
result( result<U> const & x )
|
||||
{
|
||||
copy_from(x);
|
||||
}
|
||||
|
||||
result( T const & v ):
|
||||
value_(v),
|
||||
result():
|
||||
value_(T()),
|
||||
which_(leaf_detail::result_variant::value)
|
||||
{
|
||||
}
|
||||
@@ -183,22 +143,25 @@ namespace boost { namespace leaf {
|
||||
{
|
||||
}
|
||||
|
||||
result( leaf::error const & e ) noexcept:
|
||||
err_(e),
|
||||
result( T const & v ):
|
||||
value_(v),
|
||||
which_(leaf_detail::result_variant::value)
|
||||
{
|
||||
}
|
||||
|
||||
result( error_id const & id ) noexcept:
|
||||
err_(id),
|
||||
which_(leaf_detail::result_variant::err)
|
||||
{
|
||||
}
|
||||
|
||||
result( leaf::error_capture const & cap ) noexcept:
|
||||
cap_(cap),
|
||||
which_(leaf_detail::result_variant::cap)
|
||||
{
|
||||
}
|
||||
result( std::shared_ptr<leaf_detail::dynamic_store> && ) noexcept;
|
||||
|
||||
result( leaf::error_capture && cap ) noexcept:
|
||||
cap_(std::move(cap)),
|
||||
which_(leaf_detail::result_variant::cap)
|
||||
result & operator=( result && x ) noexcept
|
||||
{
|
||||
destroy();
|
||||
move_from(std::move(x));
|
||||
return *this;
|
||||
}
|
||||
|
||||
result & operator=( result const & x )
|
||||
@@ -208,13 +171,22 @@ namespace boost { namespace leaf {
|
||||
return *this;
|
||||
}
|
||||
|
||||
result & operator=( result && x ) noexcept
|
||||
template <class U>
|
||||
result & operator=( result<U> && x ) noexcept
|
||||
{
|
||||
destroy();
|
||||
move_from(std::move(x));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
result & operator=( result<U> const & x )
|
||||
{
|
||||
destroy();
|
||||
copy_from(x);
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return which_==leaf_detail::result_variant::value;
|
||||
@@ -247,19 +219,19 @@ namespace boost { namespace leaf {
|
||||
}
|
||||
|
||||
template <class... E>
|
||||
leaf::error error( E && ... e ) noexcept
|
||||
error_id error( E && ... e ) noexcept
|
||||
{
|
||||
switch( which_ )
|
||||
{
|
||||
case leaf_detail::result_variant::value:
|
||||
return leaf::error(std::forward<E>(e)...);
|
||||
return leaf::new_error(std::forward<E>(e)...);
|
||||
case leaf_detail::result_variant::cap:
|
||||
{
|
||||
error_capture cap = cap_;
|
||||
destroy();
|
||||
(void) new(&err_) leaf::error(cap.unload());
|
||||
which_ = leaf_detail::result_variant::err;
|
||||
}
|
||||
{
|
||||
dynamic_store_ptr cap = cap_;
|
||||
destroy();
|
||||
(void) new(&err_) error_id(cap->unload());
|
||||
which_ = leaf_detail::result_variant::err;
|
||||
}
|
||||
default:
|
||||
assert(which_==leaf_detail::result_variant::err);
|
||||
return err_.propagate(std::forward<E>(e)...);
|
||||
@@ -273,23 +245,11 @@ namespace boost { namespace leaf {
|
||||
class result<void>:
|
||||
result<bool>
|
||||
{
|
||||
template <class... E, class T, class... F>
|
||||
friend typename leaf_detail::handler_pack_return_type<F...>::return_type leaf::handle_error( expect<E...> const &, result<T> const &, F && ... ) noexcept;
|
||||
|
||||
template <class P, class... E, class T>
|
||||
friend P const * leaf::peek( expect<E...> const &, result<T> const & ) noexcept;
|
||||
|
||||
template <class... E, class T>
|
||||
friend void leaf::diagnostic_output( std::ostream &, expect<E...> const &, result<T> const & );
|
||||
|
||||
template <class... E, class T>
|
||||
friend result<T> leaf::capture( expect<E...> &, result<T> const & );
|
||||
typedef result<bool> base;
|
||||
|
||||
template <class U>
|
||||
friend class result;
|
||||
|
||||
typedef result<bool> base;
|
||||
|
||||
result( result<bool> && rb ):
|
||||
base(std::move(rb))
|
||||
{
|
||||
@@ -297,81 +257,35 @@ namespace boost { namespace leaf {
|
||||
|
||||
public:
|
||||
|
||||
typedef void value_type;
|
||||
|
||||
~result() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
result() noexcept = default;
|
||||
result() = default;
|
||||
|
||||
result( leaf::error const & e ) noexcept:
|
||||
base(e)
|
||||
result( error_id const & id ) noexcept:
|
||||
base(id)
|
||||
{
|
||||
}
|
||||
|
||||
result( leaf::error_capture const & cap ) noexcept:
|
||||
base(cap)
|
||||
result( std::shared_ptr<leaf_detail::dynamic_store> && ) noexcept;
|
||||
|
||||
void value() const
|
||||
{
|
||||
(void) base::value();
|
||||
}
|
||||
|
||||
result( leaf::error_capture && cap ) noexcept:
|
||||
base(std::move(cap))
|
||||
void operator*() const
|
||||
{
|
||||
return value();
|
||||
}
|
||||
|
||||
using base::operator bool;
|
||||
using base::error;
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
template <class... E, class T, class... F>
|
||||
typename leaf_detail::handler_pack_return_type<F...>::return_type handle_error( expect<E...> const & exp, result<T> const & r, F && ... f ) noexcept
|
||||
{
|
||||
assert(!r);
|
||||
if( r.which_ == leaf_detail::result_variant::err )
|
||||
return handle_error(exp,r.err_,f...);
|
||||
else
|
||||
{
|
||||
assert(r.which_==leaf_detail::result_variant::cap);
|
||||
return handle_error(r.cap_,f...);
|
||||
}
|
||||
}
|
||||
|
||||
template <class P, class... E, class T>
|
||||
P const * peek( expect<E...> const & exp, result<T> const & r ) noexcept
|
||||
{
|
||||
assert(!r);
|
||||
if( r.which_==leaf_detail::result_variant::err )
|
||||
return peek<P>(exp,r.err_);
|
||||
else
|
||||
{
|
||||
assert(r.which_==leaf_detail::result_variant::cap);
|
||||
return peek<P>(r.cap_);
|
||||
}
|
||||
}
|
||||
|
||||
template <class... E, class T>
|
||||
void diagnostic_output( std::ostream & os, expect<E...> const & exp, result<T> const & r )
|
||||
{
|
||||
assert(!r);
|
||||
if( r.which_==leaf_detail::result_variant::err )
|
||||
return diagnostic_output(os,exp,r.err_);
|
||||
else
|
||||
{
|
||||
assert(r.which_==leaf_detail::result_variant::cap);
|
||||
return diagnostic_output(os,r.cap_);
|
||||
}
|
||||
}
|
||||
|
||||
template <class... E, class T>
|
||||
result<T> capture( expect<E...> & exp, result<T> const & r )
|
||||
{
|
||||
if( r.which_==leaf_detail::result_variant::err )
|
||||
return capture(exp,r.err_);
|
||||
else
|
||||
return r;
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#ifndef BOOST_LEAF_75F38740D98D11E881DDB244C82C3C47
|
||||
#define BOOST_LEAF_75F38740D98D11E881DDB244C82C3C47
|
||||
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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/common.hpp>
|
||||
#include <boost/leaf/error.hpp>
|
||||
#include <exception>
|
||||
|
||||
#define LEAF_EXCEPTION(...) ::boost::leaf::leaf_detail::exception_(__FILE__,__LINE__,__FUNCTION__,__VA_ARGS__)
|
||||
@@ -15,16 +16,14 @@
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace leaf_detail
|
||||
{
|
||||
inline void enforce_std_exception( std::exception const & ) { }
|
||||
inline void enforce_std_exception( std::exception const & ) noexcept { }
|
||||
|
||||
template <class Ex>
|
||||
class exception:
|
||||
public Ex,
|
||||
public error
|
||||
public error_id
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -34,14 +33,14 @@ namespace boost { namespace leaf {
|
||||
template <class... E>
|
||||
exception( Ex && ex, E && ... e ) noexcept:
|
||||
Ex(std::move(ex)),
|
||||
error(std::forward<E>(e)...)
|
||||
error_id(new_error(std::forward<E>(e)...))
|
||||
{
|
||||
leaf_detail::enforce_std_exception(*this);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Ex, class... E>
|
||||
exception<Ex> exception_( char const * file, int line, char const * function, Ex && ex, E && ... e )
|
||||
exception<Ex> exception_( char const * file, int line, char const * function, Ex && ex, E && ... e ) noexcept
|
||||
{
|
||||
assert(file&&*file);
|
||||
assert(line>0);
|
||||
@@ -51,7 +50,7 @@ namespace boost { namespace leaf {
|
||||
}
|
||||
|
||||
template <class Ex, class... E>
|
||||
leaf_detail::exception<Ex> exception( Ex && ex, E && ... e )
|
||||
leaf_detail::exception<Ex> exception( Ex && ex, E && ... e ) noexcept
|
||||
{
|
||||
return leaf_detail::exception<Ex>( std::forward<Ex>(ex), std::forward<E>(e)... );
|
||||
}
|
||||
63
include/boost/leaf/try.hpp
Normal file
63
include/boost/leaf/try.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef BOOST_LEAF_87F274C4D4BA11E89928D55AC82C3C47
|
||||
#define BOOST_LEAF_87F274C4D4BA11E89928D55AC82C3C47
|
||||
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/throw.hpp>
|
||||
#include <boost/leaf/detail/static_store.hpp>
|
||||
#include <boost/leaf/detail/print_exception_info.hpp>
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
|
||||
inline error_id get_error_id( std::exception const & ex ) noexcept
|
||||
{
|
||||
if( auto id = dynamic_cast<error_id const *>(&ex) )
|
||||
return *id;
|
||||
else
|
||||
return next_error();
|
||||
}
|
||||
|
||||
template <class TryBlock, class... Handler>
|
||||
decltype(std::declval<TryBlock>()()) try_( TryBlock && try_block, Handler && ... handler )
|
||||
{
|
||||
using namespace leaf_detail;
|
||||
typename deduce_static_store<typename handler_args_set<Handler...>::type>::type ss;
|
||||
ss.set_reset(true);
|
||||
try
|
||||
{
|
||||
return std::forward<TryBlock>(try_block)();
|
||||
}
|
||||
catch( captured_exception & cap )
|
||||
{
|
||||
try
|
||||
{
|
||||
cap.unload_and_rethrow_original_exception();
|
||||
assert(0);
|
||||
throw;
|
||||
}
|
||||
catch( std::exception const & ex )
|
||||
{
|
||||
return ss.handle_error(error_info(get_error_id(ex),&ex,&cap,&print_exception_info), std::forward<Handler>(handler)..., [ ]() -> typename function_traits<TryBlock>::return_type { throw; });
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
return ss.handle_error(error_info(next_error(),0,&cap,&print_exception_info), std::forward<Handler>(handler)..., [ ]() -> typename function_traits<TryBlock>::return_type { throw; });
|
||||
}
|
||||
}
|
||||
catch( std::exception const & ex )
|
||||
{
|
||||
return ss.handle_error(error_info(get_error_id(ex),&ex,0,&print_exception_info), std::forward<Handler>(handler)..., [ ]() -> typename function_traits<TryBlock>::return_type { throw; });
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
return ss.handle_error(error_info(next_error(),0,0,&print_exception_info), std::forward<Handler>(handler)..., [ ]() -> typename function_traits<TryBlock>::return_type { throw; });
|
||||
}
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
82
meson.build
82
meson.build
@@ -14,6 +14,7 @@ if not meson.is_subproject()
|
||||
'-Wno-unused-variable',
|
||||
'-Wno-non-virtual-dtor',
|
||||
'-Wno-dangling-else',
|
||||
'-Wno-delete-non-virtual-dtor',
|
||||
language:'cpp' )
|
||||
endif
|
||||
endif
|
||||
@@ -26,55 +27,50 @@ leaf = declare_dependency( include_directories: includes )
|
||||
|
||||
tests = [
|
||||
'_hpp_all_test',
|
||||
'_hpp_capture_exception_test',
|
||||
'_hpp_capture_result_test',
|
||||
'_hpp_common_test',
|
||||
'_hpp_error_capture_test',
|
||||
'_hpp_error_test',
|
||||
'_hpp_exception_capture_test',
|
||||
'_hpp_exception_test',
|
||||
'_hpp_expect_test',
|
||||
'_hpp_exception_to_result_test',
|
||||
'_hpp_handle_test',
|
||||
'_hpp_preload_test',
|
||||
'_hpp_result_test',
|
||||
'basic_test',
|
||||
'defer_test.1',
|
||||
'defer_test.2',
|
||||
'defer_test.3',
|
||||
'defer_test.4',
|
||||
'defer_test.5',
|
||||
'defer_test.6',
|
||||
'defer_test.7',
|
||||
'defer_test.8',
|
||||
'diagnostic_output_test',
|
||||
'error_capture_test.1',
|
||||
'error_capture_test.2',
|
||||
'error_test',
|
||||
'exception_capture_test',
|
||||
'exception_test.1',
|
||||
'exception_test.2',
|
||||
'expect_test.1',
|
||||
'expect_test.2',
|
||||
'expect_test.3',
|
||||
'expect_test.4',
|
||||
'expect_test.5',
|
||||
'_hpp_throw_test',
|
||||
'_hpp_try_test',
|
||||
'capture_exception_async_test',
|
||||
'capture_exception_state_test',
|
||||
'capture_exception_unload_test',
|
||||
'capture_result_async_test',
|
||||
'capture_result_state_test',
|
||||
'capture_result_unload_test',
|
||||
'defer_basic_test',
|
||||
'defer_nested_error_exception_test',
|
||||
'defer_nested_error_result_test',
|
||||
'defer_nested_new_error_exception_test',
|
||||
'defer_nested_new_error_result_test',
|
||||
'defer_nested_success_exception_test',
|
||||
'defer_nested_success_result_test',
|
||||
'diagnostic_info_test',
|
||||
'function_traits_test',
|
||||
'handle_all_test',
|
||||
'handle_some_basic_test',
|
||||
'handle_some_test',
|
||||
'is_error_type_test',
|
||||
'multiple_errors_test',
|
||||
'optional_test',
|
||||
'preload_test.1',
|
||||
'preload_test.2',
|
||||
'preload_test.3',
|
||||
'preload_test.4',
|
||||
'preload_test.5',
|
||||
'preload_test.6',
|
||||
'preload_test.7',
|
||||
'preload_basic_test',
|
||||
'preload_nested_error_exception_test',
|
||||
'preload_nested_error_result_test',
|
||||
'preload_nested_new_error_exception_test',
|
||||
'preload_nested_new_error_result_test',
|
||||
'preload_nested_success_exception_test',
|
||||
'preload_nested_success_result_test',
|
||||
'print_test',
|
||||
'result_capture_test',
|
||||
'result_test.1',
|
||||
'result_test.2',
|
||||
'result_test.3',
|
||||
'result_test.4',
|
||||
'result_test.5',
|
||||
'result_test.6',
|
||||
'result_void_capture_test'
|
||||
'result_bad_result_test',
|
||||
'result_state_test',
|
||||
'static_store_deduction_test',
|
||||
'static_store_test',
|
||||
'try_exception_test',
|
||||
'try_test'
|
||||
]
|
||||
foreach t : tests
|
||||
test(t, executable(t, 'test/'+t+'.cpp', dependencies: [leaf,thread_dep] ) )
|
||||
@@ -83,10 +79,10 @@ endforeach
|
||||
examples = [
|
||||
'capture_result',
|
||||
'capture_eh',
|
||||
'exception_to_result',
|
||||
'print_file_result',
|
||||
'print_file_eh',
|
||||
'print_half',
|
||||
'return_exception'
|
||||
'print_half'
|
||||
]
|
||||
foreach e : examples
|
||||
executable(e, 'example/'+e+'.cpp', dependencies: [leaf,thread_dep] )
|
||||
|
||||
108
test/Jamfile.v2
108
test/Jamfile.v2
@@ -8,70 +8,68 @@ import testing ;
|
||||
|
||||
project
|
||||
: requirements
|
||||
<toolset>gcc:<cxxflags>"-std=c++11"
|
||||
<toolset>gcc:<cxxflags>"-std=c++11 -Wno-delete-non-virtual-dtor -Wno-parentheses"
|
||||
<toolset>gcc:<linkflags>"-pthread"
|
||||
<toolset>darwin:<cxxflags>"-std=c++11 -Wno-unused-variable -Wno-non-virtual-dtor -Wno-dangling-else"
|
||||
<toolset>clang:<cxxflags>"-Wno-dangling-else"
|
||||
<toolset>darwin:<cxxflags>"-std=c++11 -Wno-unused-variable -Wno-delete-non-virtual-dtor -Wno-non-virtual-dtor -Wno-dangling-else"
|
||||
<toolset>msvc:<cxxflags>"-wd 4267 -wd 4996 -wd 4244"
|
||||
<include>../../..
|
||||
;
|
||||
|
||||
run _hpp_all_test.cpp ;
|
||||
run _hpp_common_test.cpp ;
|
||||
run _hpp_error_capture_test.cpp ;
|
||||
run _hpp_error_test.cpp ;
|
||||
run _hpp_exception_capture_test.cpp ;
|
||||
run _hpp_exception_test.cpp ;
|
||||
run _hpp_expect_test.cpp ;
|
||||
run _hpp_preload_test.cpp ;
|
||||
run _hpp_result_test.cpp ;
|
||||
run basic_test.cpp ;
|
||||
run defer_test.1.cpp ;
|
||||
run defer_test.2.cpp ;
|
||||
run defer_test.3.cpp ;
|
||||
run defer_test.4.cpp ;
|
||||
run defer_test.5.cpp ;
|
||||
run defer_test.6.cpp ;
|
||||
run defer_test.7.cpp ;
|
||||
run diagnostic_output_test.cpp ;
|
||||
run error_capture_test.1.cpp ;
|
||||
run error_capture_test.2.cpp ;
|
||||
run error_test.cpp ;
|
||||
run exception_capture_test.cpp : : : <threading>multi ;
|
||||
run exception_test.2.cpp ;
|
||||
run exception_test.1.cpp ;
|
||||
run expect_test.1.cpp ;
|
||||
run expect_test.2.cpp ;
|
||||
run expect_test.3.cpp ;
|
||||
run expect_test.4.cpp ;
|
||||
run expect_test.5.cpp ;
|
||||
run multiple_errors_test.cpp ;
|
||||
compile _hpp_all_test.cpp ;
|
||||
compile _hpp_capture_exception_test.cpp ;
|
||||
compile _hpp_capture_result_test.cpp ;
|
||||
compile _hpp_common_test.cpp ;
|
||||
compile _hpp_error_test.cpp ;
|
||||
compile _hpp_exception_to_result_test.cpp ;
|
||||
compile _hpp_handle_test.cpp ;
|
||||
compile _hpp_preload_test.cpp ;
|
||||
compile _hpp_result_test.cpp ;
|
||||
compile _hpp_throw_test.cpp ;
|
||||
compile _hpp_try_test.cpp ;
|
||||
|
||||
compile-fail is_error_type_fail_test.cpp ;
|
||||
|
||||
run capture_exception_async_test.cpp ;
|
||||
run capture_exception_state_test.cpp ;
|
||||
run capture_exception_unload_test.cpp ;
|
||||
run capture_result_async_test.cpp ;
|
||||
run capture_result_state_test.cpp ;
|
||||
run capture_result_unload_test.cpp ;
|
||||
run defer_basic_test.cpp ;
|
||||
run defer_nested_error_exception_test.cpp ;
|
||||
run defer_nested_error_result_test.cpp ;
|
||||
run defer_nested_new_error_exception_test.cpp ;
|
||||
run defer_nested_new_error_result_test.cpp ;
|
||||
run defer_nested_success_exception_test.cpp ;
|
||||
run defer_nested_success_result_test.cpp ;
|
||||
run diagnostic_info_test.cpp ;
|
||||
run function_traits_test.cpp ;
|
||||
run handle_all_test.cpp ;
|
||||
run handle_some_basic_test.cpp ;
|
||||
run handle_some_test.cpp ;
|
||||
run is_error_type_test.cpp ;
|
||||
run optional_test.cpp ;
|
||||
run preload_test.1.cpp ;
|
||||
run preload_test.2.cpp ;
|
||||
run preload_test.3.cpp ;
|
||||
run preload_test.4.cpp ;
|
||||
run preload_test.5.cpp ;
|
||||
run preload_test.6.cpp ;
|
||||
run preload_basic_test.cpp ;
|
||||
run preload_nested_error_exception_test.cpp ;
|
||||
run preload_nested_error_result_test.cpp ;
|
||||
run preload_nested_new_error_exception_test.cpp ;
|
||||
run preload_nested_new_error_result_test.cpp ;
|
||||
run preload_nested_success_exception_test.cpp ;
|
||||
run preload_nested_success_result_test.cpp ;
|
||||
run print_test.cpp ;
|
||||
run result_capture_test.cpp : : : <threading>multi ;
|
||||
run result_test.1.cpp ;
|
||||
run result_test.2.cpp ;
|
||||
run result_test.3.cpp ;
|
||||
run result_test.4.cpp ;
|
||||
run result_test.5.cpp ;
|
||||
run result_test.6.cpp ;
|
||||
run result_void_capture_test.cpp : : : <threading>multi ;
|
||||
compile-fail expect_fail_test.1.cpp ;
|
||||
compile-fail expect_fail_test.2.cpp ;
|
||||
compile-fail error_fail_test.cpp ;
|
||||
run result_bad_result_test.cpp ;
|
||||
run result_state_test.cpp ;
|
||||
run static_store_deduction_test.cpp ;
|
||||
run static_store_test.cpp ;
|
||||
run try_exception_test.cpp ;
|
||||
run try_test.cpp ;
|
||||
|
||||
exe print_file_result : ../example/print_file_result.cpp ;
|
||||
exe print_file_eh : ../example/print_file_eh.cpp ;
|
||||
#exe lua_callback_result : ../example/lua_callback_result.cpp ;
|
||||
#exe lua_callback_eh : ../example/lua_callback_eh.cpp ;
|
||||
exe capture_result : ../example/capture_result.cpp : <threading>multi ;
|
||||
exe capture_eh : ../example/capture_eh.cpp : <threading>multi ;
|
||||
exe capture_result : ../example/capture_result.cpp : <threading>multi ;
|
||||
exe exception_to_result : ../example/exception_to_result.cpp ;
|
||||
#exe lua_callback_result : ../example/exception_to_result.cpp ;
|
||||
#exe lua_callback_eh : ../example/lua_callback_eh.cpp ;
|
||||
exe print_file_eh : ../example/print_file_eh.cpp ;
|
||||
exe print_file_result : ../example/print_file_result.cpp ;
|
||||
exe print_half : ../example/print_half.cpp ;
|
||||
exe return_exception : ../example/return_exception.cpp ;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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/all.hpp>
|
||||
#include <boost/leaf/all.hpp>
|
||||
|
||||
9
test/_hpp_capture_exception_test.cpp
Normal file
9
test/_hpp_capture_exception_test.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/capture_exception.hpp>
|
||||
#include <boost/leaf/capture_exception.hpp>
|
||||
int main() { return 0; }
|
||||
9
test/_hpp_capture_result_test.cpp
Normal file
9
test/_hpp_capture_result_test.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/capture_result.hpp>
|
||||
#include <boost/leaf/capture_result.hpp>
|
||||
int main() { return 0; }
|
||||
@@ -1,8 +1,8 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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/common.hpp>
|
||||
#include <boost/leaf/common.hpp>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/error_capture.hpp>
|
||||
#include <boost/leaf/error_capture.hpp>
|
||||
int main() { return 0; }
|
||||
@@ -1,8 +1,8 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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/error.hpp>
|
||||
#include <boost/leaf/error.hpp>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/exception_capture.hpp>
|
||||
#include <boost/leaf/exception_capture.hpp>
|
||||
int main() { return 0; }
|
||||
@@ -1,9 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/exception.hpp>
|
||||
#include <boost/leaf/exception.hpp>
|
||||
int main() { return 0; }
|
||||
9
test/_hpp_exception_to_result_test.cpp
Normal file
9
test/_hpp_exception_to_result_test.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/exception_to_result.hpp>
|
||||
#include <boost/leaf/exception_to_result.hpp>
|
||||
int main() { return 0; }
|
||||
@@ -1,9 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/expect.hpp>
|
||||
#include <boost/leaf/expect.hpp>
|
||||
int main() { return 0; }
|
||||
9
test/_hpp_handle_test.cpp
Normal file
9
test/_hpp_handle_test.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/handle.hpp>
|
||||
#include <boost/leaf/handle.hpp>
|
||||
int main() { return 0; }
|
||||
@@ -1,8 +1,8 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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/preload.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, Inc.
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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)
|
||||
// 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/result.hpp>
|
||||
#include <boost/leaf/result.hpp>
|
||||
|
||||
9
test/_hpp_throw_test.cpp
Normal file
9
test/_hpp_throw_test.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/throw.hpp>
|
||||
#include <boost/leaf/throw.hpp>
|
||||
int main() { return 0; }
|
||||
9
test/_hpp_try_test.cpp
Normal file
9
test/_hpp_try_test.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/try.hpp>
|
||||
#include <boost/leaf/try.hpp>
|
||||
int main() { return 0; }
|
||||
@@ -1,134 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/expect.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int A>
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::error f1()
|
||||
{
|
||||
return leaf::error( info<1>{1} );
|
||||
}
|
||||
|
||||
leaf::error f2()
|
||||
{
|
||||
return f1().propagate( info<2>{2} );
|
||||
}
|
||||
|
||||
leaf::error f3()
|
||||
{
|
||||
return f2().propagate( info<3>{3} );
|
||||
}
|
||||
|
||||
leaf::error f4()
|
||||
{
|
||||
return f3().propagate();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
leaf::expect<info<1>,info<2>,info<4>> exp0;
|
||||
leaf::error e0 = f4();
|
||||
{
|
||||
info<1> const * p = leaf::peek<info<1>>(exp0,e0);
|
||||
BOOST_TEST(p && p->value==1);
|
||||
}
|
||||
|
||||
{
|
||||
info<2> const * p = leaf::peek<info<2>>(exp0,e0);
|
||||
BOOST_TEST(p && p->value==2);
|
||||
}
|
||||
|
||||
BOOST_TEST(!leaf::peek<info<4>>(exp0,e0));
|
||||
leaf::expect<info<1>,info<2>,info<4>> exp;
|
||||
leaf::error e1 = f4();
|
||||
|
||||
{
|
||||
info<1> const * p = leaf::peek<info<1>>(exp0,e0);
|
||||
BOOST_TEST(p && p->value==1);
|
||||
}
|
||||
|
||||
{
|
||||
info<2> const * p = leaf::peek<info<2>>(exp0,e0);
|
||||
BOOST_TEST(p && p->value==2);
|
||||
}
|
||||
|
||||
BOOST_TEST(!leaf::peek<info<4>>(exp0,e0));
|
||||
BOOST_TEST(!leaf::peek<info<1>>(exp,e0));
|
||||
BOOST_TEST(!leaf::peek<info<2>>(exp,e0));
|
||||
BOOST_TEST(!leaf::peek<info<4>>(exp,e0));
|
||||
|
||||
{
|
||||
info<1> const * p = leaf::peek<info<1>>(exp,e1);
|
||||
BOOST_TEST(p && p->value==1);
|
||||
}
|
||||
|
||||
{
|
||||
info<2> const * p = leaf::peek<info<2>>(exp,e1);
|
||||
BOOST_TEST(p && p->value==2);
|
||||
}
|
||||
|
||||
BOOST_TEST(!leaf::peek<info<4>>(exp,e1));
|
||||
BOOST_TEST( !handle_error( exp, e1, [ ](info<1>,info<2>,info<4>)->void { } ) );
|
||||
leaf::error e2 = f4();
|
||||
|
||||
{
|
||||
info<1> const * p = leaf::peek<info<1>>(exp,e2);
|
||||
BOOST_TEST(p && p->value==1);
|
||||
}
|
||||
|
||||
{
|
||||
info<2> const * p = leaf::peek<info<2>>(exp,e2);
|
||||
BOOST_TEST(p && p->value==2);
|
||||
}
|
||||
|
||||
BOOST_TEST(!leaf::peek<info<4>>(exp,e2));
|
||||
|
||||
{
|
||||
int c1=0, c2=0, c3=0;
|
||||
bool handled = handle_error( exp, e2,
|
||||
[&c1]( info<1>, info<2>, info<4> )
|
||||
{
|
||||
++c1;
|
||||
},
|
||||
[&c2]( info<1>, info<2>, info<4> )
|
||||
{
|
||||
++c2;
|
||||
},
|
||||
[&c3]( info<2> const & i2, info<1> const & i1 )
|
||||
{
|
||||
BOOST_TEST(i1.value==1);
|
||||
BOOST_TEST(i2.value==2);
|
||||
++c3;
|
||||
} );
|
||||
BOOST_TEST(handled);
|
||||
BOOST_TEST(c1==0);
|
||||
BOOST_TEST(c2==0);
|
||||
BOOST_TEST(c3==1);
|
||||
}
|
||||
|
||||
{
|
||||
int c=0;
|
||||
bool handled = handle_error( exp0, e0,
|
||||
[&c]( info<2> const & i2, info<1> const & i1 )
|
||||
{
|
||||
BOOST_TEST(i1.value==1);
|
||||
BOOST_TEST(i2.value==2);
|
||||
++c;
|
||||
} );
|
||||
BOOST_TEST(handled);
|
||||
BOOST_TEST(c==1);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
85
test/capture_exception_async_test.cpp
Normal file
85
test/capture_exception_async_test.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/capture_exception.hpp>
|
||||
#include <boost/leaf/try.hpp>
|
||||
#include <boost/leaf/throw.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
#include <vector>
|
||||
#include <future>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int> struct info { int value; };
|
||||
|
||||
struct fut_info
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
int result;
|
||||
std::future<int> fut;
|
||||
};
|
||||
|
||||
template <class... E, class F>
|
||||
std::vector<fut_info> launch_tasks( int task_count, F f )
|
||||
{
|
||||
assert(task_count>0);
|
||||
std::vector<fut_info> fut;
|
||||
std::generate_n( std::inserter(fut,fut.end()), task_count,
|
||||
[=]
|
||||
{
|
||||
int const a = rand();
|
||||
int const b = rand();
|
||||
int const res = (rand()%10) - 5;
|
||||
return fut_info { a, b, res, std::async( std::launch::async,
|
||||
[=]
|
||||
{
|
||||
return f(a,b,res);
|
||||
} ) };
|
||||
} );
|
||||
return fut;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::vector<fut_info> fut = launch_tasks<info<1>, info<2>>( 42,
|
||||
leaf::capture_exception<info<1>,info<2>,info<3>>(
|
||||
[ ]( int a, int b, int res )
|
||||
{
|
||||
if( res>=0 )
|
||||
return res;
|
||||
else
|
||||
throw leaf::exception( std::exception(), info<1>{a}, info<2>{b}, info<3>{} );
|
||||
} ) );
|
||||
|
||||
for( auto & f : fut )
|
||||
{
|
||||
f.fut.wait();
|
||||
int r = leaf::try_(
|
||||
[&]
|
||||
{
|
||||
return f.fut.get();
|
||||
},
|
||||
[&]( info<1> const & x1, info<2> const & x2 )
|
||||
{
|
||||
BOOST_TEST(x1.value==f.a);
|
||||
BOOST_TEST(x2.value==f.b);
|
||||
return -1;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return -2;
|
||||
} );
|
||||
if( f.result>=0 )
|
||||
BOOST_TEST(r==f.result);
|
||||
else
|
||||
BOOST_TEST(r==-1);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
59
test/capture_exception_state_test.cpp
Normal file
59
test/capture_exception_state_test.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/capture_exception.hpp>
|
||||
#include <boost/leaf/try.hpp>
|
||||
#include <boost/leaf/throw.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
int count = 0;
|
||||
|
||||
template <int>
|
||||
struct info
|
||||
{
|
||||
info() noexcept
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
info( info const & ) noexcept
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
~info() noexcept
|
||||
{
|
||||
--count;
|
||||
}
|
||||
};
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
template <int I> struct is_error_type<info<I>>: public std::true_type { };
|
||||
} }
|
||||
|
||||
int main()
|
||||
{
|
||||
auto f = leaf::capture_exception<info<1>, info<2>, info<3>>(
|
||||
[ ]
|
||||
{
|
||||
throw leaf::exception( std::exception(), info<1>{}, info<3>{} );
|
||||
} );
|
||||
leaf::try_(
|
||||
[&f]
|
||||
{
|
||||
BOOST_TEST(count==0);
|
||||
try { f(); }
|
||||
catch(...) { BOOST_TEST(count==2); throw; }
|
||||
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
} );
|
||||
BOOST_TEST(count==0);
|
||||
return boost::report_errors();
|
||||
}
|
||||
171
test/capture_exception_unload_test.cpp
Normal file
171
test/capture_exception_unload_test.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/capture_exception.hpp>
|
||||
#include <boost/leaf/try.hpp>
|
||||
#include <boost/leaf/throw.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int> struct info { int value; };
|
||||
|
||||
template <class F>
|
||||
void test( F f_ )
|
||||
{
|
||||
auto f = leaf::capture_exception<info<1>, info<2>, info<3>>( [=] { return f_(); } );
|
||||
|
||||
{
|
||||
int c=0;
|
||||
leaf::try_(
|
||||
[&f]
|
||||
{
|
||||
return f();
|
||||
},
|
||||
[&c]( info<1> const & x )
|
||||
{
|
||||
BOOST_TEST(x.value==1);
|
||||
BOOST_TEST(c==0);
|
||||
c = 1;
|
||||
},
|
||||
[&c]
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
c = 2;
|
||||
} );
|
||||
BOOST_TEST(c==1);
|
||||
}
|
||||
|
||||
{
|
||||
int c=0;
|
||||
leaf::try_(
|
||||
[&f]
|
||||
{
|
||||
return f();
|
||||
},
|
||||
[&c]( info<2> const & x )
|
||||
{
|
||||
BOOST_TEST(x.value==2);
|
||||
BOOST_TEST(c==0);
|
||||
c = 1;
|
||||
},
|
||||
[&c]
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
c = 2;
|
||||
} );
|
||||
BOOST_TEST(c==2);
|
||||
}
|
||||
|
||||
{
|
||||
int r = leaf::try_(
|
||||
[&f]
|
||||
{
|
||||
(void) f(); return 0;
|
||||
},
|
||||
[ ]( info<1> const & x )
|
||||
{
|
||||
BOOST_TEST(x.value==1);
|
||||
return 1;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST(r==1);
|
||||
}
|
||||
|
||||
{
|
||||
int r = leaf::try_(
|
||||
[&f]
|
||||
{
|
||||
(void) f(); return 0;
|
||||
},
|
||||
[ ]( info<2> const & x )
|
||||
{
|
||||
BOOST_TEST(x.value==2);
|
||||
return 1;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST(r==2);
|
||||
}
|
||||
|
||||
{
|
||||
bool r = leaf::try_(
|
||||
[&f]
|
||||
{
|
||||
(void) f(); return true;
|
||||
},
|
||||
[ ]( info<1> const & x, info<2> const & )
|
||||
{
|
||||
return true;
|
||||
},
|
||||
[ ]( info<1> const & x, info<3> const & y )
|
||||
{
|
||||
BOOST_TEST(x.value==1);
|
||||
BOOST_TEST(y.value==3);
|
||||
return false;
|
||||
},
|
||||
[ ]( info<1> const & x )
|
||||
{
|
||||
return true;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return true;
|
||||
} );
|
||||
BOOST_TEST(!r);
|
||||
}
|
||||
|
||||
{
|
||||
bool r = leaf::try_(
|
||||
[&f]
|
||||
{
|
||||
(void) f(); return false;
|
||||
},
|
||||
[ ]( info<1> const & x, info<2> const & )
|
||||
{
|
||||
return false;
|
||||
},
|
||||
[ ]( info<1> const & x, info<3> const & y )
|
||||
{
|
||||
BOOST_TEST(x.value==1);
|
||||
BOOST_TEST(y.value==3);
|
||||
return true;
|
||||
},
|
||||
[ ]( info<1> const & x )
|
||||
{
|
||||
return false;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return false;
|
||||
} );
|
||||
BOOST_TEST(r);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test(
|
||||
[ ]
|
||||
{
|
||||
throw leaf::exception( std::exception(), info<1>{1}, info<3>{3} ); // Derives from leaf::error_id
|
||||
} );
|
||||
|
||||
test(
|
||||
[ ]
|
||||
{
|
||||
auto propagate = leaf::preload( info<1>{1}, info<3>{3} );
|
||||
throw std::exception(); // Does not derive from leaf::error_id
|
||||
} );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
85
test/capture_result_async_test.cpp
Normal file
85
test/capture_result_async_test.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/capture_result.hpp>
|
||||
#include <boost/leaf/handle.hpp>
|
||||
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
#include <vector>
|
||||
#include <future>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int> struct info { int value; };
|
||||
|
||||
struct fut_info
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
int result;
|
||||
std::future<leaf::result<int>> fut;
|
||||
};
|
||||
|
||||
template <class... E, class F>
|
||||
std::vector<fut_info> launch_tasks( int task_count, F f )
|
||||
{
|
||||
assert(task_count>0);
|
||||
std::vector<fut_info> fut;
|
||||
std::generate_n( std::inserter(fut,fut.end()), task_count,
|
||||
[=]
|
||||
{
|
||||
int const a = rand();
|
||||
int const b = rand();
|
||||
int const res = (rand()%10) - 5;
|
||||
return fut_info { a, b, res, std::async( std::launch::async,
|
||||
[=]
|
||||
{
|
||||
return f(a,b,res);
|
||||
} ) };
|
||||
} );
|
||||
return fut;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::vector<fut_info> fut = launch_tasks<info<1>, info<2>>( 42,
|
||||
leaf::capture_result<info<1>,info<2>,info<3>>(
|
||||
[ ]( int a, int b, int res ) -> leaf::result<int>
|
||||
{
|
||||
if( res>=0 )
|
||||
return res;
|
||||
else
|
||||
return leaf::new_error( info<1>{a}, info<2>{b}, info<3>{} );
|
||||
} ) );
|
||||
|
||||
for( auto & f : fut )
|
||||
{
|
||||
f.fut.wait();
|
||||
int r = leaf::handle_all(
|
||||
[&]
|
||||
{
|
||||
return f.fut.get();
|
||||
},
|
||||
[&]( info<1> const & x1, info<2> const & x2 )
|
||||
{
|
||||
BOOST_TEST(x1.value==f.a);
|
||||
BOOST_TEST(x2.value==f.b);
|
||||
return -1;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return -2;
|
||||
} );
|
||||
if( f.result>=0 )
|
||||
BOOST_TEST(r==f.result);
|
||||
else
|
||||
BOOST_TEST(r==-1);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
59
test/capture_result_state_test.cpp
Normal file
59
test/capture_result_state_test.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/capture_result.hpp>
|
||||
#include <boost/leaf/handle.hpp>
|
||||
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
int count = 0;
|
||||
|
||||
template <int>
|
||||
struct info
|
||||
{
|
||||
info() noexcept
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
info( info const & ) noexcept
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
~info() noexcept
|
||||
{
|
||||
--count;
|
||||
}
|
||||
};
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
template <int I> struct is_error_type<info<I>>: public std::true_type { };
|
||||
} }
|
||||
|
||||
int main()
|
||||
{
|
||||
auto f = leaf::capture_result<info<1>, info<2>, info<3>>(
|
||||
[ ]() -> leaf::result<void>
|
||||
{
|
||||
return leaf::new_error( info<1>{}, info<3>{} );
|
||||
} );
|
||||
leaf::handle_all(
|
||||
[&f]
|
||||
{
|
||||
BOOST_TEST(count==0);
|
||||
auto r = f();
|
||||
BOOST_TEST(count==2);
|
||||
return r;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
} );
|
||||
BOOST_TEST(count==0);
|
||||
return boost::report_errors();
|
||||
}
|
||||
163
test/capture_result_unload_test.cpp
Normal file
163
test/capture_result_unload_test.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/capture_result.hpp>
|
||||
#include <boost/leaf/handle.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int> struct info { int value; };
|
||||
|
||||
template <class F>
|
||||
void test( F f_ )
|
||||
{
|
||||
auto f = leaf::capture_result<info<1>, info<2>, info<3>>( [=] { return f_(); } );
|
||||
|
||||
{
|
||||
int c=0;
|
||||
leaf::handle_all(
|
||||
[&f]
|
||||
{
|
||||
return f();
|
||||
},
|
||||
[&c]( info<1> const & x )
|
||||
{
|
||||
BOOST_TEST(x.value==1);
|
||||
BOOST_TEST(c==0);
|
||||
c = 1;
|
||||
},
|
||||
[&c]
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
c = 2;
|
||||
} );
|
||||
BOOST_TEST(c==1);
|
||||
}
|
||||
|
||||
{
|
||||
int c=0;
|
||||
leaf::handle_all(
|
||||
[&f]
|
||||
{
|
||||
return f();
|
||||
},
|
||||
[&c]( info<2> const & x )
|
||||
{
|
||||
BOOST_TEST(x.value==2);
|
||||
BOOST_TEST(c==0);
|
||||
c = 1;
|
||||
},
|
||||
[&c]
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
c = 2;
|
||||
} );
|
||||
BOOST_TEST(c==2);
|
||||
}
|
||||
|
||||
{
|
||||
int r = leaf::handle_all(
|
||||
[&f]() -> leaf::result<int>
|
||||
{
|
||||
return f().error();
|
||||
},
|
||||
[ ]( info<1> const & x )
|
||||
{
|
||||
BOOST_TEST(x.value==1);
|
||||
return 1;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST(r==1);
|
||||
}
|
||||
|
||||
{
|
||||
int r = leaf::handle_all(
|
||||
[&f]() -> leaf::result<int>
|
||||
{
|
||||
return f().error();
|
||||
},
|
||||
[ ]( info<2> const & x )
|
||||
{
|
||||
BOOST_TEST(x.value==2);
|
||||
return 1;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST(r==2);
|
||||
}
|
||||
|
||||
{
|
||||
bool r = leaf::handle_all(
|
||||
[&f]() -> leaf::result<bool>
|
||||
{
|
||||
return f().error();
|
||||
},
|
||||
[ ]( info<1> const & x, info<2> const & )
|
||||
{
|
||||
return true;
|
||||
},
|
||||
[ ]( info<1> const & x, info<3> const & y )
|
||||
{
|
||||
BOOST_TEST(x.value==1);
|
||||
BOOST_TEST(y.value==3);
|
||||
return false;
|
||||
},
|
||||
[ ]( info<1> const & x )
|
||||
{
|
||||
return true;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return true;
|
||||
} );
|
||||
BOOST_TEST(!r);
|
||||
}
|
||||
|
||||
{
|
||||
bool r = leaf::handle_all(
|
||||
[&f]() -> leaf::result<bool>
|
||||
{
|
||||
return f().error();
|
||||
},
|
||||
[ ]( info<1> const & x, info<2> const & )
|
||||
{
|
||||
return false;
|
||||
},
|
||||
[ ]( info<1> const & x, info<3> const & y )
|
||||
{
|
||||
BOOST_TEST(x.value==1);
|
||||
BOOST_TEST(y.value==3);
|
||||
return true;
|
||||
},
|
||||
[ ]( info<1> const & x )
|
||||
{
|
||||
return false;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return false;
|
||||
} );
|
||||
BOOST_TEST(r);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test(
|
||||
[ ]() -> leaf::result<void>
|
||||
{
|
||||
return leaf::new_error( info<1>{1}, info<3>{3} );
|
||||
} );
|
||||
return boost::report_errors();
|
||||
}
|
||||
56
test/defer_basic_test.cpp
Normal file
56
test/defer_basic_test.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/preload.hpp>
|
||||
#include <boost/leaf/handle.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
int global;
|
||||
|
||||
int get_global() noexcept
|
||||
{
|
||||
return global;
|
||||
}
|
||||
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::error_id g()
|
||||
{
|
||||
global = 0;
|
||||
auto propagate = leaf::defer( [ ] { return info{get_global()}; } );
|
||||
global = 42;
|
||||
return leaf::new_error();
|
||||
}
|
||||
|
||||
leaf::error_id f()
|
||||
{
|
||||
return g();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int r = leaf::handle_all(
|
||||
[ ]() -> leaf::result<int>
|
||||
{
|
||||
return f();
|
||||
},
|
||||
[ ]( info const & i42 )
|
||||
{
|
||||
BOOST_TEST(i42.value==42);
|
||||
return 1;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST(r==1);
|
||||
return boost::report_errors();
|
||||
}
|
||||
68
test/defer_nested_error_exception_test.cpp
Normal file
68
test/defer_nested_error_exception_test.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/preload.hpp>
|
||||
#include <boost/leaf/try.hpp>
|
||||
#include <boost/leaf/throw.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int>
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
void f0()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info<0>{0}; } );
|
||||
throw leaf::exception(std::exception(), info<2>{2} );
|
||||
}
|
||||
|
||||
void f1()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info<0>{-1}; }, [ ] { return info<1>{1}; }, [ ] { return info<2>{-1}; } );
|
||||
f0();
|
||||
}
|
||||
|
||||
void f2()
|
||||
{
|
||||
try
|
||||
{
|
||||
f1();
|
||||
}
|
||||
catch( leaf::error_id id )
|
||||
{
|
||||
id.propagate( info<3>{3} );
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int r = leaf::try_(
|
||||
[ ]
|
||||
{
|
||||
f2();
|
||||
return 0;
|
||||
},
|
||||
[ ]( info<0> i0, info<1> i1, info<2> i2, info<3> i3 )
|
||||
{
|
||||
BOOST_TEST(i0.value==0);
|
||||
BOOST_TEST(i1.value==1);
|
||||
BOOST_TEST(i2.value==2);
|
||||
BOOST_TEST(i3.value==3);
|
||||
return 1;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST(r==1);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
58
test/defer_nested_error_result_test.cpp
Normal file
58
test/defer_nested_error_result_test.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/preload.hpp>
|
||||
#include <boost/leaf/handle.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int>
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::error_id f0()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info<0>{0}; } );
|
||||
return leaf::new_error( info<2>{2} );
|
||||
}
|
||||
|
||||
leaf::error_id f1()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info<0>{-1}; }, [ ] { return info<1>{1}; }, [ ] { return info<2>{-1}; } );
|
||||
return f0();
|
||||
}
|
||||
|
||||
leaf::error_id f2()
|
||||
{
|
||||
return f1().propagate( info<3>{3} );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int r = leaf::handle_all(
|
||||
[ ]() -> leaf::result<int>
|
||||
{
|
||||
return f2();
|
||||
},
|
||||
[ ]( info<0> i0, info<1> i1, info<2> i2, info<3> i3 )
|
||||
{
|
||||
BOOST_TEST(i0.value==0);
|
||||
BOOST_TEST(i1.value==1);
|
||||
BOOST_TEST(i2.value==2);
|
||||
BOOST_TEST(i3.value==3);
|
||||
return 1;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST(r==1);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
75
test/defer_nested_new_error_exception_test.cpp
Normal file
75
test/defer_nested_new_error_exception_test.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/preload.hpp>
|
||||
#include <boost/leaf/try.hpp>
|
||||
#include <boost/leaf/throw.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int A>
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
void f0()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info<0>{-1}; } );
|
||||
throw leaf::exception( std::exception(), info<1>{-1} );
|
||||
}
|
||||
|
||||
void f1()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info<0>{0}; }, [ ] { return info<1>{1}; }, [ ] { return info<2>{2}; } );
|
||||
try { f0(); } catch(...) { }
|
||||
throw leaf::exception(std::exception());
|
||||
}
|
||||
|
||||
leaf::error_id f2()
|
||||
{
|
||||
try
|
||||
{
|
||||
f1();
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch( leaf::error_id id )
|
||||
{
|
||||
id.propagate( info<3>{3} );
|
||||
throw;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
return leaf::new_error();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int r = leaf::try_(
|
||||
[ ]
|
||||
{
|
||||
f2();
|
||||
return 0;
|
||||
},
|
||||
[ ]( info<0> i0, info<1> i1, info<2> i2, info<3> i3 )
|
||||
{
|
||||
BOOST_TEST(i0.value==0);
|
||||
BOOST_TEST(i1.value==1);
|
||||
BOOST_TEST(i2.value==2);
|
||||
BOOST_TEST(i3.value==3);
|
||||
return 1;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST(r==1);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
59
test/defer_nested_new_error_result_test.cpp
Normal file
59
test/defer_nested_new_error_result_test.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/preload.hpp>
|
||||
#include <boost/leaf/handle.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int A>
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::error_id f0()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info<0>{-1}; } );
|
||||
return leaf::new_error( info<1>{-1} );
|
||||
}
|
||||
|
||||
leaf::error_id f1()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info<0>{0}; }, [ ] { return info<1>{1}; }, [ ] { return info<2>{2}; } );
|
||||
(void) f0();
|
||||
return leaf::new_error();
|
||||
}
|
||||
|
||||
leaf::error_id f2()
|
||||
{
|
||||
return f1().propagate( info<3>{3} );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int r = leaf::handle_all(
|
||||
[ ]() -> leaf::result<int>
|
||||
{
|
||||
return f2();
|
||||
},
|
||||
[ ]( info<0> i0, info<1> i1, info<2> i2, info<3> i3 )
|
||||
{
|
||||
BOOST_TEST(i0.value==0);
|
||||
BOOST_TEST(i1.value==1);
|
||||
BOOST_TEST(i2.value==2);
|
||||
BOOST_TEST(i3.value==3);
|
||||
return 1;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST(r==1);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
52
test/defer_nested_success_exception_test.cpp
Normal file
52
test/defer_nested_success_exception_test.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/preload.hpp>
|
||||
#include <boost/leaf/try.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
struct info { int value; };
|
||||
|
||||
void g1()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info{1}; } );
|
||||
}
|
||||
|
||||
void g2()
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
void f()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info{2}; } );
|
||||
g1();
|
||||
g2();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int r = leaf::try_(
|
||||
[ ]
|
||||
{
|
||||
f();
|
||||
return 0;
|
||||
},
|
||||
[ ]( info x )
|
||||
{
|
||||
BOOST_TEST(x.value==2);
|
||||
return 1;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST(r==1);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
53
test/defer_nested_success_result_test.cpp
Normal file
53
test/defer_nested_success_result_test.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/preload.hpp>
|
||||
#include <boost/leaf/handle.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
struct info { int value; };
|
||||
|
||||
leaf::result<void> g1()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info{1}; } );
|
||||
return { };
|
||||
}
|
||||
|
||||
leaf::result<void> g2()
|
||||
{
|
||||
return leaf::new_error();
|
||||
}
|
||||
|
||||
leaf::result<void> f()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info{2}; } );
|
||||
LEAF_CHECK(g1());
|
||||
return g2();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int r = leaf::handle_all(
|
||||
[ ]() -> leaf::result<int>
|
||||
{
|
||||
LEAF_CHECK(f());
|
||||
return 1;
|
||||
},
|
||||
[ ]( info x )
|
||||
{
|
||||
BOOST_TEST(x.value==2);
|
||||
return 2;
|
||||
},
|
||||
[ ]
|
||||
{
|
||||
return 3;
|
||||
} );
|
||||
BOOST_TEST(r==2);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/expect.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
int global;
|
||||
|
||||
int get_global() noexcept
|
||||
{
|
||||
return global;
|
||||
}
|
||||
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::error g()
|
||||
{
|
||||
global = 0;
|
||||
auto propagate = leaf::defer( [ ] { return info{get_global()}; } );
|
||||
global = 42;
|
||||
return leaf::error();
|
||||
}
|
||||
|
||||
leaf::error f()
|
||||
{
|
||||
return g();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
leaf::expect<info> exp;
|
||||
int c=0;
|
||||
bool handled = handle_error( exp, f(),
|
||||
[&c]( info const & i42 )
|
||||
{
|
||||
BOOST_TEST(i42.value==42);
|
||||
++c;
|
||||
} );
|
||||
BOOST_TEST(handled);
|
||||
return boost::report_errors();
|
||||
BOOST_TEST(c==1);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/expect.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int A>
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::error f0()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info<0>{0}; } );
|
||||
return leaf::error( info<2>{2} );
|
||||
}
|
||||
|
||||
leaf::error f1()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info<0>{-1}; }, [ ] { return info<1>{1}; }, [ ] { return info<2>{-1}; } );
|
||||
return f0();
|
||||
}
|
||||
|
||||
leaf::error f2()
|
||||
{
|
||||
return f1().propagate( info<4>{4} );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
leaf::expect<info<0>,info<1>,info<2>,info<3>,info<4>> exp;
|
||||
leaf::error e = f2();
|
||||
BOOST_TEST(!leaf::peek<info<3>>(exp,e));
|
||||
int c=0;
|
||||
bool handled = handle_error( exp, e,
|
||||
[&c]( info<1> const & i1, info<2> const & i2, info<4> const & i4 )
|
||||
{
|
||||
BOOST_TEST(i1.value==1);
|
||||
BOOST_TEST(i2.value==2);
|
||||
BOOST_TEST(i4.value==4);
|
||||
++c;
|
||||
} );
|
||||
BOOST_TEST(handled);
|
||||
BOOST_TEST(c==1);
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/result.hpp>
|
||||
#include <boost/leaf/expect.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
struct info { int value; };
|
||||
|
||||
leaf::result<void> g1()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info{1}; } );
|
||||
return { };
|
||||
}
|
||||
|
||||
leaf::result<void> g2()
|
||||
{
|
||||
return leaf::error();
|
||||
}
|
||||
|
||||
leaf::result<void> f()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info{2}; } );
|
||||
LEAF_CHECK(g1());
|
||||
return g2();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
leaf::expect<info> exp;
|
||||
leaf::result<void> r = f();
|
||||
int c=0;
|
||||
BOOST_TEST( handle_error( exp, r,
|
||||
[&c]( info const & x )
|
||||
{
|
||||
BOOST_TEST(x.value==2);
|
||||
++c;
|
||||
} ) );
|
||||
BOOST_TEST(c==1);
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/exception.hpp>
|
||||
#include <boost/leaf/expect.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
struct my_error: std::exception { };
|
||||
|
||||
struct info { int value; };
|
||||
|
||||
void g1()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info{1}; } );
|
||||
}
|
||||
|
||||
void g2()
|
||||
{
|
||||
throw my_error();
|
||||
}
|
||||
|
||||
void f()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info{2}; } );
|
||||
g1();
|
||||
g2();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
leaf::expect<info> exp;
|
||||
try
|
||||
{
|
||||
f();
|
||||
}
|
||||
catch( my_error & e )
|
||||
{
|
||||
int c=0;
|
||||
handle_exception( exp, e,
|
||||
[&c]( info const & x )
|
||||
{
|
||||
BOOST_TEST(x.value==2);
|
||||
++c;
|
||||
} );
|
||||
BOOST_TEST(c==1);
|
||||
}
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/expect.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int A>
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::error f0()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info<0>{-1}; } );
|
||||
return leaf::error( info<1>{-1} );
|
||||
}
|
||||
|
||||
leaf::error f1()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info<0>{0}; }, [ ] { return info<1>{1}; }, [ ] { return info<2>{2}; } );
|
||||
(void) f0();
|
||||
return leaf::error();
|
||||
}
|
||||
|
||||
leaf::error f2()
|
||||
{
|
||||
return f1().propagate( info<3>{3} );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
leaf::expect<info<0>,info<1>,info<2>,info<3>> exp;
|
||||
leaf::error e = f2();
|
||||
int c=0;
|
||||
bool handled = handle_error( exp, e,
|
||||
[&c]( info<0> const & i0, info<1> const & i1, info<2> const & i2, info<3> const & i3 )
|
||||
{
|
||||
BOOST_TEST(i0.value==0);
|
||||
BOOST_TEST(i1.value==1);
|
||||
BOOST_TEST(i2.value==2);
|
||||
BOOST_TEST(i3.value==3);
|
||||
++c;
|
||||
} );
|
||||
BOOST_TEST(handled);
|
||||
BOOST_TEST(c==1);
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/expect.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::error f0()
|
||||
{
|
||||
return leaf::error();
|
||||
}
|
||||
|
||||
leaf::error f1()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info{0}; } );
|
||||
(void) f0();
|
||||
return leaf::error();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
leaf::expect<info> exp;
|
||||
leaf::error e = f1();
|
||||
int c=0;
|
||||
bool handled = handle_error( exp, e,
|
||||
[&c]( info const & i0 )
|
||||
{
|
||||
BOOST_TEST(i0.value==0);
|
||||
++c;
|
||||
} );
|
||||
BOOST_TEST(handled);
|
||||
BOOST_TEST(c==1);
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/exception.hpp>
|
||||
#include <boost/leaf/expect.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
struct my_error: std::exception { };
|
||||
|
||||
struct info { int value; };
|
||||
|
||||
void g1()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info{1}; } );
|
||||
}
|
||||
|
||||
void g2()
|
||||
{
|
||||
throw leaf::exception(my_error());
|
||||
}
|
||||
|
||||
void f()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info{2}; } );
|
||||
g1();
|
||||
g2();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
leaf::expect<info> exp;
|
||||
try
|
||||
{
|
||||
f();
|
||||
}
|
||||
catch( my_error & e )
|
||||
{
|
||||
int c=0;
|
||||
handle_exception( exp, e,
|
||||
[&c]( info const & x )
|
||||
{
|
||||
BOOST_TEST(x.value==2);
|
||||
++c;
|
||||
} );
|
||||
BOOST_TEST(c==1);
|
||||
}
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/expect.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::error f0()
|
||||
{
|
||||
return leaf::error();
|
||||
}
|
||||
|
||||
leaf::error f1()
|
||||
{
|
||||
auto propagate = leaf::defer( [ ] { return info{42}; } );
|
||||
return f0();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
leaf::expect<leaf::e_unexpected,leaf::e_unexpected_diagnostic_output> exp;
|
||||
leaf::error e = f1();
|
||||
int c=0;
|
||||
bool handled = handle_error( exp, e,
|
||||
[&c]( leaf::e_unexpected const & unx, leaf::e_unexpected_diagnostic_output const & unxdo )
|
||||
{
|
||||
BOOST_TEST(unx.count==1);
|
||||
BOOST_TEST(unx.first_type==&leaf::type<info>);
|
||||
BOOST_TEST(unxdo.value.find(": 42")!=std::string::npos);
|
||||
++c;
|
||||
} );
|
||||
BOOST_TEST(handled);
|
||||
BOOST_TEST(c==1);
|
||||
return boost::report_errors();
|
||||
}
|
||||
186
test/diagnostic_info_test.cpp
Normal file
186
test/diagnostic_info_test.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
// Copyright (c) 2018 Emil Dotchevski
|
||||
// Copyright (c) 2018 Second Spectrum, 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/try.hpp>
|
||||
#include <boost/leaf/capture_exception.hpp>
|
||||
#include <boost/leaf/common.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
#include <sstream>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int A>
|
||||
struct unexpected_test
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
struct my_error:
|
||||
virtual std::exception
|
||||
{
|
||||
char const * what() const noexcept
|
||||
{
|
||||
return "my_error";
|
||||
}
|
||||
};
|
||||
|
||||
struct printable_payload
|
||||
{
|
||||
friend std::ostream & operator<<( std::ostream & os, printable_payload const & x )
|
||||
{
|
||||
return os << "printed printable_payload";
|
||||
}
|
||||
};
|
||||
|
||||
struct non_printable_payload
|
||||
{
|
||||
};
|
||||
|
||||
struct printable_info_printable_payload
|
||||
{
|
||||
printable_payload value;
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, printable_info_printable_payload const & x )
|
||||
{
|
||||
return os << "*** printable_info_printable_payload " << x.value << " ***";
|
||||
}
|
||||
};
|
||||
|
||||
struct printable_info_non_printable_payload
|
||||
{
|
||||
non_printable_payload value;
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, printable_info_non_printable_payload const & x )
|
||||
{
|
||||
return os << "*** printable_info_non_printable_payload ***";
|
||||
}
|
||||
};
|
||||
|
||||
struct non_printable_info_printable_payload
|
||||
{
|
||||
printable_payload value;
|
||||
};
|
||||
|
||||
struct non_printable_info_non_printable_payload
|
||||
{
|
||||
non_printable_payload value;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
leaf::try_(
|
||||
[ ]
|
||||
{
|
||||
LEAF_THROW( my_error(),
|
||||
printable_info_printable_payload(),
|
||||
printable_info_non_printable_payload(),
|
||||
non_printable_info_printable_payload(),
|
||||
non_printable_info_non_printable_payload(),
|
||||
unexpected_test<1>{1},
|
||||
unexpected_test<2>{2},
|
||||
leaf::e_errno{ENOENT} );
|
||||
},
|
||||
[ ](
|
||||
leaf::e_source_location,
|
||||
printable_info_printable_payload,
|
||||
printable_info_non_printable_payload,
|
||||
non_printable_info_printable_payload,
|
||||
non_printable_info_non_printable_payload,
|
||||
leaf::e_errno,
|
||||
leaf::error_info const & unmatched )
|
||||
{
|
||||
std::ostringstream st;
|
||||
st << unmatched;
|
||||
std::string s = st.str();
|
||||
BOOST_TEST(s.find("std::exception::what(): my_error")!=s.npos);
|
||||
BOOST_TEST(s.find(": N/A")!=s.npos);
|
||||
BOOST_TEST(s.find(": printed printable_payload")!=s.npos);
|
||||
BOOST_TEST(s.find("*** printable_info_non_printable_payload ***")!=s.npos);
|
||||
BOOST_TEST(s.find("*** printable_info_printable_payload printed printable_payload ***")!=s.npos);
|
||||
BOOST_TEST(s.find(") in function")!=s.npos);
|
||||
BOOST_TEST(s.find("unexpected")==s.npos);
|
||||
std::cout << s;
|
||||
} );
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
leaf::try_(
|
||||
[ ]
|
||||
{
|
||||
LEAF_THROW( my_error(),
|
||||
printable_info_printable_payload(),
|
||||
printable_info_non_printable_payload(),
|
||||
non_printable_info_printable_payload(),
|
||||
non_printable_info_non_printable_payload(),
|
||||
unexpected_test<1>{1},
|
||||
unexpected_test<2>{2},
|
||||
leaf::e_errno{ENOENT} );
|
||||
},
|
||||
[ ](
|
||||
leaf::e_source_location,
|
||||
printable_info_printable_payload,
|
||||
printable_info_non_printable_payload,
|
||||
non_printable_info_printable_payload,
|
||||
non_printable_info_non_printable_payload,
|
||||
leaf::e_errno,
|
||||
leaf::diagnostic_info const & unmatched )
|
||||
{
|
||||
std::ostringstream st;
|
||||
st << unmatched;
|
||||
std::string s = st.str();
|
||||
BOOST_TEST(s.find("std::exception::what(): my_error")!=s.npos);
|
||||
BOOST_TEST(s.find(": N/A")!=s.npos);
|
||||
BOOST_TEST(s.find(": printed printable_payload")!=s.npos);
|
||||
BOOST_TEST(s.find("*** printable_info_non_printable_payload ***")!=s.npos);
|
||||
BOOST_TEST(s.find("*** printable_info_printable_payload printed printable_payload ***")!=s.npos);
|
||||
BOOST_TEST(s.find(") in function")!=s.npos);
|
||||
BOOST_TEST(s.find("Detected 2 attempts")!=s.npos);
|
||||
BOOST_TEST(s.find("unexpected_test<1>")!=s.npos);
|
||||
BOOST_TEST(s.find("unexpected_test<2>")==s.npos);
|
||||
std::cout << s;
|
||||
} );
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
leaf::try_(
|
||||
[ ]
|
||||
{
|
||||
LEAF_THROW( my_error(),
|
||||
printable_info_printable_payload(),
|
||||
printable_info_non_printable_payload(),
|
||||
non_printable_info_printable_payload(),
|
||||
non_printable_info_non_printable_payload(),
|
||||
unexpected_test<1>{1},
|
||||
unexpected_test<2>{2},
|
||||
leaf::e_errno{ENOENT} );
|
||||
},
|
||||
[ ](
|
||||
leaf::e_source_location,
|
||||
printable_info_printable_payload,
|
||||
printable_info_non_printable_payload,
|
||||
non_printable_info_printable_payload,
|
||||
non_printable_info_non_printable_payload,
|
||||
leaf::e_errno,
|
||||
leaf::verbose_diagnostic_info const & di )
|
||||
{
|
||||
std::ostringstream st;
|
||||
st << di;
|
||||
std::string s = st.str();
|
||||
BOOST_TEST(s.find("std::exception::what(): my_error")!=s.npos);
|
||||
BOOST_TEST(s.find(": N/A")!=s.npos);
|
||||
BOOST_TEST(s.find(": printed printable_payload")!=s.npos);
|
||||
BOOST_TEST(s.find("*** printable_info_non_printable_payload ***")!=s.npos);
|
||||
BOOST_TEST(s.find("*** printable_info_printable_payload printed printable_payload ***")!=s.npos);
|
||||
BOOST_TEST(s.find(") in function")!=s.npos);
|
||||
BOOST_TEST(s.find("unexpected_test<1>")!=s.npos);
|
||||
BOOST_TEST(s.find("unexpected_test<2>")!=s.npos);
|
||||
std::cout << s;
|
||||
} );
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/diagnostic_output_current_exception.hpp>
|
||||
#include <boost/leaf/common.hpp>
|
||||
#include <boost/leaf/exception.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
#include <sstream>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int A>
|
||||
struct unexpected_test
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
struct my_error:
|
||||
virtual std::exception
|
||||
{
|
||||
char const * what() const noexcept
|
||||
{
|
||||
return "my_error";
|
||||
}
|
||||
};
|
||||
|
||||
struct printable_payload
|
||||
{
|
||||
friend std::ostream & operator<<( std::ostream & os, printable_payload const & x )
|
||||
{
|
||||
return os << "printed printable_payload";
|
||||
}
|
||||
};
|
||||
|
||||
struct non_printable_payload
|
||||
{
|
||||
};
|
||||
|
||||
struct printable_info_printable_payload
|
||||
{
|
||||
printable_payload value;
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, printable_info_printable_payload const & x )
|
||||
{
|
||||
return os << "*** printable_info_printable_payload " << x.value << " ***";
|
||||
}
|
||||
};
|
||||
|
||||
struct printable_info_non_printable_payload
|
||||
{
|
||||
non_printable_payload value;
|
||||
|
||||
friend std::ostream & operator<<( std::ostream & os, printable_info_non_printable_payload const & x )
|
||||
{
|
||||
return os << "*** printable_info_non_printable_payload ***";
|
||||
}
|
||||
};
|
||||
|
||||
struct non_printable_info_printable_payload
|
||||
{
|
||||
printable_payload value;
|
||||
};
|
||||
|
||||
struct non_printable_info_non_printable_payload
|
||||
{
|
||||
non_printable_payload value;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_TEST(leaf::leaf_detail::tl_unexpected_enabled_counter()==0);
|
||||
{
|
||||
leaf::expect
|
||||
<
|
||||
leaf::e_source_location,
|
||||
printable_info_printable_payload,
|
||||
printable_info_non_printable_payload,
|
||||
non_printable_info_printable_payload,
|
||||
non_printable_info_non_printable_payload,
|
||||
leaf::e_errno,
|
||||
leaf::e_unexpected_diagnostic_output,
|
||||
leaf::e_unexpected
|
||||
> exp;
|
||||
BOOST_TEST(leaf::leaf_detail::tl_unexpected_enabled_counter()==2);
|
||||
try
|
||||
{
|
||||
LEAF_THROW( my_error(),
|
||||
printable_info_printable_payload(),
|
||||
printable_info_non_printable_payload(),
|
||||
non_printable_info_printable_payload(),
|
||||
non_printable_info_non_printable_payload(),
|
||||
unexpected_test<1>{1},
|
||||
unexpected_test<2>{2},
|
||||
leaf::e_errno{ENOENT} );
|
||||
}
|
||||
catch( my_error & e )
|
||||
{
|
||||
std::ostringstream st;
|
||||
diagnostic_output_current_exception(st,exp);
|
||||
std::string s = st.str();
|
||||
BOOST_TEST(s.find("std::exception::what(): my_error")!=s.npos);
|
||||
BOOST_TEST(s.find(": N/A")!=s.npos);
|
||||
BOOST_TEST(s.find(": printed printable_payload")!=s.npos);
|
||||
BOOST_TEST(s.find("*** printable_info_non_printable_payload ***")!=s.npos);
|
||||
BOOST_TEST(s.find("*** printable_info_printable_payload printed printable_payload ***")!=s.npos);
|
||||
BOOST_TEST(s.find(") in function")!=s.npos);
|
||||
BOOST_TEST(s.find("Detected 2 attempts to communicate unexpected error objects, the first one of type ")!=s.npos);
|
||||
BOOST_TEST(s.find("unexpected_test")!=s.npos);
|
||||
std::cout << s;
|
||||
handle_exception( exp, e, [ ]{ } );
|
||||
}
|
||||
}
|
||||
BOOST_TEST(leaf::leaf_detail::tl_unexpected_enabled_counter()==0);
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/error_capture.hpp>
|
||||
#include <boost/leaf/expect.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int> struct info { int value; };
|
||||
|
||||
leaf::error f()
|
||||
{
|
||||
return leaf::error(info<1>{1},info<3>{3});
|
||||
}
|
||||
|
||||
leaf::error_capture make_capture()
|
||||
{
|
||||
leaf::expect<info<1>,info<2>,info<3>> exp;
|
||||
return capture(exp,f());
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
leaf::error_capture ec = make_capture();
|
||||
|
||||
{
|
||||
int c=0;
|
||||
bool r = handle_error( ec,
|
||||
[&c]( info<1> const & x )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
BOOST_TEST(x.value==1);
|
||||
c = 1;
|
||||
} );
|
||||
BOOST_TEST(r);
|
||||
BOOST_TEST(c==1);
|
||||
}
|
||||
|
||||
{
|
||||
int c=0;
|
||||
bool r = handle_error( ec,
|
||||
[&c]( info<2> const & x )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
BOOST_TEST(x.value==2);
|
||||
c = 1;
|
||||
} );
|
||||
BOOST_TEST(!r);
|
||||
BOOST_TEST(c==0);
|
||||
}
|
||||
|
||||
{
|
||||
int c=0;
|
||||
int r = handle_error( ec,
|
||||
[&c]( info<1> const & x )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
BOOST_TEST(x.value==1);
|
||||
return c = 1;
|
||||
} );
|
||||
BOOST_TEST(r==1);
|
||||
}
|
||||
|
||||
{
|
||||
int c=0;
|
||||
int r = handle_error( ec,
|
||||
[&c]( info<2> const & x )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
BOOST_TEST(x.value==2);
|
||||
return c = 1;
|
||||
} );
|
||||
BOOST_TEST(r==-1);
|
||||
}
|
||||
|
||||
{
|
||||
int c=0;
|
||||
bool r = handle_error( ec,
|
||||
[&c]( info<1> const & x, info<2> const & )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
c = 1;
|
||||
},
|
||||
[&c]( info<1> const & x, info<3> const & y )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
BOOST_TEST(x.value==1);
|
||||
BOOST_TEST(y.value==3);
|
||||
c = 2;
|
||||
return false;
|
||||
},
|
||||
[&c]( info<1> const & x )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
c = 3;
|
||||
} );
|
||||
BOOST_TEST(!r);
|
||||
BOOST_TEST(c==2);
|
||||
}
|
||||
|
||||
{
|
||||
int c=0;
|
||||
bool r = handle_error( ec,
|
||||
[&c]( info<1> const & x, info<2> const & )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
c = 1;
|
||||
return false;
|
||||
},
|
||||
[&c]( info<1> const & x, info<3> const & y )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
BOOST_TEST(x.value==1);
|
||||
BOOST_TEST(y.value==3);
|
||||
c = 2;
|
||||
},
|
||||
[&c]( info<1> const & x )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
c = 3;
|
||||
return false;
|
||||
} );
|
||||
BOOST_TEST(r);
|
||||
BOOST_TEST(c==2);
|
||||
}
|
||||
|
||||
{
|
||||
leaf::expect<info<1>,info<2>,info<3>> exp;
|
||||
leaf::error e1( info<1>{-1}, info<2>{-2}, info<3>{-3} );
|
||||
leaf::error e2 = ec.unload();
|
||||
{
|
||||
int c = 0;
|
||||
bool r = handle_error( exp, e1,
|
||||
[&c]( info<1>, info<2>, info<3> )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
c = 1;
|
||||
},
|
||||
[&c]( info<1>, info<3> )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
c = 2;
|
||||
},
|
||||
[&c]( info<2> const & y )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
BOOST_TEST(y.value==-2);
|
||||
c = 3;
|
||||
} );
|
||||
BOOST_TEST(r);
|
||||
BOOST_TEST(c==3);
|
||||
}
|
||||
{
|
||||
int c = 0;
|
||||
bool r = handle_error( exp, e2,
|
||||
[&c]( info<1>, info<2>, info<3> )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
c = 1;
|
||||
},
|
||||
[&c]( info<2> const & y )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
c = 2;
|
||||
},
|
||||
[&c]( info<1> const & x, info<3> const & z )
|
||||
{
|
||||
BOOST_TEST(c==0);
|
||||
BOOST_TEST(x.value==1);
|
||||
BOOST_TEST(z.value==3);
|
||||
c = 3;
|
||||
} );
|
||||
BOOST_TEST(r);
|
||||
BOOST_TEST(c==3);
|
||||
}
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/error_capture.hpp>
|
||||
#include <boost/leaf/expect.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
int count = 0;
|
||||
|
||||
template <int>
|
||||
struct info
|
||||
{
|
||||
info() noexcept
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
info( info const & ) noexcept
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
~info() noexcept
|
||||
{
|
||||
--count;
|
||||
}
|
||||
};
|
||||
|
||||
namespace boost { namespace leaf {
|
||||
template <int I> struct is_error_type<info<I>>: public std::true_type { };
|
||||
} }
|
||||
|
||||
leaf::error f()
|
||||
{
|
||||
return leaf::error(info<1>{},info<3>{});
|
||||
}
|
||||
|
||||
leaf::error_capture make_capture()
|
||||
{
|
||||
leaf::expect<info<1>,info<2>,info<3>> exp;
|
||||
return capture(exp,f());
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
leaf::error_capture ec1 = make_capture();
|
||||
BOOST_TEST( handle_error( ec1, [ ]( info<1>, info<3> ) { } ) );
|
||||
BOOST_TEST(count==2);
|
||||
leaf::error_capture ec2(ec1);
|
||||
BOOST_TEST(count==2);
|
||||
BOOST_TEST( handle_error( ec1, [ ]( info<1>, info<3> ) { } ) );
|
||||
BOOST_TEST( handle_error( ec2, [ ]( info<1>, info<3> ) { } ) );
|
||||
leaf::error_capture ec3(std::move(ec2));
|
||||
BOOST_TEST(count==2);
|
||||
BOOST_TEST( handle_error( ec1, [ ]( info<1>, info<3> ) { } ) );
|
||||
BOOST_TEST( handle_error( ec3, [ ]( info<1>, info<3> ) { } ) );
|
||||
leaf::error_capture ec4; ec4 = ec3;
|
||||
BOOST_TEST(count==2);
|
||||
BOOST_TEST( handle_error( ec1, [ ]( info<1>, info<3> ) { } ) );
|
||||
BOOST_TEST( handle_error( ec3, [ ]( info<1>, info<3> ) { } ) );
|
||||
BOOST_TEST( handle_error( ec4, [ ]( info<1>, info<3> ) { } ) );
|
||||
leaf::error_capture ec5; ec5 = std::move(ec4);
|
||||
BOOST_TEST(count==2);
|
||||
BOOST_TEST( handle_error( ec1, [ ]( info<1>, info<3> ) { } ) );
|
||||
BOOST_TEST( handle_error( ec3, [ ]( info<1>, info<3> ) { } ) );
|
||||
BOOST_TEST( handle_error( ec5, [ ]( info<1>, info<3> ) { } ) );
|
||||
}
|
||||
BOOST_TEST(count==0);
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/error.hpp>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
struct no_member_value { };
|
||||
|
||||
leaf::error f()
|
||||
{
|
||||
//Note: the line below should trigger a compile error (via static_assert).
|
||||
return leaf::error( no_member_value{ } );
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/expect.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
#include <string.h>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
template <int A>
|
||||
struct unexp
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
template <int A>
|
||||
struct info
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
leaf::error f1()
|
||||
{
|
||||
return LEAF_ERROR( info<1>{1}, unexp<1>{1}, unexp<2>{2} );
|
||||
}
|
||||
|
||||
leaf::error f2()
|
||||
{
|
||||
leaf::expect<info<1>> exp;
|
||||
return f1().propagate( info<2>{2} );
|
||||
}
|
||||
|
||||
leaf::error f3()
|
||||
{
|
||||
leaf::expect<info<2>,info<3>,unexp<1>> exp;
|
||||
leaf::error e = f2().propagate( info<4>{4} );
|
||||
BOOST_TEST(leaf::peek<unexp<1>>(exp,e)->value==1);
|
||||
return e;
|
||||
}
|
||||
|
||||
leaf::error f4()
|
||||
{
|
||||
leaf::expect<leaf::e_source_location,leaf::e_unexpected,info<1>,info<2>,info<3>,info<4>> exp;
|
||||
{
|
||||
leaf::error e = f3();
|
||||
bool handled = handle_error( exp, e,
|
||||
[ ]( info<1>, info<2>, info<3>, info<4> ){ },
|
||||
[ ]( info<1>, info<2>, info<4> ) { } );
|
||||
BOOST_TEST(handled);
|
||||
}
|
||||
leaf::error e = f3();
|
||||
int c1=0, c2=0;
|
||||
bool handled = handle_error( exp, e,
|
||||
[&c1]( info<1>,info<2>,info<3>,info<4> )
|
||||
{
|
||||
++c1;
|
||||
},
|
||||
[&c2]( leaf::e_source_location const & loc, leaf::e_unexpected const & unx, info<1> const & i1, info<2> const & i2, info<4> const & i4 )
|
||||
{
|
||||
BOOST_TEST(loc.line==27);
|
||||
BOOST_TEST(strcmp(loc.file,__FILE__)==0);
|
||||
BOOST_TEST(strstr(loc.function,"f1")!=0);
|
||||
BOOST_TEST(unx.count==2);
|
||||
BOOST_TEST(unx.first_type==&leaf::type<unexp<2>>);
|
||||
BOOST_TEST(i1.value==1);
|
||||
BOOST_TEST(i2.value==2);
|
||||
BOOST_TEST(i4.value==4);
|
||||
++c2;
|
||||
} );
|
||||
BOOST_TEST(handled);
|
||||
BOOST_TEST(c1==0);
|
||||
BOOST_TEST(c2==1);
|
||||
return leaf::error();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
leaf::expect<info<2>,info<3>,info<4>> exp;
|
||||
leaf::error e=f4();
|
||||
BOOST_TEST(!leaf::peek<info<2>>(exp,e));
|
||||
BOOST_TEST(!leaf::peek<info<3>>(exp,e));
|
||||
BOOST_TEST(!leaf::peek<info<4>>(exp,e));
|
||||
BOOST_TEST(leaf::leaf_detail::tl_slot_ptr<info<1>>()==0);
|
||||
BOOST_TEST(leaf::leaf_detail::tl_slot_ptr<info<2>>()!=0);
|
||||
BOOST_TEST(leaf::leaf_detail::tl_slot_ptr<info<3>>()!=0);
|
||||
BOOST_TEST(leaf::leaf_detail::tl_slot_ptr<info<4>>()!=0);
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
//Copyright (c) 2018 Emil Dotchevski
|
||||
//Copyright (c) 2018 Second Spectrum, 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/exception_capture.hpp>
|
||||
#include <boost/leaf/preload.hpp>
|
||||
#include <boost/leaf/exception.hpp>
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
#include <vector>
|
||||
#include <future>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
|
||||
namespace leaf = boost::leaf;
|
||||
|
||||
struct my_error: std::exception { };
|
||||
|
||||
template <int> struct info { int value; };
|
||||
|
||||
struct fut_info
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
int result;
|
||||
std::future<int> fut;
|
||||
};
|
||||
|
||||
template <class F>
|
||||
std::vector<fut_info> launch_tasks( int task_count, F && f )
|
||||
{
|
||||
assert(task_count>0);
|
||||
std::vector<fut_info> fut;
|
||||
std::generate_n( std::inserter(fut,fut.end()), task_count, [&f]
|
||||
{
|
||||
int const a = rand();
|
||||
int const b = rand();
|
||||
int const res = (rand()%10) - 5;
|
||||
return fut_info { a, b, res, std::async( std::launch::async, [f,a,b,res]
|
||||
{
|
||||
auto wrapper = leaf::capture_exception<info<1>,info<2>,info<3>>(std::move(f));
|
||||
return wrapper( a, b, res );
|
||||
} ) };
|
||||
} );
|
||||
return fut;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void test( int task_count, F && f ) noexcept
|
||||
{
|
||||
std::vector<fut_info> fut = launch_tasks( task_count, std::forward<F>(f) );
|
||||
for( auto & f : fut )
|
||||
{
|
||||
using namespace leaf::leaf_detail;
|
||||
f.fut.wait();
|
||||
leaf::expect<info<1>,info<2>,info<4>> exp;
|
||||
try
|
||||
{
|
||||
int r = leaf::get(f.fut);
|
||||
BOOST_TEST(r>=0);
|
||||
BOOST_TEST(r==f.result);
|
||||
}
|
||||
catch( my_error const & e )
|
||||
{
|
||||
int c=0;
|
||||
handle_exception( exp, e, [&f,&c]( info<1> const & x1, info<2> const & x2 )
|
||||
{
|
||||
BOOST_TEST(x1.value==f.a);
|
||||
BOOST_TEST(x2.value==f.b);
|
||||
++c;
|
||||
} );
|
||||
BOOST_TEST(c==1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test( 42, [ ]( int a, int b, int res )
|
||||
{
|
||||
if( res>=0 )
|
||||
return res;
|
||||
else
|
||||
throw leaf::exception( my_error(), info<1>{a}, info<2>{b}, info<3>{} );
|
||||
} );
|
||||
|
||||
test( 42, [ ]( int a, int b, int res )
|
||||
{
|
||||
if( res>=0 )
|
||||
return res;
|
||||
else
|
||||
{
|
||||
auto propagate = leaf::preload( info<1>{a}, info<2>{b}, info<3>{} );
|
||||
throw my_error();
|
||||
}
|
||||
} );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user