mirror of
https://github.com/boostorg/system.git
synced 2025-12-26 16:58:12 +01:00
Compare commits
55 Commits
boost-1.78
...
feature/st
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6bff94709 | ||
|
|
ae079810be | ||
|
|
928de55563 | ||
|
|
442138de0a | ||
|
|
de610efd53 | ||
|
|
4b143cdacc | ||
|
|
a1cb578f52 | ||
|
|
96b5073b79 | ||
|
|
2bff5c7071 | ||
|
|
137128176d | ||
|
|
e0e0f56eae | ||
|
|
58d55a67e5 | ||
|
|
34dcb59ee8 | ||
|
|
33f6ecba31 | ||
|
|
23fbfb1ffa | ||
|
|
5366407135 | ||
|
|
72a79b1dcb | ||
|
|
a5c1ab042e | ||
|
|
c2beb75d66 | ||
|
|
54d9f4f38a | ||
|
|
b92be6417a | ||
|
|
245fff8af3 | ||
|
|
c359af3141 | ||
|
|
50cad72fac | ||
|
|
9554d8bbd3 | ||
|
|
cf9d986871 | ||
|
|
a5d68e52e6 | ||
|
|
9c6a09f41d | ||
|
|
b9c26b9fa0 | ||
|
|
2e2430c4fa | ||
|
|
4b1caad727 | ||
|
|
5b96abbaa8 | ||
|
|
2e1c800d82 | ||
|
|
04a79d710f | ||
|
|
5700936367 | ||
|
|
86b031cab9 | ||
|
|
204e65f725 | ||
|
|
01ce081470 | ||
|
|
8c9ceba775 | ||
|
|
91c0dd9a74 | ||
|
|
189fff42fe | ||
|
|
3b4045c149 | ||
|
|
3d877a1fca | ||
|
|
128bdf9db2 | ||
|
|
0e84860604 | ||
|
|
83a306f3bf | ||
|
|
7dce2e3f42 | ||
|
|
292c6825c6 | ||
|
|
0d90d3d883 | ||
|
|
81fec2b171 | ||
|
|
4e15afe5be | ||
|
|
8d1a866920 | ||
|
|
09466c85b4 | ||
|
|
baef8e50ea | ||
|
|
a688d7834a |
32
.drone.star
Normal file
32
.drone.star
Normal file
@@ -0,0 +1,32 @@
|
||||
# Copyright 2020 Rene Rivera
|
||||
# Copyright 2022 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
globalenv={ 'UBSAN_OPTIONS': 'print_stacktrace=1' }
|
||||
|
||||
def main(ctx):
|
||||
return [
|
||||
linux_cxx("GCC 4.4 14.04", "", packages="g++-4.4", buildscript="drone", image="cppalliance/droneubuntu1404:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-4.4', 'CXXSTD': '98,0x'}, globalenv=globalenv),
|
||||
linux_cxx("GCC 4.6 14.04", "", packages="g++-4.6", buildscript="drone", image="cppalliance/droneubuntu1404:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-4.6', 'CXXSTD': '03,0x'}, globalenv=globalenv),
|
||||
linux_cxx("GCC 4.8* 14.04", "", packages="g++-multilib", buildscript="drone", image="cppalliance/droneubuntu1404:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++', 'CXXSTD': '03,11', 'ADDRMD': '32,64'}, globalenv=globalenv),
|
||||
linux_cxx("GCC 4.9 14.04", "", packages="g++-4.9", buildscript="drone", image="cppalliance/droneubuntu1404:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-4.9', 'CXXSTD': '03,11'}, globalenv=globalenv),
|
||||
linux_cxx("GCC 5* 16.04", "", packages="g++-multilib", buildscript="drone", image="cppalliance/droneubuntu1604:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++', 'CXXSTD': '03,11,14', 'ADDRMD': '32,64'}, globalenv=globalenv),
|
||||
linux_cxx("GCC 6 16.04", "", packages="g++-6", buildscript="drone", image="cppalliance/droneubuntu1604:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-6', 'CXXSTD': '03,11'}, globalenv=globalenv),
|
||||
linux_cxx("GCC 7* 18.04", "", packages="g++-multilib", buildscript="drone", image="cppalliance/droneubuntu1804:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++', 'CXXSTD': '03,11,14,1z', 'ADDRMD': '32,64'}, globalenv=globalenv),
|
||||
#linux_cxx("GCC 8 18.04", "", packages="g++-8", buildscript="drone", image="cppalliance/droneubuntu1804:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-8', 'CXXSTD': '03,11,14,1z', 'ADDRMD': '32,64'}, globalenv=globalenv),
|
||||
linux_cxx("GCC 9* 20.04", "", packages="g++-multilib", buildscript="drone", image="cppalliance/droneubuntu2004:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++', 'CXXSTD': '03,11,14,17,2a', 'ADDRMD': '32,64'}, globalenv=globalenv),
|
||||
linux_cxx("GCC 9* 20.04 UBSAN", "", packages="", buildscript="drone", image="cppalliance/droneubuntu2004:1", environment={'UBSAN': 1, 'TOOLSET': 'gcc', 'COMPILER': 'g++', 'CXXSTD': '03,11,14,17,2a', 'LINKFLAGS': '-fuse-ld=gold'}, globalenv=globalenv),
|
||||
linux_cxx("GCC 9* 20.04 ARM64", "", packages="", buildscript="drone", image="cppalliance/droneubuntu2004:multiarch", arch="arm64", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++', 'CXXSTD': '03,11,14,17,2a', 'ADDRMD': '32,64'}, globalenv=globalenv),
|
||||
linux_cxx("Clang 3.4 14.04", "", packages="clang-3.4", buildscript="drone", image="cppalliance/droneubuntu1404:1", environment={'TOOLSET': 'clang', 'COMPILER': '/usr/bin/clang++', 'CXXSTD': '03,11'}, globalenv=globalenv),
|
||||
linux_cxx("Clang 13 20.04 UBSAN", "", packages="clang-13", llvm_os="focal", llvm_ver="13", buildscript="drone", image="cppalliance/droneubuntu2004:1", environment={'UBSAN': '1', 'TOOLSET': 'clang', 'COMPILER': 'clang++-13', 'CXXSTD': '03,11,14,17,20'}, globalenv=globalenv),
|
||||
linux_cxx("Clang 14 20.04 UBSAN", "", packages="clang-14", llvm_os="focal", llvm_ver="14", buildscript="drone", image="cppalliance/droneubuntu2004:1", environment={'UBSAN': '1', 'TOOLSET': 'clang', 'COMPILER': 'clang++-14', 'CXXSTD': '03,11,14,17,20'}, globalenv=globalenv),
|
||||
osx_cxx("Xcode 12.2 UBSAN", "", packages="", buildtype="boost", buildscript="drone", xcode_version="12.2", environment={'UBSAN': '1', 'TOOLSET': 'clang', 'COMPILER': 'clang++', 'CXXSTD': '03,11,14,1z'}, globalenv=globalenv),
|
||||
windows_cxx("msvc-14.0", "", image="cppalliance/dronevs2015", buildscript="drone", environment={"TOOLSET": "msvc-14.0", "CXXSTD": "14,latest"}, globalenv=globalenv),
|
||||
windows_cxx("msvc-14.1", "", image="cppalliance/dronevs2017", buildscript="drone", environment={"TOOLSET": "msvc-14.1", "CXXSTD": "14,17,latest"}, globalenv=globalenv),
|
||||
windows_cxx("msvc-14.2", "", image="cppalliance/dronevs2019", buildscript="drone", environment={"TOOLSET": "msvc-14.2", "CXXSTD": "14,17,20,latest"}, globalenv=globalenv),
|
||||
windows_cxx("msvc-14.3", "", image="cppalliance/dronevs2022:1", buildscript="drone", environment={"TOOLSET": "msvc-14.3", "CXXSTD": "14,17,20,latest"}, globalenv=globalenv)
|
||||
]
|
||||
|
||||
# from https://github.com/boostorg/boost-ci
|
||||
load("@boost_ci//ci/drone/:functions.star", "linux_cxx", "windows_cxx", "osx_cxx")
|
||||
24
.drone/drone.bat
Normal file
24
.drone/drone.bat
Normal file
@@ -0,0 +1,24 @@
|
||||
@ECHO ON
|
||||
|
||||
set DRONE_BUILD_DIR=%CD%
|
||||
|
||||
IF "%DRONE_BRANCH%" == "" (
|
||||
for /F %%i in ("%GITHUB_REF%") do @set DRONE_BRANCH=%%~nxi
|
||||
)
|
||||
|
||||
for /F %%i in ("%DRONE_REPO%") do @set SELF=%%~nxi
|
||||
|
||||
set BOOST_BRANCH=develop
|
||||
if "%DRONE_BRANCH%" == "master" set BOOST_BRANCH=master
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
git submodule update --init tools/boostdep
|
||||
xcopy /s /e /q %DRONE_BUILD_DIR% libs\%SELF%\
|
||||
python tools/boostdep/depinst/depinst.py %SELF%
|
||||
cmd /c bootstrap
|
||||
b2 -d0 headers
|
||||
|
||||
if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
|
||||
if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
|
||||
b2 -j3 libs/%SELF%/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker
|
||||
31
.drone/drone.sh
Executable file
31
.drone/drone.sh
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2020 Rene Rivera, Sam Darwin
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
set -e
|
||||
export TRAVIS_BUILD_DIR=$(pwd)
|
||||
export DRONE_BUILD_DIR=$(pwd)
|
||||
export TRAVIS_BRANCH=$DRONE_BRANCH
|
||||
export VCS_COMMIT_ID=$DRONE_COMMIT
|
||||
export GIT_COMMIT=$DRONE_COMMIT
|
||||
export REPO_NAME=$DRONE_REPO
|
||||
export PATH=~/.local/bin:/usr/local/bin:$PATH
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
git submodule update --init tools/boostdep
|
||||
cp -r $TRAVIS_BUILD_DIR/* libs/system
|
||||
python tools/boostdep/depinst/depinst.py system
|
||||
./bootstrap.sh
|
||||
./b2 -d0 headers
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
|
||||
./b2 -j3 libs/system/test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined define=UBSAN=1 debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}
|
||||
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -144,15 +144,23 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: msvc-14.0
|
||||
cxxstd: "14"
|
||||
addrmd: 32,64
|
||||
os: windows-2019
|
||||
- toolset: msvc-14.1
|
||||
cxxstd: "14,17,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2016
|
||||
- toolset: msvc-14.2
|
||||
cxxstd: "14,17,latest"
|
||||
cxxstd: "14,17,20,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2019
|
||||
- toolset: msvc-14.3
|
||||
cxxstd: "14,17,20,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2022
|
||||
- toolset: clang-win
|
||||
cxxstd: "14,17,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2022
|
||||
@@ -192,7 +200,7 @@ jobs:
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release
|
||||
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker
|
||||
|
||||
posix-cmake-subdir:
|
||||
strategy:
|
||||
|
||||
10
appveyor.yml
10
appveyor.yml
@@ -22,20 +22,12 @@ environment:
|
||||
ADDRMD: 32,64
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: msvc-14.1
|
||||
CXXSTD: 14,17
|
||||
ADDRMD: 32,64
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: clang-win
|
||||
CXXSTD: 14,17
|
||||
ADDRMD: 64
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
TOOLSET: msvc-14.2
|
||||
CXXSTD: 14,17,latest
|
||||
ADDRMD: 32,64
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
TOOLSET: clang-win
|
||||
CXXSTD: 14,17,latest
|
||||
ADDRMD: 64
|
||||
ADDRMD: 32,64
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
ADDPATH: C:\cygwin\bin;
|
||||
TOOLSET: gcc
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
////
|
||||
Copyright 2018-2021 Peter Dimov
|
||||
Copyright 2018-2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
@@ -8,6 +8,13 @@ https://www.boost.org/LICENSE_1_0.txt
|
||||
# Revision History
|
||||
:idprefix:
|
||||
|
||||
## Changes in Boost 1.79
|
||||
|
||||
* Added a `throw_exception_from_error` overload for `std::error_code`.
|
||||
* Added a `boost::source_location` parameter to `throw_exception_from_error`.
|
||||
* `result<T>::value` now automatically supplies `BOOST_CURRENT_LOCATION` to
|
||||
`throw_exception_from_error` via a default argument.
|
||||
|
||||
## Changes in Boost 1.78
|
||||
|
||||
* Added support for source locations to `error_code`.
|
||||
|
||||
@@ -14,6 +14,6 @@ http://www.boost.org/LICENSE_1_0.txt
|
||||
This documentation is
|
||||
|
||||
* Copyright 2003-2017 Beman Dawes
|
||||
* Copyright 2018-2021 Peter Dimov
|
||||
* Copyright 2018-2022 Peter Dimov
|
||||
|
||||
and is distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
////
|
||||
Copyright 2003-2017 Beman Dawes
|
||||
Copyright 2018 Peter Dimov
|
||||
Copyright 2018, 2021 Peter Dimov
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
|
||||
@@ -12,39 +12,67 @@ http://www.boost.org/LICENSE_1_0.txt
|
||||
# Introduction
|
||||
:idprefix: intro_
|
||||
|
||||
Error conditions originating from the operating system or other low-level
|
||||
application program interfaces (API's) are typically reported via an integer
|
||||
representing an error code. When these low-level API calls are wrapped in
|
||||
portable code, such as in a portable library, some users want to deal with the
|
||||
error codes in portable ways. Other users need to get at the system specific
|
||||
error codes, so they can deal with system specific needs. The Boost System
|
||||
library provides simple, light-weight `error_code` objects that encapsulate
|
||||
system-specific error code values, yet also provide access to more abstract
|
||||
and portable error conditions via `error_condition` objects.
|
||||
Errors originating from the operating system or other low-level application
|
||||
program interfaces (APIs) are typically reported via an integer representing
|
||||
an error code, either by returning the code directly from the function (e.g.
|
||||
`pthread_mutex_init`) or by using a side channel such as the `errno`
|
||||
pseudo-variable under POSIX or `GetLastError()` under Windows.
|
||||
|
||||
Because `error_code` objects can represent errors from sources other than the
|
||||
operating system, including user-defined sources, each `error_code` and
|
||||
`error_condition` has an associated `error_category`.
|
||||
However, these integer error values can only be interpreted when their source
|
||||
is known. The value 5 under Windows means `ERROR_ACCESS_DENIED` when returned
|
||||
by `GetLastError()`, but `EIO` when retrieved from `errno`. And conversely,
|
||||
the same error condition "access denied" is represented by the value 5 when
|
||||
returned by `GetLastError()` and 13 (`EACCES`) when retrieved from `errno`.
|
||||
|
||||
An exception class, `system_error`, is provided. Derived from
|
||||
`std::runtime_error`, it captures the underlying `error_code` for the problem
|
||||
causing the exception so that this important information is not lost.
|
||||
This means that in order for code to be able to handle errors from both
|
||||
sources (to retrieve a text message describing the error, or to check whether
|
||||
the error means "access denied"), it needs to know where the integer error
|
||||
value originated. For this to be possible, the integer error value needs to
|
||||
be accompanied by a piece of information identifying the source.
|
||||
|
||||
While exceptions are the preferred {cpp} default error code reporting
|
||||
mechanism, users of libraries dependent on low-level API's often need overloads
|
||||
reporting error conditions via error code arguments and/or return values rather
|
||||
than via throwing exceptions. Otherwise, when errors are not exceptional
|
||||
occurrences and must be dealt with as they arise, programs become littered with
|
||||
try/catch blocks, unreadable, and inefficient. The Boost System library
|
||||
supports both error reporting by exception and by error code.
|
||||
Boost.System provides a framework in which this is possible. Errors are
|
||||
represented by a class `error_code` which contains both the error value and
|
||||
a pointer to their source (called "category"), represented as a class derived
|
||||
from `error_category`.
|
||||
|
||||
In addition to portable errors codes and conditions supported by the
|
||||
`error_code.hpp` header, system-specific headers support the Cygwin, Linux,
|
||||
and Windows platforms. These headers are effectively no-ops if included for
|
||||
platforms other than their intended target.
|
||||
The category provides member functions such as `message`, which returns a text
|
||||
message for a specific error value, and `equivalent`, which can be used to test
|
||||
whether a specific error value correspond to an error condition such as "access
|
||||
denied". `error_code` uses these category-provided functions in the
|
||||
implementation of its `message` and `operator==` member functions.
|
||||
|
||||
Boost.System is part of the {cpp}11 Standard Library.
|
||||
A number of changes, particularly to names, were made by the C++ committee
|
||||
during standardization. The Boost implementation has been tracking those changes.
|
||||
See <<#ref_deprecated_names,Deprecated Names>> for synonyms provided to prevent
|
||||
breakage of existing user code.
|
||||
Boost.System contains two predefined category classes, the generic category
|
||||
(a reference to which is returned by `generic_category()`) and the system
|
||||
category (`system_category()`). The generic category represents the error
|
||||
values of the portable subset of `errno` values defined by the POSIX standard,
|
||||
whereas the system category is OS dependent. Under POSIX, the system category
|
||||
represents the `errno` values returned by the OS APIs (a superset of those in
|
||||
the generic category), whereas under Windows, the system category represents
|
||||
the error values returned by `GetLastError()`.
|
||||
|
||||
The framework is extensible. Users can define their own categories by
|
||||
deriving a class from `error_category` and implementing a function that
|
||||
returns a reference to an instance of it. This capability is useful both for
|
||||
describing library-defined error values, and for adapting existing C API
|
||||
libraries that return integer error values.
|
||||
|
||||
For those who prefer error reporting via exceptions, Boost.System provides
|
||||
a standard exception class `system_error` that stores an `error_code`.
|
||||
|
||||
Boost.System was standardized in {cpp}11 as `<system_error>`. For a while,
|
||||
the two were equivalent, but Boost.System has evolved since then and now
|
||||
contains a number of extensions over its standard sibling:
|
||||
|
||||
* A non-allocating overload of `message`;
|
||||
* Support for nonzero error codes meaning success, via the `failed` member
|
||||
functions;
|
||||
* Support for 64 bit category identifiers, as a solution to the problem
|
||||
that sometimes it's not possible to ensure that only one instance of a
|
||||
category exists in the program;
|
||||
* Support for attaching source locations (file/line/function) to error codes;
|
||||
* A class `result<T>` that can be used to return either a value or an error
|
||||
code from a function;
|
||||
* Various other minor improvements.
|
||||
|
||||
`boost::system::error_code` can be converted to, and constructed from,
|
||||
`std::error_code`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
////
|
||||
Copyright 2003-2017 Beman Dawes
|
||||
Copyright 2018-2021 Peter Dimov
|
||||
Copyright 2018-2022 Peter Dimov
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
|
||||
@@ -175,7 +175,7 @@ namespace errc {
|
||||
too_many_files_open_in_system, //ENFILE
|
||||
too_many_files_open, //EMFILE
|
||||
too_many_links, //EMLINK
|
||||
too_many_synbolic_link_levels, //ELOOP
|
||||
too_many_symbolic_link_levels, //ELOOP
|
||||
value_too_large, //EOVERFLOW
|
||||
wrong_protocol_type //EPROTOTYPE
|
||||
};
|
||||
@@ -1454,7 +1454,11 @@ namespace system {
|
||||
|
||||
// throw_exception_from_error
|
||||
|
||||
BOOST_NORETURN inline void throw_exception_from_error( error_code const & e );
|
||||
BOOST_NORETURN inline void throw_exception_from_error( error_code const & e,
|
||||
boost::source_location const & loc );
|
||||
|
||||
BOOST_NORETURN inline void throw_exception_from_error( std::error_code const & e,
|
||||
boost::source_location const & loc );
|
||||
|
||||
// in_place_*
|
||||
|
||||
@@ -1486,13 +1490,24 @@ If `result<T, E>` is used with other error types, the user is expected to provid
|
||||
an appropriate overload of `throw_exception_from_error` in the namespace of `E`.
|
||||
|
||||
```
|
||||
BOOST_NORETURN inline void throw_exception_from_error( error_code const & e );
|
||||
BOOST_NORETURN inline void throw_exception_from_error( error_code const & e,
|
||||
boost::source_location const & loc );
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects: ::
|
||||
`boost::throw_exception( system_error( e ) )`.
|
||||
`boost::throw_exception( system_error( e ), loc )`.
|
||||
|
||||
```
|
||||
BOOST_NORETURN inline void throw_exception_from_error( std::error_code const & e,
|
||||
boost::source_location const & loc );
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects: ::
|
||||
`boost::throw_exception( std::system_error( e ), loc )`.
|
||||
|
||||
### result<T, E>
|
||||
|
||||
@@ -1528,10 +1543,17 @@ public:
|
||||
|
||||
// checked value access
|
||||
|
||||
constexpr T& value() & ;
|
||||
constexpr T const& value() const& ;
|
||||
constexpr T&& value() && ;
|
||||
constexpr T const&& value() const&& ;
|
||||
constexpr T& value( boost::source_location const & loc =
|
||||
BOOST_CURRENT_LOCATION ) & ;
|
||||
|
||||
constexpr T const& value( boost::source_location const & loc =
|
||||
BOOST_CURRENT_LOCATION ) const& ;
|
||||
|
||||
constexpr T&& value( boost::source_location const & loc =
|
||||
BOOST_CURRENT_LOCATION ) && ;
|
||||
|
||||
constexpr T const&& value( boost::source_location const & loc =
|
||||
BOOST_CURRENT_LOCATION ) const&& ;
|
||||
|
||||
// unchecked value access
|
||||
|
||||
@@ -1653,10 +1675,17 @@ Returns: ::
|
||||
#### Checked Value Access
|
||||
|
||||
```
|
||||
constexpr T& value() & ;
|
||||
constexpr T const& value() const& ;
|
||||
constexpr T&& value() && ;
|
||||
constexpr T const&& value() const&& ;
|
||||
constexpr T& value(
|
||||
boost::source_location const & loc = BOOST_CURRENT_LOCATION ) & ;
|
||||
|
||||
constexpr T const& value(
|
||||
boost::source_location const & loc = BOOST_CURRENT_LOCATION ) const& ;
|
||||
|
||||
constexpr T&& value(
|
||||
boost::source_location const & loc = BOOST_CURRENT_LOCATION ) && ;
|
||||
|
||||
constexpr T const&& value(
|
||||
boost::source_location const & loc = BOOST_CURRENT_LOCATION ) const&& ;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
@@ -1664,7 +1693,7 @@ constexpr T const&& value() const&& ;
|
||||
Effects: ::
|
||||
If `*this` holds a value, returns a reference to it. Otherwise,
|
||||
calls `throw_exception_from_error`, passing it a reference to
|
||||
the held error.
|
||||
the held error, and `loc`.
|
||||
|
||||
#### Unchecked Value Access
|
||||
|
||||
@@ -1799,7 +1828,8 @@ public:
|
||||
|
||||
// checked value access
|
||||
|
||||
constexpr void value() const;
|
||||
constexpr void value( boost::source_location const & loc =
|
||||
BOOST_CURRENT_LOCATION ) const;
|
||||
|
||||
// unchecked value access
|
||||
|
||||
@@ -1912,14 +1942,15 @@ Returns: ::
|
||||
#### Checked Value Access
|
||||
|
||||
```
|
||||
constexpr void value() const;
|
||||
constexpr void value(
|
||||
boost::source_location const & loc = BOOST_CURRENT_LOCATION ) const;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects: ::
|
||||
If `*this` doesn't hold a value, calls `throw_exception_from_error`,
|
||||
passing it a reference to the held error.
|
||||
passing it a reference to the held error, and `loc`.
|
||||
|
||||
#### Unchecked Value Access
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#usage]
|
||||
# Usage Examples
|
||||
# Usage
|
||||
:idprefix: usage_
|
||||
|
||||
All of the following examples assume that these lines
|
||||
All of the following code snippets assume that these lines
|
||||
```
|
||||
#include <boost/system.hpp>
|
||||
namespace sys = boost::system;
|
||||
@@ -198,7 +198,7 @@ It's possible to use system as well, as `EINVAL` is also a system category
|
||||
value under POSIX; however, using the generic category for values belonging
|
||||
to the portable `errno` subset is slightly preferrable.
|
||||
|
||||
Our implementation of `file::write` needs to uindergo a similar treatment.
|
||||
Our implementation of `file::write` needs to undergo a similar treatment.
|
||||
There, however, we'll apply another change. When there's no space left on
|
||||
the disk, `::write` returns a number of bytes written that is lower than
|
||||
what we requested with `size`, but our function signals no error. We'll make
|
||||
@@ -297,7 +297,7 @@ std::size_t file::write( void const * buffer, std::size_t size, sys::error_code&
|
||||
## Attaching a Source Location to Error Codes
|
||||
|
||||
Unlike the standard `<system_error>`, Boost.System allows source locations
|
||||
(file:line:function) to be stored in `error_code`, so that functions handling
|
||||
(file/line/function) to be stored in `error_code`, so that functions handling
|
||||
the error can display or log the source code location where the error occurred.
|
||||
To take advantage of this functionality, our POSIX `file::read` function needs
|
||||
to be augmented as follows:
|
||||
@@ -514,8 +514,8 @@ std::size_t file_copy( file& src, file& dest )
|
||||
That is, we simply call the nonthrowing overload of `file_copy`, and if
|
||||
it signals failure in `ec`, throw a `system_error` exception.
|
||||
|
||||
We use our function name `++__func__++` (`file_copy`) as the prefix, although
|
||||
that's a matter of taste.
|
||||
We use our function name `++__func__++` (`"file_copy"`) as the prefix,
|
||||
although that's a matter of taste.
|
||||
|
||||
Note that typically under this style the overloads taking `error_code& ec`
|
||||
are decorated with `noexcept`, so that it's clear that they don't throw
|
||||
@@ -610,3 +610,805 @@ sys::result<std::size_t> file_copy( file& src, file& dest )
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Testing for Specific Error Conditions
|
||||
|
||||
Let's suppose that we have called a function that signals failure
|
||||
using `error_code`, we have passed it an `error_code` variable `ec`,
|
||||
and now for some reason want to check whether the function has
|
||||
failed with an error code of `EINVAL`, "invalid argument".
|
||||
|
||||
Since `error_code` can be compared for equality, our first instict
|
||||
might be `if( ec == error_code( EINVAL, generic_category() )`.
|
||||
|
||||
This is wrong, and we should never do it.
|
||||
|
||||
First, under POSIX, the function might have returned `EINVAL` from
|
||||
the system category (because the error might have been returned by
|
||||
an OS API, and not by the function itself, as was the case in our
|
||||
`read` and `write` implementations.)
|
||||
|
||||
Since `error_code` comparisons are exact, `EINVAL` from the generic
|
||||
category does not compare equal to `EINVAL` from the system category.
|
||||
|
||||
(And before you start thinking about just comparing `ec.value()` to
|
||||
`EINVAL`, read on.)
|
||||
|
||||
Second, under Windows, the function might have returned `error_code(
|
||||
ERROR_INVALID_PARAMETER, system_category() )`. As we have already
|
||||
mentioned, the integer error values in the system category under
|
||||
Windows are completely unrelated to the integer `errno` values.
|
||||
|
||||
The correct approach is to compare `ec` not to specific error codes,
|
||||
but to `error_condition( EINVAL, generic_category() )`. Error
|
||||
conditions are a platform-independent way to represent the meaning
|
||||
of the concrete error codes. In our case, all error codes, under
|
||||
both POSIX and Windows, that represent `EINVAL` will compare equal
|
||||
to `error_condition( EINVAL, generic_category() )`.
|
||||
|
||||
In short, you should never compare error codes to error codes, and
|
||||
should compare them to error conditions instead. This is the purpose
|
||||
of the `error_condition` class, which is very frequently misunderstood.
|
||||
|
||||
Since
|
||||
|
||||
```
|
||||
if( ec == sys::error_condition( EINVAL, sys::generic_category() ) )
|
||||
{
|
||||
// handle EINVAL
|
||||
}
|
||||
```
|
||||
|
||||
is a bit verbose, Boost.System provides enumerator values for the
|
||||
`errno` values against which an error code can be compared directly.
|
||||
|
||||
These enumerators are defined in <<#ref_errc,`<boost/system/errc.hpp>`>>,
|
||||
and enable the above test to be written
|
||||
|
||||
```
|
||||
if( ec == sys::errc::invalid_argument )
|
||||
{
|
||||
// handle EINVAL
|
||||
}
|
||||
```
|
||||
|
||||
which is what one should generally use for testing for a specific error
|
||||
condition, as a best practice.
|
||||
|
||||
## Adapting Existing Integer Error Values
|
||||
|
||||
Libraries with C (or `extern "C"`) APIs often signal failure by returning
|
||||
a library-specific integer error code (with zero typically being reserved
|
||||
for "no error".) When writing portable {cpp} wrappers, we need to decide
|
||||
how to expose these error codes, and using `error_code` is a good way to
|
||||
do it.
|
||||
|
||||
Because the integer error codes are library specific, and in general match
|
||||
neither `errno` values or system category values, we need to define a
|
||||
library-specific error category.
|
||||
|
||||
### Adapting SQLite Errors
|
||||
|
||||
We'll take SQLite as an example. The general outline of a custom error
|
||||
category is as follows:
|
||||
|
||||
```
|
||||
class sqlite3_category_impl: public sys::error_category
|
||||
{
|
||||
// TODO add whatever's needed here
|
||||
};
|
||||
|
||||
sys::error_category const& sqlite3_category()
|
||||
{
|
||||
static const sqlite3_category_impl instance;
|
||||
return instance;
|
||||
}
|
||||
```
|
||||
|
||||
which can then be used similarly to the predefined generic and system
|
||||
categories:
|
||||
|
||||
```
|
||||
int r = some_sqlite3_function( ... );
|
||||
ec.assign( r, sqlite3_category() );
|
||||
```
|
||||
|
||||
If we try to compile the above category definition as-is, it will complain
|
||||
about our not implementing two pure virtual member functions, `name` and
|
||||
`message`, so at minimum, we'll need to add these. In addition, we'll also
|
||||
implement the non-allocating overload of `message`. It's not pure virtual,
|
||||
but its default implementation calls the `std::string`-returning overload,
|
||||
and that's almost never what one wants. (This default implementation is only
|
||||
provided for backward compatibility, in order to not break existing
|
||||
user-defined categories that were written before this overload was added.)
|
||||
|
||||
So, the minimum we need to implement is this:
|
||||
|
||||
```
|
||||
class sqlite3_category_impl: public sys::error_category
|
||||
{
|
||||
public:
|
||||
|
||||
const char * name() const noexcept;
|
||||
std::string message( int ev ) const;
|
||||
char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
|
||||
};
|
||||
```
|
||||
|
||||
`name` is easy, it just returns the category name:
|
||||
|
||||
```
|
||||
const char * sqlite3_category_impl::name() const noexcept
|
||||
{
|
||||
return "sqlite3";
|
||||
}
|
||||
```
|
||||
|
||||
`message` is used to obtain an error message given an integer error code.
|
||||
SQLite provides the function `sqlite3_errstr` for this, so we don't need
|
||||
to do any work:
|
||||
|
||||
```
|
||||
std::string sqlite3_category_impl::message( int ev ) const
|
||||
{
|
||||
return sqlite3_errstr( ev );
|
||||
}
|
||||
|
||||
char const * sqlite3_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
|
||||
{
|
||||
std::snprintf( buffer, len, "%s", sqlite3_errstr( ev ) );
|
||||
return buffer;
|
||||
}
|
||||
```
|
||||
|
||||
and we're done. `sqlite3_category()` can now be used like the predefined
|
||||
categories, and we can put an SQLite error code `int r` into a Boost.System
|
||||
`error_code ec` by means of `ec.assign( r, sqlite3_category() )`.
|
||||
|
||||
### Adapting ZLib Errors
|
||||
|
||||
Another widely used C library is ZLib, and the portion of `zlib.h` that
|
||||
defines its error codes is shown below:
|
||||
|
||||
```
|
||||
#define Z_OK 0
|
||||
#define Z_STREAM_END 1
|
||||
#define Z_NEED_DICT 2
|
||||
#define Z_ERRNO (-1)
|
||||
#define Z_STREAM_ERROR (-2)
|
||||
#define Z_DATA_ERROR (-3)
|
||||
#define Z_MEM_ERROR (-4)
|
||||
#define Z_BUF_ERROR (-5)
|
||||
#define Z_VERSION_ERROR (-6)
|
||||
/* Return codes for the compression/decompression functions. Negative values
|
||||
* are errors, positive values are used for special but normal events.
|
||||
*/
|
||||
```
|
||||
|
||||
There are three relevant differences with the previous case of SQLite:
|
||||
|
||||
* While for SQLite all non-zero values were errors, as is the typical case,
|
||||
here negative values are errors, but positive values are "special but normal",
|
||||
that is, they represent success, not failure;
|
||||
* ZLib does not provide a function that returns the error message corresponding
|
||||
to a specific error code;
|
||||
* When `Z_ERRNO` is returned, the error code should be retrieved from `errno`.
|
||||
|
||||
Our category implementation will look like this:
|
||||
|
||||
```
|
||||
class zlib_category_impl: public sys::error_category
|
||||
{
|
||||
public:
|
||||
|
||||
const char * name() const noexcept;
|
||||
|
||||
std::string message( int ev ) const;
|
||||
char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
|
||||
|
||||
bool failed( int ev ) const noexcept;
|
||||
};
|
||||
|
||||
sys::error_category const& zlib_category()
|
||||
{
|
||||
static const zlib_category_impl instance;
|
||||
return instance;
|
||||
}
|
||||
```
|
||||
|
||||
As usual, the implementation of `name` is trivial:
|
||||
|
||||
```
|
||||
const char * zlib_category_impl::name() const noexcept
|
||||
{
|
||||
return "zlib";
|
||||
}
|
||||
```
|
||||
|
||||
We'll need to work a bit harder to implement `message` this time, as there's
|
||||
no preexisting function to lean on:
|
||||
|
||||
```
|
||||
char const * zlib_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
|
||||
{
|
||||
switch( ev )
|
||||
{
|
||||
case Z_OK: return "No error";
|
||||
case Z_STREAM_END: return "End of stream";
|
||||
case Z_NEED_DICT: return "A dictionary is needed";
|
||||
case Z_ERRNO: return "OS API error";
|
||||
case Z_STREAM_ERROR: return "Inconsistent stream state or invalid argument";
|
||||
case Z_DATA_ERROR: return "Data error";
|
||||
case Z_MEM_ERROR: return "Out of memory";
|
||||
case Z_BUF_ERROR: return "Insufficient buffer space";
|
||||
case Z_VERSION_ERROR: return "Library version mismatch";
|
||||
}
|
||||
|
||||
std::snprintf( buffer, len, "Unknown zlib error %d", ev );
|
||||
return buffer;
|
||||
}
|
||||
```
|
||||
|
||||
This is a typical implementation of the non-throwing `message` overload. Note
|
||||
that `message` is allowed to return something different from `buffer`, which
|
||||
means that we can return character literals directly, without copying them
|
||||
into the supplied buffer first. This allows our function to return the correct
|
||||
message text even when the buffer is too small.
|
||||
|
||||
The `std::string` overload of `message` is now trivial:
|
||||
|
||||
```
|
||||
std::string zlib_category_impl::message( int ev ) const
|
||||
{
|
||||
char buffer[ 64 ];
|
||||
return this->message( ev, buffer, sizeof( buffer ) );
|
||||
}
|
||||
```
|
||||
|
||||
Finally, we need to implement `failed`, in order to override its default
|
||||
behavior of returning `true` for all nonzero values:
|
||||
|
||||
```
|
||||
bool zlib_category_impl::failed( int ev ) const noexcept
|
||||
{
|
||||
return ev < 0;
|
||||
}
|
||||
```
|
||||
|
||||
This completes the implementation of `zlib_category()` and takes care of the
|
||||
first two bullets above, but we still haven't addressed the third one; namely,
|
||||
that we need to retrieve the error from `errno` in the `Z_ERRNO` case.
|
||||
|
||||
To do that, we'll define a helper function that would be used to assign a ZLib
|
||||
error code to an `error_code`:
|
||||
|
||||
```
|
||||
void assign_zlib_error( sys::error_code & ec, int r )
|
||||
{
|
||||
if( r != Z_ERRNO )
|
||||
{
|
||||
ec.assign( r, zlib_category() );
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign( errno, sys::generic_category() );
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
so that, instead of using `ec.assign( r, zlib_category() )` directly, code
|
||||
would do
|
||||
|
||||
```
|
||||
int r = some_zlib_function( ... );
|
||||
assign_zlib_error( ec, r );
|
||||
```
|
||||
|
||||
We can stop here, as this covers everything we set out to do, but we can take
|
||||
an extra step and enable source locations for our error codes. For that, we'll
|
||||
need to change `assign_zlib_error` to take a `source_location`:
|
||||
|
||||
```
|
||||
void assign_zlib_error( sys::error_code & ec, int r, boost::source_location const* loc )
|
||||
{
|
||||
if( r != Z_ERRNO )
|
||||
{
|
||||
ec.assign( r, zlib_category(), loc );
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign( errno, sys::generic_category(), loc );
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Define a helper macro to avoid the boilerplate of defining the `static
|
||||
constexpr` source location object each time:
|
||||
|
||||
```
|
||||
#define ASSIGN_ZLIB_ERROR(ec, r) { \
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION; \
|
||||
assign_zlib_error( ec, r, &loc ); }
|
||||
```
|
||||
|
||||
And then use the macro instead of the function:
|
||||
|
||||
```
|
||||
int r = some_zlib_function( ... );
|
||||
ASSIGN_ZLIB_ERROR( ec, r );
|
||||
```
|
||||
|
||||
### Supporting Comparisons against Conditions
|
||||
|
||||
We notice that some of the ZLib error codes correspond to portable `errno`
|
||||
conditions. `Z_STREAM_ERROR`, for instance, is returned in cases where
|
||||
POSIX functions would have returned `EINVAL`; `Z_MEM_ERROR` is `ENOMEM`;
|
||||
and `Z_BUF_ERROR`, insufficient space in the output buffer to store the
|
||||
result, roughly corresponds to `ERANGE`, result out of range.
|
||||
|
||||
To encode this relationship, we need to implement either
|
||||
`default_error_condition` or `equivalent` in our category. Since we have
|
||||
a simple one to one mapping, the former will suffice:
|
||||
|
||||
```
|
||||
class zlib_category_impl: public sys::error_category
|
||||
{
|
||||
public:
|
||||
|
||||
const char * name() const noexcept;
|
||||
|
||||
std::string message( int ev ) const;
|
||||
char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
|
||||
|
||||
bool failed( int ev ) const noexcept;
|
||||
|
||||
sys::error_condition default_error_condition( int ev ) const noexcept;
|
||||
};
|
||||
```
|
||||
|
||||
The implementation is straightforward:
|
||||
|
||||
```
|
||||
sys::error_condition zlib_category_impl::default_error_condition( int ev ) const noexcept
|
||||
{
|
||||
switch( ev )
|
||||
{
|
||||
case Z_OK: return sys::error_condition();
|
||||
case Z_STREAM_ERROR: return sys::errc::invalid_argument;
|
||||
case Z_MEM_ERROR: return sys::errc::not_enough_memory;
|
||||
case Z_BUF_ERROR: return sys::errc::result_out_of_range;
|
||||
}
|
||||
|
||||
return sys::error_condition( ev, *this );
|
||||
}
|
||||
```
|
||||
|
||||
Once this is added, we will be able to compare a ZLib `error_code ec` against
|
||||
`errc` enumerators:
|
||||
|
||||
```
|
||||
if( ec == sys::errc::not_enough_memory )
|
||||
{
|
||||
// Z_MEM_ERROR, or ENOMEM
|
||||
}
|
||||
```
|
||||
|
||||
## Defining Library-Specific Error Codes
|
||||
|
||||
Let's suppose that we are writing a library `libmyimg` for reading some
|
||||
hypothetical image format, and that we have defined the following API
|
||||
function for that:
|
||||
|
||||
```
|
||||
namespace libmyimg
|
||||
{
|
||||
|
||||
struct image;
|
||||
|
||||
void load_image( file& f, image& im, sys::error_code& ec );
|
||||
|
||||
} // namespace libmyimg
|
||||
```
|
||||
|
||||
(using our portable `file` class from the preceding examples.)
|
||||
|
||||
Our hypothetical image format is simple, consisting of a fixed header,
|
||||
followed by the image data, so an implementation of `load_image` might
|
||||
have the following structure:
|
||||
|
||||
```
|
||||
namespace libmyimg
|
||||
{
|
||||
|
||||
struct image_header
|
||||
{
|
||||
uint32_t signature;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t bits_per_pixel;
|
||||
uint32_t channels;
|
||||
};
|
||||
|
||||
void load_image_header( file& f, image_header& im, sys::error_code& ec );
|
||||
|
||||
struct image;
|
||||
|
||||
void load_image( file& f, image& im, sys::error_code& ec )
|
||||
{
|
||||
image_header ih = {};
|
||||
load_image_header( f, ih, ec );
|
||||
|
||||
if( ec.failed() ) return;
|
||||
|
||||
if( ih.signature != 0xFF0AD71A )
|
||||
{
|
||||
// return an "invalid signature" error
|
||||
}
|
||||
|
||||
if( ih.width == 0 )
|
||||
{
|
||||
// return an "invalid width" error
|
||||
}
|
||||
|
||||
if( ih.height == 0 )
|
||||
{
|
||||
// return an "invalid height" error
|
||||
}
|
||||
|
||||
if( ih.bits_per_pixel != 8 )
|
||||
{
|
||||
// return an "unsupported bit depth" error
|
||||
}
|
||||
|
||||
if( ih.channels != 1 && ih.channels != 3 && ih.channels != 4 )
|
||||
{
|
||||
// return an "unsupported channel count" error
|
||||
}
|
||||
|
||||
// initialize `im` and read image data
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
} // namespace libmyimg
|
||||
```
|
||||
|
||||
We can see that we need to define five error codes of our own. (Our function
|
||||
can also return other kinds of failures in `ec` -- those will come from
|
||||
`file::read` which `load_image_header` will use to read the header.)
|
||||
|
||||
To define these errors, we'll use a scoped enumeration type. (This example
|
||||
will take advantage of {cpp}11 features.)
|
||||
|
||||
```
|
||||
namespace libmyimg
|
||||
{
|
||||
|
||||
enum class error
|
||||
{
|
||||
success = 0,
|
||||
|
||||
invalid_signature,
|
||||
invalid_width,
|
||||
invalid_height,
|
||||
unsupported_bit_depth,
|
||||
unsupported_channel_count
|
||||
};
|
||||
|
||||
} // namespace libmyimg
|
||||
```
|
||||
|
||||
Boost.System supports being told that an enumeration type represents an error
|
||||
code, which enables implicit conversions between the enumeration type and
|
||||
`error_code`. It's done by specializing the `is_error_code_enum` type trait,
|
||||
which resides in `namespace boost::system` like the rest of the library:
|
||||
|
||||
```
|
||||
namespace boost
|
||||
{
|
||||
namespace system
|
||||
{
|
||||
|
||||
template<> struct is_error_code_enum< ::libmyimg::error >: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace system
|
||||
} // namespace boost
|
||||
```
|
||||
|
||||
Once this is in place, we can now assign values of `libmyimg::error` to
|
||||
`sys::error_code`, which enables the implementation of `load_image` to be
|
||||
written as follows:
|
||||
|
||||
```
|
||||
void load_image( file& f, image& im, sys::error_code& ec )
|
||||
{
|
||||
image_header ih = {};
|
||||
load_image_header( f, ih, ec );
|
||||
|
||||
if( ec.failed() ) return;
|
||||
|
||||
if( ih.signature != 0xFF0AD71A )
|
||||
{
|
||||
ec = error::invalid_signature;
|
||||
return;
|
||||
}
|
||||
|
||||
if( ih.width == 0 )
|
||||
{
|
||||
ec = error::invalid_width;
|
||||
return;
|
||||
}
|
||||
|
||||
if( ih.height == 0 )
|
||||
{
|
||||
ec = error::invalid_height;
|
||||
return;
|
||||
}
|
||||
|
||||
if( ih.bits_per_pixel != 8 )
|
||||
{
|
||||
ec = error::unsupported_bit_depth;
|
||||
return;
|
||||
}
|
||||
|
||||
if( ih.channels != 1 && ih.channels != 3 && ih.channels != 4 )
|
||||
{
|
||||
ec = error::unsupported_channel_count;
|
||||
return;
|
||||
}
|
||||
|
||||
// initialize `image` and read image data
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
This is however not enough; we still need to define the error category
|
||||
for our enumerators, and associate them with it.
|
||||
|
||||
The first step follows our previous two examples very closely:
|
||||
|
||||
```
|
||||
namespace libmyimg
|
||||
{
|
||||
|
||||
class myimg_category_impl: public sys::error_category
|
||||
{
|
||||
public:
|
||||
|
||||
const char * name() const noexcept;
|
||||
|
||||
std::string message( int ev ) const;
|
||||
char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
|
||||
};
|
||||
|
||||
const char * myimg_category_impl::name() const noexcept
|
||||
{
|
||||
return "libmyimg";
|
||||
}
|
||||
|
||||
std::string myimg_category_impl::message( int ev ) const
|
||||
{
|
||||
char buffer[ 64 ];
|
||||
return this->message( ev, buffer, sizeof( buffer ) );
|
||||
}
|
||||
|
||||
char const * myimg_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
|
||||
{
|
||||
switch( static_cast<error>( ev ) )
|
||||
{
|
||||
case error::success: return "No error";
|
||||
case error::invalid_signature: return "Invalid image signature";
|
||||
case error::invalid_width: return "Invalid image width";
|
||||
case error::invalid_height: return "Invalid image height";
|
||||
case error::unsupported_bit_depth: return "Unsupported bit depth";
|
||||
case error::unsupported_channel_count: return "Unsupported number of channels";
|
||||
}
|
||||
|
||||
std::snprintf( buffer, len, "Unknown libmyimg error %d", ev );
|
||||
return buffer;
|
||||
}
|
||||
|
||||
sys::error_category const& myimg_category()
|
||||
{
|
||||
static const myimg_category_impl instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
} // namespace libmyimg
|
||||
```
|
||||
|
||||
The second step involves implementing a function `make_error_code` in
|
||||
the namespace of our enumeration type `error` that takes `error` and
|
||||
returns `boost::system::error_code`:
|
||||
|
||||
```
|
||||
namespace libmyimg
|
||||
{
|
||||
|
||||
sys::error_code make_error_code( error e )
|
||||
{
|
||||
return sys::error_code( static_cast<int>( e ), myimg_category() );
|
||||
}
|
||||
|
||||
} // namespace libmyimg
|
||||
```
|
||||
|
||||
Now `load_image` will compile, and we just need to fill the rest of its
|
||||
implementation with code that uses `file::read` to read the image data.
|
||||
|
||||
There's one additional embellishment we can make. As we know, Boost.System
|
||||
was proposed for, and accepted into, the {cpp}11 standard, and now there's
|
||||
a standard implementation of it in `<system_error>`. We can make our
|
||||
error enumeration type compatible with `std::error_code` as well, by
|
||||
specializing the standard type trait `std::is_error_code_enum`:
|
||||
|
||||
```
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<> struct is_error_code_enum< ::libmyimg::error >: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
```
|
||||
|
||||
This makes our enumerators convertible to `std::error_code`.
|
||||
|
||||
(The reason this works is that `boost::system::error_code` is convertible
|
||||
to `std::error_code`, so the return value of our `make_error_code` overload
|
||||
can be used to initialize a `std::error_code`.)
|
||||
|
||||
## Defining Library-Specific Error Conditions
|
||||
|
||||
All of the `libmyimg::error` error codes we have so far represent the same
|
||||
error condition - invalid or unsupported image format. It might make sense to
|
||||
enable testing for this condition without the need to enumerate all five
|
||||
specific codes. To do this, we can define an error condition enumeration type:
|
||||
|
||||
```
|
||||
namespace libmyimg
|
||||
{
|
||||
|
||||
enum class condition
|
||||
{
|
||||
invalid_format = 1
|
||||
};
|
||||
|
||||
} // namespace libmyimg
|
||||
```
|
||||
|
||||
which we can tag as representing an error condition by specializing
|
||||
`is_error_condition_enum`:
|
||||
|
||||
```
|
||||
namespace boost
|
||||
{
|
||||
namespace system
|
||||
{
|
||||
|
||||
template<> struct is_error_condition_enum< ::libmyimg::condition >: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace system
|
||||
} // namespace boost
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<> struct is_error_condition_enum< ::libmyimg::condition >: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
```
|
||||
|
||||
Similarly to the error code enumeration type, which needed a `make_error_code`
|
||||
overload, this one will need to have a `make_error_condition` overload, and a
|
||||
category.
|
||||
|
||||
It's in principle possible to reuse the category we already defined for our
|
||||
error codes, by making the condition values start from, say, 10000 instead of
|
||||
1. This saves some typing, but a better practice is to use a separate category
|
||||
for the error conditions. So that's what we'll do:
|
||||
|
||||
```
|
||||
namespace libmyimg
|
||||
{
|
||||
|
||||
class myimg_condition_category_impl: public sys::error_category
|
||||
{
|
||||
public:
|
||||
|
||||
const char * name() const noexcept;
|
||||
|
||||
std::string message( int ev ) const;
|
||||
char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
|
||||
};
|
||||
|
||||
const char * myimg_condition_category_impl::name() const noexcept
|
||||
{
|
||||
return "libmyimg_condition";
|
||||
}
|
||||
|
||||
std::string myimg_condition_category_impl::message( int ev ) const
|
||||
{
|
||||
char buffer[ 64 ];
|
||||
return this->message( ev, buffer, sizeof( buffer ) );
|
||||
}
|
||||
|
||||
char const * myimg_condition_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
|
||||
{
|
||||
switch( static_cast<condition>( ev ) )
|
||||
{
|
||||
case condition::invalid_format: return "Invalid or unsupported image format";
|
||||
}
|
||||
|
||||
std::snprintf( buffer, len, "Unknown libmyimg condition %d", ev );
|
||||
return buffer;
|
||||
}
|
||||
|
||||
sys::error_category const& myimg_condition_category()
|
||||
{
|
||||
static const myimg_condition_category_impl instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
sys::error_condition make_error_condition( condition e )
|
||||
{
|
||||
return sys::error_condition( static_cast<int>( e ), myimg_condition_category() );
|
||||
}
|
||||
|
||||
} // namespace libmyimg
|
||||
```
|
||||
|
||||
We have our condition, but it doesn't do anything yet. To enable
|
||||
`libmyimg::condition::invalid_format` to compare equal to our error codes,
|
||||
we need to implement `default_error_condition` in the error code category:
|
||||
|
||||
```
|
||||
namespace libmyimg
|
||||
{
|
||||
|
||||
class myimg_category_impl: public sys::error_category
|
||||
{
|
||||
public:
|
||||
|
||||
const char * name() const noexcept;
|
||||
|
||||
std::string message( int ev ) const;
|
||||
char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
|
||||
|
||||
sys::error_condition default_error_condition( int ev ) const noexcept;
|
||||
};
|
||||
|
||||
sys::error_condition myimg_category_impl::default_error_condition( int ev ) const noexcept
|
||||
{
|
||||
switch( static_cast<error>( ev ) )
|
||||
{
|
||||
case error::success:
|
||||
|
||||
return {};
|
||||
|
||||
case error::invalid_signature:
|
||||
case error::invalid_width:
|
||||
case error::invalid_height:
|
||||
case error::unsupported_bit_depth:
|
||||
case error::unsupported_channel_count:
|
||||
|
||||
return condition::invalid_format;
|
||||
}
|
||||
|
||||
return sys::error_condition( ev, *this );
|
||||
}
|
||||
|
||||
} // namespace libmyimg
|
||||
```
|
||||
|
||||
That's it; now `ec == libmyimg::condition::invalid_format` can be used to test
|
||||
whether `ec` contains one of our error codes corresponding to the "invalid
|
||||
image format" condition.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_SYSTEM_DETAIL_CONFIG_HPP_INCLUDED
|
||||
#define BOOST_SYSTEM_DETAIL_CONFIG_HPP_INCLUDED
|
||||
|
||||
// Copyright 2018 Peter Dimov
|
||||
// Copyright 2018-2022 Peter Dimov
|
||||
//
|
||||
// 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)
|
||||
@@ -62,4 +62,20 @@
|
||||
# define BOOST_SYSTEM_CLANG_6
|
||||
#endif
|
||||
|
||||
//
|
||||
|
||||
#if defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 50000
|
||||
# define BOOST_SYSTEM_AVOID_STD_GENERIC_CATEGORY
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__) || defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER == 1800) || (defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 90000)
|
||||
|
||||
// Under Cygwin (and MinGW!), std::system_category() is POSIX
|
||||
// Under VS2013, std::system_category() isn't quite right
|
||||
// Under libstdc++ before 7.4, before 8.3, before 9.1, default_error_condition
|
||||
// for the system category returns a condition from the system category
|
||||
|
||||
# define BOOST_SYSTEM_AVOID_STD_SYSTEM_CATEGORY
|
||||
#endif
|
||||
|
||||
#endif // BOOST_SYSTEM_DETAIL_CONFIG_HPP_INCLUDED
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <boost/system/detail/error_condition.hpp>
|
||||
#include <boost/system/detail/error_code.hpp>
|
||||
#include <boost/system/detail/snprintf.hpp>
|
||||
#include <boost/system/detail/config.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
@@ -108,7 +109,7 @@ inline error_category::operator std::error_category const & () const
|
||||
if( id_ == detail::generic_category_id )
|
||||
{
|
||||
// This condition must be the same as the one in error_condition.hpp
|
||||
#if defined(BOOST_GCC) && BOOST_GCC < 50000
|
||||
#if defined(BOOST_SYSTEM_AVOID_STD_GENERIC_CATEGORY)
|
||||
|
||||
static const boost::system::detail::std_category generic_instance( this, 0x1F4D3 );
|
||||
return generic_instance;
|
||||
@@ -123,10 +124,7 @@ inline error_category::operator std::error_category const & () const
|
||||
if( id_ == detail::system_category_id )
|
||||
{
|
||||
// This condition must be the same as the one in error_code.hpp
|
||||
#if defined(__CYGWIN__) || defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER == 1800) || (defined(BOOST_GCC) && BOOST_GCC < 50000)
|
||||
|
||||
// Under Cygwin (and MinGW!), std::system_category() is POSIX
|
||||
// Under VS2013, std::system_category() isn't quite right
|
||||
#if defined(BOOST_SYSTEM_AVOID_STD_SYSTEM_CATEGORY)
|
||||
|
||||
static const boost::system::detail::std_category system_instance( this, 0x1F4D7 );
|
||||
return system_instance;
|
||||
|
||||
@@ -83,6 +83,28 @@ private:
|
||||
// >3: pointer to source_location, failed_ in lsb
|
||||
boost::uintptr_t lc_flags_;
|
||||
|
||||
private:
|
||||
|
||||
char const* category_name() const BOOST_NOEXCEPT
|
||||
{
|
||||
// return category().name();
|
||||
|
||||
if( lc_flags_ == 0 )
|
||||
{
|
||||
// must match detail::system_error_category::name()
|
||||
return "system";
|
||||
}
|
||||
else if( lc_flags_ == 1 )
|
||||
{
|
||||
// must match detail::interop_error_category::name()
|
||||
return "std:unknown";
|
||||
}
|
||||
else
|
||||
{
|
||||
return d1_.cat_->name();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// constructors:
|
||||
@@ -188,7 +210,11 @@ public:
|
||||
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
|
||||
|
||||
std::error_code const& ec = *reinterpret_cast<std::error_code const*>( d2_ );
|
||||
return ec.value() + 1000 * static_cast<unsigned>( reinterpret_cast<boost::uintptr_t>( &ec.category() ) % 2097143 ); // 2^21-9, prime
|
||||
|
||||
unsigned cv = static_cast<unsigned>( ec.value() );
|
||||
unsigned ch = static_cast<unsigned>( reinterpret_cast<boost::uintptr_t>( &ec.category() ) % 2097143 ); // 2^21-9, prime
|
||||
|
||||
return static_cast<int>( cv + 1000 * ch );
|
||||
#else
|
||||
|
||||
return -1;
|
||||
@@ -230,7 +256,14 @@ public:
|
||||
|
||||
#endif
|
||||
|
||||
return category().message( value() );
|
||||
if( lc_flags_ == 0 )
|
||||
{
|
||||
return detail::system_error_category_message( value() );
|
||||
}
|
||||
else
|
||||
{
|
||||
return category().message( value() );
|
||||
}
|
||||
}
|
||||
|
||||
char const * message( char * buffer, std::size_t len ) const BOOST_NOEXCEPT
|
||||
@@ -238,23 +271,33 @@ public:
|
||||
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
|
||||
if( lc_flags_ == 1 )
|
||||
{
|
||||
std::error_code const& ec = *reinterpret_cast<std::error_code const*>( d2_ );
|
||||
|
||||
#if !defined(BOOST_NO_EXCEPTIONS)
|
||||
try
|
||||
#endif
|
||||
{
|
||||
std::error_code const& ec = *reinterpret_cast<std::error_code const*>( d2_ );
|
||||
detail::snprintf( buffer, len, "%s", ec.message().c_str() );
|
||||
return buffer;
|
||||
}
|
||||
#if !defined(BOOST_NO_EXCEPTIONS)
|
||||
catch( ... )
|
||||
{
|
||||
detail::snprintf( buffer, len, "No message text available for error std:%s:%d", ec.category().name(), ec.value() );
|
||||
return buffer;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return category().message( value(), buffer, len );
|
||||
if( lc_flags_ == 0 )
|
||||
{
|
||||
return detail::system_error_category_message( value(), buffer, len );
|
||||
}
|
||||
else
|
||||
{
|
||||
return category().message( value(), buffer, len );
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_SYSTEM_CONSTEXPR bool failed() const BOOST_NOEXCEPT
|
||||
@@ -532,7 +575,7 @@ public:
|
||||
else if( lc_flags_ == 0 )
|
||||
{
|
||||
// This condition must be the same as the one in error_category_impl.hpp
|
||||
#if defined(__CYGWIN__) || defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER == 1800) || (defined(BOOST_GCC) && BOOST_GCC < 50000)
|
||||
#if defined(BOOST_SYSTEM_AVOID_STD_SYSTEM_CATEGORY)
|
||||
|
||||
return std::error_code( 0, boost::system::system_category() );
|
||||
|
||||
@@ -594,7 +637,7 @@ public:
|
||||
else
|
||||
#endif
|
||||
{
|
||||
std::string r = category().name();
|
||||
std::string r = category_name();
|
||||
detail::append_int( r, value() );
|
||||
return r;
|
||||
}
|
||||
@@ -604,7 +647,7 @@ public:
|
||||
inline friend std::basic_ostream<Ch, Tr>&
|
||||
operator<< (std::basic_ostream<Ch, Tr>& os, error_code const & ec)
|
||||
{
|
||||
return os << ec.to_string();
|
||||
return os << ec.to_string().c_str();
|
||||
}
|
||||
|
||||
std::string what() const
|
||||
|
||||
@@ -223,7 +223,7 @@ public:
|
||||
operator std::error_condition () const
|
||||
{
|
||||
// This condition must be the same as the one in error_category_impl.hpp
|
||||
#if defined(BOOST_GCC) && BOOST_GCC < 50000
|
||||
#if defined(BOOST_SYSTEM_AVOID_STD_GENERIC_CATEGORY)
|
||||
|
||||
return std::error_condition( value(), category() );
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// See library home page at http://www.boost.org/libs/system
|
||||
|
||||
#include <boost/system/detail/system_category.hpp>
|
||||
#include <boost/system/detail/system_category_message.hpp>
|
||||
#include <boost/system/detail/error_condition.hpp>
|
||||
#include <boost/system/api_config.hpp>
|
||||
|
||||
@@ -22,7 +23,6 @@
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
|
||||
#include <boost/system/detail/system_category_message_win32.hpp>
|
||||
#include <boost/system/detail/system_category_condition_win32.hpp>
|
||||
|
||||
inline boost::system::error_condition boost::system::detail::system_error_category::default_error_condition( int ev ) const BOOST_NOEXCEPT
|
||||
@@ -39,35 +39,23 @@ inline boost::system::error_condition boost::system::detail::system_error_catego
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string boost::system::detail::system_error_category::message( int ev ) const
|
||||
{
|
||||
return system_category_message_win32( ev );
|
||||
}
|
||||
|
||||
inline char const * boost::system::detail::system_error_category::message( int ev, char * buffer, std::size_t len ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return system_category_message_win32( ev, buffer, len );
|
||||
}
|
||||
|
||||
#else // #if defined(BOOST_WINDOWS_API)
|
||||
|
||||
#include <boost/system/detail/generic_category_message.hpp>
|
||||
|
||||
inline boost::system::error_condition boost::system::detail::system_error_category::default_error_condition( int ev ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return error_condition( boost::system::detail::generic_value_tag( ev ) );
|
||||
}
|
||||
|
||||
#endif // #if defined(BOOST_WINDOWS_API)
|
||||
|
||||
inline std::string boost::system::detail::system_error_category::message( int ev ) const
|
||||
{
|
||||
return generic_error_category_message( ev );
|
||||
return system_error_category_message( ev );
|
||||
}
|
||||
|
||||
inline char const * boost::system::detail::system_error_category::message( int ev, char * buffer, std::size_t len ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return generic_error_category_message( ev, buffer, len );
|
||||
return system_error_category_message( ev, buffer, len );
|
||||
}
|
||||
|
||||
#endif // #if defined(BOOST_WINDOWS_API)
|
||||
|
||||
#endif // #ifndef BOOST_SYSTEM_DETAIL_SYSTEM_CATEGORY_IMPL_HPP_INCLUDED
|
||||
|
||||
71
include/boost/system/detail/system_category_message.hpp
Normal file
71
include/boost/system/detail/system_category_message.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef BOOST_SYSTEM_DETAIL_SYSTEM_CATEGORY_MESSAGE_HPP_INCLUDED
|
||||
#define BOOST_SYSTEM_DETAIL_SYSTEM_CATEGORY_MESSAGE_HPP_INCLUDED
|
||||
|
||||
// Implementation of system_error_category_message
|
||||
//
|
||||
// Copyright 2018, 2022 Peter Dimov
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// See library home page at http://www.boost.org/libs/system
|
||||
|
||||
#include <boost/system/api_config.hpp>
|
||||
|
||||
#if !defined(BOOST_POSIX_API) && !defined(BOOST_WINDOWS_API)
|
||||
# error BOOST_POSIX_API or BOOST_WINDOWS_API must be defined
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
|
||||
#include <boost/system/detail/system_category_message_win32.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace system
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
inline std::string system_error_category_message( int ev )
|
||||
{
|
||||
return system_category_message_win32( ev );
|
||||
}
|
||||
|
||||
inline char const * system_error_category_message( int ev, char * buffer, std::size_t len ) BOOST_NOEXCEPT
|
||||
{
|
||||
return system_category_message_win32( ev, buffer, len );
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace system
|
||||
} // namespace boost
|
||||
|
||||
#else // #if defined(BOOST_WINDOWS_API)
|
||||
|
||||
#include <boost/system/detail/generic_category_message.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace system
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
inline std::string system_error_category_message( int ev )
|
||||
{
|
||||
return generic_error_category_message( ev );
|
||||
}
|
||||
|
||||
inline char const * system_error_category_message( int ev, char * buffer, std::size_t len ) BOOST_NOEXCEPT
|
||||
{
|
||||
return generic_error_category_message( ev, buffer, len );
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace system
|
||||
} // namespace boost
|
||||
|
||||
#endif // #if defined(BOOST_WINDOWS_API)
|
||||
|
||||
#endif // #ifndef BOOST_SYSTEM_DETAIL_SYSTEM_CATEGORY_MESSAGE_HPP_INCLUDED
|
||||
@@ -10,13 +10,6 @@
|
||||
#ifndef BOOST_SYSTEM_LINUX_ERROR_HPP
|
||||
#define BOOST_SYSTEM_LINUX_ERROR_HPP
|
||||
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
#if !defined(BOOST_ALLOW_DEPRECATED_HEADERS)
|
||||
BOOST_PRAGMA_MESSAGE("This header is deprecated and is slated for removal."
|
||||
" If you want it retained, please open an issue in github.com/boostorg/system.")
|
||||
#endif
|
||||
|
||||
// This header is effectively empty for compiles on operating systems where
|
||||
// it is not applicable.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BOOST_SYSTEM_RESULT_HPP_INCLUDED
|
||||
#define BOOST_SYSTEM_RESULT_HPP_INCLUDED
|
||||
|
||||
// Copyright 2017, 2021 Peter Dimov.
|
||||
// Copyright 2017, 2021, 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
@@ -11,11 +11,13 @@
|
||||
#include <boost/system/detail/error_category_impl.hpp>
|
||||
#include <boost/variant2/variant.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/assert/source_location.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <iosfwd>
|
||||
#include <system_error>
|
||||
|
||||
//
|
||||
|
||||
@@ -26,11 +28,25 @@ namespace system
|
||||
|
||||
// throw_exception_from_error
|
||||
|
||||
BOOST_NORETURN inline void throw_exception_from_error( error_code const & e )
|
||||
#if defined(__GNUC__) && __GNUC__ >= 7 && __GNUC__ <= 8
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wattributes"
|
||||
#endif
|
||||
|
||||
BOOST_NORETURN BOOST_NOINLINE inline void throw_exception_from_error( error_code const & e, boost::source_location const& loc )
|
||||
{
|
||||
boost::throw_exception( system_error( e ) );
|
||||
boost::throw_exception( system_error( e ), loc );
|
||||
}
|
||||
|
||||
BOOST_NORETURN BOOST_NOINLINE inline void throw_exception_from_error( std::error_code const & e, boost::source_location const& loc )
|
||||
{
|
||||
boost::throw_exception( std::system_error( e ), loc );
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 7 && __GNUC__ <= 8
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
// in_place_*
|
||||
|
||||
using in_place_value_t = variant2::in_place_index_t<0>;
|
||||
@@ -39,6 +55,15 @@ constexpr in_place_value_t in_place_value{};
|
||||
using in_place_error_t = variant2::in_place_index_t<1>;
|
||||
constexpr in_place_error_t in_place_error{};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class T> using remove_cvref = typename std::remove_cv< typename std::remove_reference<T>::type >::type;
|
||||
|
||||
template<class... T> using is_errc_t = std::is_same<mp11::mp_list<remove_cvref<T>...>, mp11::mp_list<errc::errc_t>>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// result
|
||||
|
||||
template<class T, class E = error_code> class result
|
||||
@@ -65,6 +90,7 @@ public:
|
||||
// implicit, value
|
||||
template<class A = T, typename std::enable_if<
|
||||
std::is_convertible<A, T>::value &&
|
||||
!(detail::is_errc_t<A>::value && std::is_arithmetic<T>::value) &&
|
||||
!std::is_constructible<E, A>::value, int>::type = 0>
|
||||
constexpr result( A&& a )
|
||||
noexcept( std::is_nothrow_constructible<T, A>::value )
|
||||
@@ -85,6 +111,7 @@ public:
|
||||
// explicit, value
|
||||
template<class... A, class En = typename std::enable_if<
|
||||
std::is_constructible<T, A...>::value &&
|
||||
!(detail::is_errc_t<A...>::value && std::is_arithmetic<T>::value) &&
|
||||
!std::is_constructible<E, A...>::value
|
||||
>::type>
|
||||
explicit constexpr result( A&&... a )
|
||||
@@ -144,7 +171,7 @@ public:
|
||||
// checked value access
|
||||
#if defined( BOOST_NO_CXX11_REF_QUALIFIERS )
|
||||
|
||||
BOOST_CXX14_CONSTEXPR T value() const
|
||||
BOOST_CXX14_CONSTEXPR T value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const
|
||||
{
|
||||
if( has_value() )
|
||||
{
|
||||
@@ -152,13 +179,13 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_exception_from_error( variant2::unsafe_get<1>( v_ ) );
|
||||
throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc );
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
BOOST_CXX14_CONSTEXPR T& value() &
|
||||
BOOST_CXX14_CONSTEXPR T& value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) &
|
||||
{
|
||||
if( has_value() )
|
||||
{
|
||||
@@ -166,11 +193,11 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_exception_from_error( variant2::unsafe_get<1>( v_ ) );
|
||||
throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc );
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR T const& value() const&
|
||||
BOOST_CXX14_CONSTEXPR T const& value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const&
|
||||
{
|
||||
if( has_value() )
|
||||
{
|
||||
@@ -178,24 +205,24 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_exception_from_error( variant2::unsafe_get<1>( v_ ) );
|
||||
throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc );
|
||||
}
|
||||
}
|
||||
|
||||
template<class U = T>
|
||||
BOOST_CXX14_CONSTEXPR
|
||||
typename std::enable_if<std::is_move_constructible<U>::value, T>::type
|
||||
value() &&
|
||||
value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) &&
|
||||
{
|
||||
return std::move( value() );
|
||||
return std::move( value( loc ) );
|
||||
}
|
||||
|
||||
template<class U = T>
|
||||
BOOST_CXX14_CONSTEXPR
|
||||
typename std::enable_if<!std::is_move_constructible<U>::value, T&&>::type
|
||||
value() &&
|
||||
value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) &&
|
||||
{
|
||||
return std::move( value() );
|
||||
return std::move( value( loc ) );
|
||||
}
|
||||
|
||||
template<class U = T>
|
||||
@@ -206,9 +233,9 @@ public:
|
||||
template<class U = T>
|
||||
BOOST_CXX14_CONSTEXPR
|
||||
typename std::enable_if<!std::is_move_constructible<U>::value, T const&&>::type
|
||||
value() const &&
|
||||
value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const &&
|
||||
{
|
||||
return std::move( value() );
|
||||
return std::move( value( loc ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -432,14 +459,14 @@ public:
|
||||
|
||||
// checked value access
|
||||
|
||||
BOOST_CXX14_CONSTEXPR void value() const
|
||||
BOOST_CXX14_CONSTEXPR void value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const
|
||||
{
|
||||
if( has_value() )
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_exception_from_error( variant2::unsafe_get<1>( v_ ) );
|
||||
throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,46 +23,25 @@ private:
|
||||
|
||||
error_code code_;
|
||||
|
||||
private:
|
||||
|
||||
static std::string build_message( char const * prefix, error_code const & ec )
|
||||
{
|
||||
std::string r;
|
||||
|
||||
if( prefix )
|
||||
{
|
||||
r += prefix;
|
||||
r += ": ";
|
||||
}
|
||||
|
||||
r += ec.what();
|
||||
return r;
|
||||
}
|
||||
|
||||
static std::string build_message( char const * prefix, int ev, error_category const & cat )
|
||||
{
|
||||
return build_message( prefix, error_code( ev, cat ) );
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
explicit system_error( error_code const & ec )
|
||||
: std::runtime_error( build_message( 0, ec ) ), code_( ec ) {}
|
||||
explicit system_error( error_code const & ec ):
|
||||
std::runtime_error( ec.what() ), code_( ec ) {}
|
||||
|
||||
system_error( error_code const & ec, std::string const & prefix )
|
||||
: std::runtime_error( build_message( prefix.c_str(), ec ) ), code_( ec ) {}
|
||||
system_error( error_code const & ec, std::string const & prefix ):
|
||||
std::runtime_error( prefix + ": " + ec.what() ), code_( ec ) {}
|
||||
|
||||
system_error( error_code const & ec, char const * prefix )
|
||||
: std::runtime_error( build_message( prefix, ec ) ), code_( ec ) {}
|
||||
system_error( error_code const & ec, char const * prefix ):
|
||||
std::runtime_error( std::string( prefix ) + ": " + ec.what() ), code_( ec ) {}
|
||||
|
||||
system_error( int ev, error_category const & ecat )
|
||||
: std::runtime_error( build_message( 0, ev, ecat ) ), code_( ev, ecat ) {}
|
||||
system_error( int ev, error_category const & ecat ):
|
||||
std::runtime_error( error_code( ev, ecat ).what() ), code_( ev, ecat ) {}
|
||||
|
||||
system_error( int ev, error_category const & ecat, std::string const & prefix )
|
||||
: std::runtime_error( build_message( prefix.c_str(), ev, ecat ) ), code_( ev, ecat ) {}
|
||||
system_error( int ev, error_category const & ecat, std::string const & prefix ):
|
||||
std::runtime_error( prefix + ": " + error_code( ev, ecat ).what() ), code_( ev, ecat ) {}
|
||||
|
||||
system_error( int ev, error_category const & ecat, char const * prefix )
|
||||
: std::runtime_error( build_message( prefix, ev, ecat ) ), code_( ev, ecat ) {}
|
||||
system_error( int ev, error_category const & ecat, char const * prefix ):
|
||||
std::runtime_error( std::string( prefix ) + ": " + error_code( ev, ecat ).what() ), code_( ev, ecat ) {}
|
||||
|
||||
error_code code() const BOOST_NOEXCEPT
|
||||
{
|
||||
|
||||
@@ -4,9 +4,14 @@
|
||||
"authors": [
|
||||
"Beman Dawes"
|
||||
],
|
||||
"description": "Operating system support, including the diagnostics support that will be part of the C++0x standard library.",
|
||||
"maintainers": [
|
||||
"Peter Dimov <pdimov -at- gmail.com>"
|
||||
],
|
||||
"description": "Extensible error reporting.",
|
||||
"category": [
|
||||
"System"
|
||||
"System",
|
||||
"Error-handling",
|
||||
"Programming"
|
||||
],
|
||||
"cxxstd": "03"
|
||||
}
|
||||
|
||||
@@ -112,6 +112,10 @@ boost_test(TYPE run SOURCES system_error_test3.cpp)
|
||||
|
||||
boost_test(TYPE run SOURCES std_interop_test11.cpp)
|
||||
|
||||
boost_test(TYPE run SOURCES ec_wstream_test.cpp)
|
||||
|
||||
boost_test(TYPE run SOURCES std_interop_test12.cpp)
|
||||
|
||||
# result
|
||||
|
||||
set(BOOST_TEST_COMPILE_FEATURES cxx_std_11)
|
||||
|
||||
@@ -20,6 +20,8 @@ project
|
||||
<toolset>msvc:<warnings-as-errors>on
|
||||
<toolset>gcc:<warnings-as-errors>on
|
||||
<toolset>clang:<warnings-as-errors>on
|
||||
|
||||
<toolset>gcc-4.4:<cxxflags>-Wno-sign-compare
|
||||
;
|
||||
|
||||
rule system-run ( sources + )
|
||||
@@ -134,6 +136,10 @@ run system_error_test3.cpp ;
|
||||
|
||||
run std_interop_test11.cpp ;
|
||||
|
||||
run ec_wstream_test.cpp ;
|
||||
|
||||
run std_interop_test12.cpp ;
|
||||
|
||||
# result
|
||||
|
||||
import ../../config/checks/config : requires ;
|
||||
@@ -154,3 +160,4 @@ run result_eq.cpp : : : $(CPP11) ;
|
||||
run result_range_for.cpp : : : $(CPP11) ;
|
||||
run result_value_construct2.cpp : : : $(CPP11) ;
|
||||
run result_error_construct2.cpp : : : $(CPP11) ;
|
||||
run result_errc_construct.cpp : : : $(CPP11) ;
|
||||
|
||||
21
test/ec_wstream_test.cpp
Normal file
21
test/ec_wstream_test.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <sstream>
|
||||
|
||||
namespace sys = boost::system;
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
std::wostringstream os;
|
||||
os << sys::error_code();
|
||||
|
||||
BOOST_TEST( os.str() == L"system:0" );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
23
test/result_errc_construct.cpp
Normal file
23
test/result_errc_construct.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2021 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/system/result.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
using namespace boost::system;
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_TEST_TRAIT_FALSE((std::is_convertible<errc::errc_t, result<int>>));
|
||||
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int>, errc::errc_t>));
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE((std::is_convertible<errc::errc_t, result<double>>));
|
||||
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<double>, errc::errc_t>));
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE((std::is_convertible<errc::errc_t, result<bool>>));
|
||||
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<bool>, errc::errc_t>));
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
// Copyright 2017, 2021 Peter Dimov.
|
||||
// Copyright 2017, 2021, 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/system/result.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <system_error>
|
||||
|
||||
using namespace boost::system;
|
||||
|
||||
@@ -26,7 +27,7 @@ struct E
|
||||
{
|
||||
};
|
||||
|
||||
BOOST_NORETURN void throw_exception_from_error( Y const & )
|
||||
BOOST_NORETURN void throw_exception_from_error( Y const &, boost::source_location const& )
|
||||
{
|
||||
throw E();
|
||||
}
|
||||
@@ -165,6 +166,22 @@ int main()
|
||||
BOOST_TEST_EQ( result<int>( ec ).operator->(), static_cast<int*>(0) );
|
||||
}
|
||||
|
||||
{
|
||||
auto ec = make_error_code( std::errc::invalid_argument );
|
||||
|
||||
result<int, std::error_code> const r( ec );
|
||||
|
||||
BOOST_TEST( !r.has_value() );
|
||||
BOOST_TEST( r.has_error() );
|
||||
|
||||
BOOST_TEST_NOT( r );
|
||||
BOOST_TEST( !r );
|
||||
|
||||
BOOST_TEST_THROWS( r.value(), std::system_error );
|
||||
|
||||
BOOST_TEST_EQ( r.operator->(), static_cast<int*>(0) );
|
||||
}
|
||||
|
||||
{
|
||||
result<X> r( 1 );
|
||||
|
||||
@@ -341,5 +358,21 @@ int main()
|
||||
BOOST_TEST_EQ( result<void>( ec ).operator->(), static_cast<void*>(0) );
|
||||
}
|
||||
|
||||
{
|
||||
auto ec = make_error_code( std::errc::invalid_argument );
|
||||
|
||||
result<void, std::error_code> const r( ec );
|
||||
|
||||
BOOST_TEST( !r.has_value() );
|
||||
BOOST_TEST( r.has_error() );
|
||||
|
||||
BOOST_TEST_NOT( r );
|
||||
BOOST_TEST( !r );
|
||||
|
||||
BOOST_TEST_THROWS( r.value(), std::system_error );
|
||||
|
||||
BOOST_TEST_EQ( r.operator->(), static_cast<void*>(0) );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
127
test/std_interop_test12.cpp
Normal file
127
test/std_interop_test12.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright 2021, 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/system/error_category.hpp>
|
||||
#include <boost/system/errc.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <cerrno>
|
||||
|
||||
#if !defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "BOOST_SYSTEM_HAS_SYSTEM_ERROR not defined, test will be skipped" )
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
#include <system_error>
|
||||
|
||||
enum my_errc
|
||||
{
|
||||
my_enoent = ENOENT
|
||||
};
|
||||
|
||||
class my_category: public boost::system::error_category
|
||||
{
|
||||
public:
|
||||
|
||||
char const* name() const BOOST_NOEXCEPT
|
||||
{
|
||||
return "mycat";
|
||||
}
|
||||
|
||||
boost::system::error_condition default_error_condition( int ev ) const BOOST_NOEXCEPT
|
||||
{
|
||||
switch( ev )
|
||||
{
|
||||
case my_enoent:
|
||||
|
||||
return boost::system::error_condition( ENOENT, boost::system::generic_category() );
|
||||
|
||||
default:
|
||||
|
||||
return boost::system::error_condition( ev, *this );
|
||||
}
|
||||
}
|
||||
|
||||
std::string message( int ev ) const
|
||||
{
|
||||
switch( ev )
|
||||
{
|
||||
case my_enoent:
|
||||
|
||||
return "No such entity";
|
||||
|
||||
default:
|
||||
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(BOOST_GCC) && BOOST_GCC < 70000
|
||||
|
||||
// g++ 6 and earlier do not allow specializations outside the namespace
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace system
|
||||
{
|
||||
|
||||
template<> struct is_error_code_enum<my_errc>: std::true_type {};
|
||||
|
||||
} // namespace system
|
||||
} // namespace boost
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<> struct is_error_code_enum<my_errc>: std::true_type {};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#else
|
||||
|
||||
template<> struct boost::system::is_error_code_enum<my_errc>: std::true_type {};
|
||||
template<> struct std::is_error_code_enum<my_errc>: std::true_type {};
|
||||
|
||||
#endif
|
||||
|
||||
boost::system::error_code make_error_code( my_errc e )
|
||||
{
|
||||
// If `cat` is declared constexpr or const, msvc-14.1 and
|
||||
// msvc-14.2 before 19.29 put it in read-only memory,
|
||||
// despite the `ps_` member being mutable. So it crashes.
|
||||
|
||||
static /*BOOST_SYSTEM_CONSTEXPR*/ my_category cat;
|
||||
return boost::system::error_code( e, cat );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
boost::system::error_code e1 = my_enoent;
|
||||
|
||||
BOOST_TEST( e1 == my_enoent );
|
||||
BOOST_TEST_NOT( e1 != my_enoent );
|
||||
|
||||
BOOST_TEST( e1 == boost::system::errc::no_such_file_or_directory );
|
||||
BOOST_TEST( e1 == std::errc::no_such_file_or_directory );
|
||||
}
|
||||
|
||||
{
|
||||
std::error_code e1 = my_enoent;
|
||||
|
||||
BOOST_TEST( e1 == my_enoent );
|
||||
BOOST_TEST_NOT( e1 != my_enoent );
|
||||
|
||||
BOOST_TEST( e1 == std::errc::no_such_file_or_directory );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021 Peter Dimov
|
||||
// Copyright 2021, 2022 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
@@ -14,22 +14,36 @@ int main()
|
||||
sys::error_code ec( 5, sys::generic_category() );
|
||||
sys::system_error x1( ec );
|
||||
|
||||
BOOST_TEST_EQ( std::string( x1.what() ), ec.what() );
|
||||
BOOST_TEST_EQ( std::string( x1.what() ), ec.what() );
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
sys::error_code ec( 5, sys::system_category(), &loc );
|
||||
sys::error_code ec( 5, sys::generic_category() );
|
||||
sys::system_error x1( ec, "prefix" );
|
||||
|
||||
BOOST_TEST_EQ( std::string( x1.what() ), "prefix: " + ec.what() );
|
||||
}
|
||||
|
||||
{
|
||||
sys::system_error x1( 5, sys::generic_category() );
|
||||
sys::error_code ec( 5, sys::generic_category() );
|
||||
sys::system_error x1( ec, std::string( "prefix2" ) );
|
||||
|
||||
BOOST_TEST_EQ( std::string( x1.what() ), sys::error_code( 5, sys::generic_category() ).what() );
|
||||
BOOST_TEST_EQ( std::string( x1.what() ), "prefix2: " + ec.what() );
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
sys::error_code ec( 5, sys::generic_category(), &loc );
|
||||
sys::system_error x1( ec, "prefix3" );
|
||||
|
||||
BOOST_TEST_EQ( std::string( x1.what() ), "prefix3: " + ec.what() );
|
||||
}
|
||||
|
||||
{
|
||||
sys::system_error x1( 5, sys::system_category() );
|
||||
|
||||
BOOST_TEST_EQ( std::string( x1.what() ), sys::error_code( 5, sys::system_category() ).what() );
|
||||
}
|
||||
|
||||
{
|
||||
@@ -38,5 +52,11 @@ int main()
|
||||
BOOST_TEST_EQ( std::string( x1.what() ), "prefix: " + sys::error_code( 5, sys::system_category() ).what() );
|
||||
}
|
||||
|
||||
{
|
||||
sys::system_error x1( 5, sys::system_category(), std::string( "prefix2" ) );
|
||||
|
||||
BOOST_TEST_EQ( std::string( x1.what() ), "prefix2: " + sys::error_code( 5, sys::system_category() ).what() );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user