2
0
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:
Emil Dotchevski
2019-01-15 18:11:45 -08:00
146 changed files with 9772 additions and 8207 deletions

View File

@@ -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
View File

@@ -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
View File

@@ -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"
}
}
]

File diff suppressed because it is too large Load Diff

View 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;
} }
----

View 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;
} }
----

View File

@@ -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>>

View File

@@ -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 );
} }
----

View File

@@ -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>>

View File

@@ -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>>

View File

@@ -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>>

View File

@@ -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>>

View 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;
} }
----

View File

@@ -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
View 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>>

View File

@@ -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
View 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
View 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>>

View File

@@ -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;
} );
}
}

View File

@@ -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;
} );
}
}

View 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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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());
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
} );
}

View File

@@ -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;
}

View File

@@ -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

View 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

View 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

View File

@@ -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

View 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

View File

@@ -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
//

View 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

View 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

View File

@@ -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
} }

View File

@@ -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

View 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

View File

@@ -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
} }

View File

@@ -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
} }

View 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

View 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

View File

@@ -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

View File

@@ -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) _;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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)... );
}

View 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

View File

@@ -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] )

View File

@@ -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 ;

View File

@@ -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>

View 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; }

View 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; }

View File

@@ -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>

View File

@@ -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; }

View File

@@ -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>

View File

@@ -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; }

View File

@@ -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; }

View 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; }

View File

@@ -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; }

View 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; }

View File

@@ -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>

View File

@@ -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
View 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
View 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; }

View File

@@ -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();
}

View 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();
}

View 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();
}

View 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();
}

View 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();
}

View 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();
}

View 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
View 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();
}

View 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();
}

View 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();
}

View 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();
}

View 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();
}

View 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();
}

View 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();
}

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View 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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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{ } );
}

View File

@@ -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();
}

View File

@@ -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