mirror of
https://github.com/boostorg/system.git
synced 2025-12-26 00:38:08 +01:00
Compare commits
37 Commits
feature/er
...
boost-1.78
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5034f11a3a | ||
|
|
f78b036665 | ||
|
|
9b0d735040 | ||
|
|
bfebaf53d7 | ||
|
|
8338e80295 | ||
|
|
2b23aaab16 | ||
|
|
7933300b6f | ||
|
|
4ec1e54099 | ||
|
|
5217e58a7d | ||
|
|
ce37e23491 | ||
|
|
420a262733 | ||
|
|
e15bccc09b | ||
|
|
bb775c071a | ||
|
|
01676ae42f | ||
|
|
eefcc5dcf6 | ||
|
|
f2d3a0decf | ||
|
|
0ccf08509b | ||
|
|
7a72aee355 | ||
|
|
a8df99e927 | ||
|
|
85c7d92302 | ||
|
|
4c201d26b2 | ||
|
|
1659dfbeba | ||
|
|
d2b8b54356 | ||
|
|
41f7ea49cb | ||
|
|
0b22dc595f | ||
|
|
aab58b0d5b | ||
|
|
ad66ea43a3 | ||
|
|
811564f186 | ||
|
|
a7e4879e55 | ||
|
|
9b11d864be | ||
|
|
cc6a61b6c5 | ||
|
|
9151633c95 | ||
|
|
5e0db22075 | ||
|
|
60a20eeeb9 | ||
|
|
1c8128e4cb | ||
|
|
1879ba6d35 | ||
|
|
b1dec88674 |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -152,6 +152,10 @@ jobs:
|
||||
cxxstd: "14,17,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2019
|
||||
- toolset: msvc-14.3
|
||||
cxxstd: "14,17,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2022
|
||||
- toolset: gcc
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
addrmd: 64
|
||||
|
||||
@@ -13,10 +13,13 @@ Beman Dawes, Christopher Kohlhoff, Peter Dimov
|
||||
:toclevels: 4
|
||||
:idprefix:
|
||||
:docinfo: private-footer
|
||||
:source-highlighter: rouge
|
||||
:source-language: c++
|
||||
|
||||
:leveloffset: +1
|
||||
|
||||
include::system/introduction.adoc[]
|
||||
include::system/usage.adoc[]
|
||||
include::system/changes.adoc[]
|
||||
include::system/rationale.adoc[]
|
||||
include::system/reference.adoc[]
|
||||
|
||||
@@ -11,7 +11,7 @@ https://www.boost.org/LICENSE_1_0.txt
|
||||
## Changes in Boost 1.78
|
||||
|
||||
* Added support for source locations to `error_code`.
|
||||
* Added `error_code::to_string`, `error_condition::to_string`.
|
||||
* Added `error_code::to_string`, `error_condition::to_string`, `error_code::what`.
|
||||
* `system_error::what()` now contains the source location, if present.
|
||||
* Added `result<T, E = error_code>`, a class holding either a value or an
|
||||
error, defined in `<boost/system/result.hpp>`.
|
||||
|
||||
@@ -571,9 +571,13 @@ public:
|
||||
error_code( int val, const error_category & cat,
|
||||
boost::source_location const * loc ) noexcept;
|
||||
|
||||
template <class ErrorCodeEnum>
|
||||
template<class ErrorCodeEnum>
|
||||
constexpr error_code( ErrorCodeEnum e ) noexcept;
|
||||
|
||||
template<class ErrorCodeEnum>
|
||||
error_code( ErrorCodeEnum e, boost::source_location const * loc )
|
||||
noexcept;
|
||||
|
||||
error_code( std::error_code const& ec ) noexcept;
|
||||
|
||||
// modifiers
|
||||
@@ -583,9 +587,13 @@ public:
|
||||
void assign( int val, const error_category & cat,
|
||||
boost::source_location const * loc ) noexcept;
|
||||
|
||||
template<typename ErrorCodeEnum>
|
||||
template<class ErrorCodeEnum>
|
||||
constexpr error_code & operator=( ErrorCodeEnum e ) noexcept;
|
||||
|
||||
template<class ErrorCodeEnum>
|
||||
void assign( ErrorCodeEnum e,
|
||||
boost::source_location const * loc ) noexcept;
|
||||
|
||||
constexpr void clear() noexcept;
|
||||
|
||||
// observers
|
||||
@@ -657,9 +665,13 @@ public:
|
||||
|
||||
// stream insertion
|
||||
|
||||
template <class charT, class traits>
|
||||
template<class charT, class traits>
|
||||
friend std::basic_ostream<charT, traits>&
|
||||
operator<<( basic_ostream<charT, traits>& os, const error_code & ec );
|
||||
|
||||
// what
|
||||
|
||||
std::string what() const;
|
||||
};
|
||||
|
||||
// non-member functions
|
||||
@@ -699,7 +711,7 @@ Requires: :: `loc` points to a valid `boost::source_location` object with static
|
||||
Ensures: :: `value() == val`; `category() == cat`; `has_location()`; `&location() == loc`.
|
||||
|
||||
```
|
||||
template <class ErrorCodeEnum>
|
||||
template<class ErrorCodeEnum>
|
||||
constexpr error_code( ErrorCodeEnum e ) noexcept;
|
||||
```
|
||||
[none]
|
||||
@@ -708,6 +720,19 @@ template <class ErrorCodeEnum>
|
||||
Ensures: :: `*this == make_error_code( e )`.
|
||||
Remarks: :: This constructor is only enabled when `is_error_code_enum<ErrorCodeEnum>::value` is `true`.
|
||||
|
||||
```
|
||||
template<class ErrorCodeEnum>
|
||||
error_code( ErrorCodeEnum e, boost::source_location const * loc ) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Requires: :: `loc` points to a valid `boost::source_location` object with static storage duration.
|
||||
Ensures: :: `*this == make_error_code( e )`.
|
||||
Remarks: :: This constructor is only enabled when `is_error_code_enum<ErrorCodeEnum>::value` is `true`.
|
||||
When `make_error_code( e )` is not a default-constructed `error_code` and doesn't wrap a
|
||||
`std::error_code`, `has_location()` is `true` and `&location()` is `loc`.
|
||||
|
||||
```
|
||||
error_code( std::error_code const & ec ) noexcept;
|
||||
```
|
||||
@@ -737,7 +762,7 @@ void assign( int val, const error_category & cat,
|
||||
Effects: :: `*this = error_code( val, cat, loc )`.
|
||||
|
||||
```
|
||||
template<typename ErrorCodeEnum>
|
||||
template<class ErrorCodeEnum>
|
||||
constexpr error_code & operator=( ErrorCodeEnum e ) noexcept;
|
||||
```
|
||||
[none]
|
||||
@@ -746,6 +771,18 @@ template<typename ErrorCodeEnum>
|
||||
Ensures: :: `*this == make_error_code( e )`.
|
||||
Remarks: :: This operator is only enabled when `is_error_code_enum<ErrorCodeEnum>::value` is `true`.
|
||||
|
||||
```
|
||||
template<class ErrorCodeEnum>
|
||||
void assign( ErrorCodeEnum e,
|
||||
boost::source_location const * loc ) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Requires: :: `loc` points to a valid `boost::source_location` object with static storage duration.
|
||||
Effects: :: `*this = error_code( e, loc )`.
|
||||
Remarks: :: This function is only enabled when `is_error_code_enum<ErrorCodeEnum>::value` is `true`.
|
||||
|
||||
```
|
||||
constexpr void clear() noexcept;
|
||||
```
|
||||
@@ -1021,6 +1058,18 @@ template <class charT, class traits>
|
||||
Effects: :: `os << to_string()`.
|
||||
Returns: :: `os`.
|
||||
|
||||
#### what
|
||||
|
||||
```
|
||||
std::string what() const;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns: :: A string representation of `*this`, suitable for logging and
|
||||
diagnostic output. Typically incorporates `message()`, `to_string()`, and
|
||||
`location().to_string()` (if available.)
|
||||
|
||||
#### Nonmembers
|
||||
|
||||
```
|
||||
|
||||
612
doc/system/usage.adoc
Normal file
612
doc/system/usage.adoc
Normal file
@@ -0,0 +1,612 @@
|
||||
////
|
||||
Copyright 2021 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#usage]
|
||||
# Usage Examples
|
||||
:idprefix: usage_
|
||||
|
||||
All of the following examples assume that these lines
|
||||
```
|
||||
#include <boost/system.hpp>
|
||||
namespace sys = boost::system;
|
||||
```
|
||||
are in effect.
|
||||
|
||||
## Returning Errors from OS APIs under POSIX
|
||||
|
||||
Let's suppose that we're implementing a portable `file` wrapper
|
||||
over the OS file APIs. Its general outline is shown below:
|
||||
|
||||
```
|
||||
class file
|
||||
{
|
||||
private:
|
||||
|
||||
int fd_;
|
||||
|
||||
public:
|
||||
|
||||
// ...
|
||||
|
||||
std::size_t read( void * buffer, std::size_t size, sys::error_code& ec );
|
||||
std::size_t write( void const * buffer, std::size_t size, sys::error_code& ec );
|
||||
};
|
||||
```
|
||||
|
||||
Since we're implementing the POSIX version of `file`, its
|
||||
data member is a POSIX file descriptor `int fd_;`, although other
|
||||
implementations will differ.
|
||||
|
||||
Our `read` and `write` functions return the number of bytes transferred, and signal
|
||||
errors via the output parameter `ec`, of type `boost::system::error_code`.
|
||||
|
||||
An implementation of `file::read` might look like this:
|
||||
|
||||
```
|
||||
std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
|
||||
{
|
||||
ssize_t r = ::read( fd_, buffer, size );
|
||||
|
||||
if( r < 0 )
|
||||
{
|
||||
ec.assign( errno, sys::system_category() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
ec = {}; // ec.clear(); under C++03
|
||||
return r;
|
||||
}
|
||||
```
|
||||
|
||||
We first call the POSIX API `read`; if it returns an error, we store the `errno`
|
||||
value in `ec`, using the system category, and return 0 as bytes transferred.
|
||||
Otherwise, we clear `ec` to signal success, and return the result of `::read`.
|
||||
|
||||
NOTE: Clearing `ec` on successful returns is an important step; do not omit it.
|
||||
|
||||
Under POSIX, the system category corresponds to POSIX `errno` values, which is
|
||||
why we use it.
|
||||
|
||||
In principle, since the generic category _also_ corresponds to `errno` values
|
||||
under all platforms, we could have used it here; however, by convention under
|
||||
POSIX, if the `errno` value comes from the OS (the "system"), we use the system
|
||||
category for it. That's because the system category values may be a
|
||||
platform-specific superset of the generic (platform-independent) values.
|
||||
|
||||
The implementation of `file::write` is basically the same. We show it here for
|
||||
completeness:
|
||||
|
||||
```
|
||||
std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
|
||||
{
|
||||
ssize_t r = ::write( fd_, buffer, size );
|
||||
|
||||
if( r < 0 )
|
||||
{
|
||||
ec.assign( errno, sys::system_category() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
ec = {}; // ec.clear(); under C++03
|
||||
return r;
|
||||
}
|
||||
```
|
||||
|
||||
## Returning Errors from OS APIs under Windows
|
||||
|
||||
Under Windows, our `file` object will store a `HANDLE` instead of an `int`:
|
||||
|
||||
```
|
||||
class file
|
||||
{
|
||||
private:
|
||||
|
||||
HANDLE fh_;
|
||||
|
||||
public:
|
||||
|
||||
// as before
|
||||
};
|
||||
```
|
||||
|
||||
and the implementation of `file::read` will look like this:
|
||||
|
||||
```
|
||||
std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
|
||||
{
|
||||
DWORD r = 0;
|
||||
|
||||
if( ::ReadFile( fh_, buffer, size, &r, 0 ) )
|
||||
{
|
||||
// success
|
||||
ec = {}; // ec.clear(); under C++03
|
||||
}
|
||||
else
|
||||
{
|
||||
// failure
|
||||
ec.assign( ::GetLastError(), sys::system_category() );
|
||||
}
|
||||
|
||||
// In both cases, r is bytes transferred
|
||||
return r;
|
||||
}
|
||||
```
|
||||
|
||||
Here, the system category corresponds to the values defined in the system
|
||||
header `<winerror.h>` and returned by `GetLastError()`. Since we use the
|
||||
Win32 API `ReadFile` to implement `file::read`, and it returns the error
|
||||
code via `GetLastError()`, we again store that value in `ec` as belonging
|
||||
to the system category.
|
||||
|
||||
The implementation of `file::write` is, again, the same.
|
||||
|
||||
```
|
||||
std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
|
||||
{
|
||||
DWORD r = 0;
|
||||
|
||||
if( ::WriteFile( fh_, buffer, size, &r, 0 ) )
|
||||
{
|
||||
ec = {}; // ec.clear(); under C++03
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign( ::GetLastError(), sys::system_category() );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
```
|
||||
|
||||
## Returning Specific Errors under POSIX
|
||||
|
||||
Our implementation of `file::read` has a problem; it accepts `std::size_t`
|
||||
values for `size`, but the behavior of `::read` is unspecified when the
|
||||
requested value does not fit in `ssize_t`. To avoid reliance on unspecified
|
||||
behavior, let's add a check for this condition and return an error:
|
||||
|
||||
```
|
||||
std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
|
||||
{
|
||||
if( size > SSIZE_MAX )
|
||||
{
|
||||
ec.assign( EINVAL, sys::generic_category() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t r = ::read( fd_, buffer, size );
|
||||
|
||||
if( r < 0 )
|
||||
{
|
||||
ec.assign( errno, sys::system_category() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
ec = {}; // ec.clear(); under C++03
|
||||
return r;
|
||||
}
|
||||
```
|
||||
|
||||
In this case, since we're returning the fixed `errno` value `EINVAL`, which
|
||||
is part of the portable subset defined by the generic category, we mark the
|
||||
error value in `ec` as belonging to the generic category.
|
||||
|
||||
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.
|
||||
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
|
||||
it return `ENOSPC` in this case.
|
||||
|
||||
```
|
||||
std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
|
||||
{
|
||||
if( size > SSIZE_MAX )
|
||||
{
|
||||
ec.assign( EINVAL, sys::generic_category() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t r = ::write( fd_, buffer, size );
|
||||
|
||||
if( r < 0 )
|
||||
{
|
||||
ec.assign( errno, sys::system_category() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( r < size )
|
||||
{
|
||||
ec.assign( ENOSPC, sys::system_category() );
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = {}; // ec.clear(); under C++03
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
```
|
||||
|
||||
We've used the system category to make it appear that the `ENOSPC` value
|
||||
has come from the `::write` API, mostly to illustrate that this is also a
|
||||
possible approach. Using a generic value would have worked just as well.
|
||||
|
||||
## Returning Specific Errors under Windows
|
||||
|
||||
Not much to say; the situation under Windows is exactly the same. The only
|
||||
difference is that we _must_ use the generic category for returning `errno`
|
||||
values. The system category does not work; the integer values in the system
|
||||
category are entirely different from those in the generic category.
|
||||
|
||||
```
|
||||
std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
|
||||
{
|
||||
DWORD r = 0;
|
||||
|
||||
if( size > MAXDWORD )
|
||||
{
|
||||
ec.assign( EINVAL, sys::generic_category() );
|
||||
}
|
||||
else if( ::ReadFile( fh_, buffer, size, &r, 0 ) )
|
||||
{
|
||||
ec = {}; // ec.clear(); under C++03
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign( ::GetLastError(), sys::system_category() );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
|
||||
{
|
||||
DWORD r = 0;
|
||||
|
||||
if( size > MAXDWORD )
|
||||
{
|
||||
ec.assign( EINVAL, sys::generic_category() );
|
||||
}
|
||||
else if( ::WriteFile( fh_, buffer, size, &r, 0 ) )
|
||||
{
|
||||
if( r < size )
|
||||
{
|
||||
ec.assign( ENOSPC, sys::generic_category() );
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = {}; // ec.clear(); under C++03
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign( ::GetLastError(), sys::system_category() );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
```
|
||||
|
||||
## 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
|
||||
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:
|
||||
|
||||
```
|
||||
std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
|
||||
{
|
||||
if( size > SSIZE_MAX )
|
||||
{
|
||||
static constexpr boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
ec.assign( EINVAL, sys::generic_category(), &loc );
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t r = ::read( fd_, buffer, size );
|
||||
|
||||
if( r < 0 )
|
||||
{
|
||||
static constexpr boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
ec.assign( errno, sys::system_category(), &loc );
|
||||
return 0;
|
||||
}
|
||||
|
||||
ec = {}; // ec.clear(); under C++03
|
||||
return r;
|
||||
}
|
||||
```
|
||||
|
||||
That is, before every `ec.assign` statement, we need to declare a
|
||||
`static constexpr` variable holding the current source location, then pass
|
||||
a pointer to it to `assign`. Since `error_code` is small and there's no space
|
||||
in it for more than a pointer, we can't just store the `source_location` in it
|
||||
by value.
|
||||
|
||||
`BOOST_CURRENT_LOCATION` is a macro expanding to the current source location
|
||||
(a combination of `++__FILE__++`, `++__LINE__++`, and `BOOST_CURRENT_FUNCTION`.)
|
||||
It's defined and documented in link:../../../assert/index.html[Boost.Assert].
|
||||
|
||||
Under {cpp}03, instead of `static constexpr`, one needs to use `static const`.
|
||||
Another option is `BOOST_STATIC_CONSTEXPR`, a
|
||||
link:../../../config/index.html[Boost.Config] macro that expands to either
|
||||
`static constexpr` or `static const`, as appropriate.
|
||||
|
||||
To avoid repeating this boilerplate each time we do `ec.assign`, we can define
|
||||
a macro:
|
||||
|
||||
```
|
||||
#define ASSIGN(ec, ...) { \
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION; \
|
||||
(ec).assign(__VA_ARGS__, &loc); }
|
||||
```
|
||||
|
||||
which we can now use to augment, for example, the POSIX implementation of `file::write`:
|
||||
|
||||
```
|
||||
std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
|
||||
{
|
||||
if( size > SSIZE_MAX )
|
||||
{
|
||||
ASSIGN( ec, EINVAL, sys::generic_category() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t r = ::write( fd_, buffer, size );
|
||||
|
||||
if( r < 0 )
|
||||
{
|
||||
ASSIGN( ec, errno, sys::system_category() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( r < size )
|
||||
{
|
||||
ASSIGN( ec, ENOSPC, sys::generic_category() );
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = {}; // ec.clear(); under C++03
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
```
|
||||
|
||||
## Obtaining Textual Representations of Error Codes for Logging and Display
|
||||
|
||||
Assuming that we have an `error_code` instance `ec`, returned to us by some
|
||||
function, we have a variety of means to obtain textual representations of the
|
||||
error code represented therein.
|
||||
|
||||
`ec.to_string()` gives us the result of streaming `ec` into a `std::ostream`,
|
||||
e.g. if `std::cout << ec << std::endl;` outputs `system:6`, this is what
|
||||
`ec.to_string()` will return. (`system:6` under Windows is `ERROR_INVALID_HANDLE`
|
||||
from `<winerror.h>`.)
|
||||
|
||||
To obtain a human-readable error message corresponding to this code, we can
|
||||
use `ec.message()`. For `ERROR_INVALID_HANDLE`, it would give us "The handle is
|
||||
invalid" - possibly localized.
|
||||
|
||||
If `ec` contains a source location, we can obtain its textual representation
|
||||
via `ec.location().to_string()`. This will give us something like
|
||||
|
||||
```text
|
||||
C:\Projects\testbed2019\testbed2019.cpp:98 in function 'unsigned __int64 __cdecl file::read(void *,unsigned __int64,class boost::system::error_code &)'
|
||||
```
|
||||
|
||||
if there is a location in `ec`, and
|
||||
|
||||
```text
|
||||
(unknown source location)
|
||||
```
|
||||
|
||||
if there isn't. (`ec.has_location()` is `true` when `ec` contains a location.)
|
||||
|
||||
Finally, `ec.what()` will give us a string that contains all of the above,
|
||||
something like
|
||||
|
||||
```text
|
||||
The handle is invalid [system:6 at C:\Projects\testbed2019\testbed2019.cpp:98 in function 'unsigned __int64 __cdecl file::read(void *,unsigned __int64,class boost::system::error_code &)']
|
||||
```
|
||||
|
||||
Most logging and diagnostic output that is not intended for the end user would
|
||||
probably end up using `what()`. (`ec.what()`, augmented with the prefix
|
||||
supplied at construction, is also what `boost::system::system_error::what()`
|
||||
would return.)
|
||||
|
||||
## Composing Functions Returning Error Codes
|
||||
|
||||
Let's suppose that we need to implement a file copy function, with the following
|
||||
interface:
|
||||
|
||||
```
|
||||
std::size_t file_copy( file& src, file& dest, sys::error_code& ec );
|
||||
```
|
||||
|
||||
`file_copy` uses `src.read` to read bytes from `src`, then writes these bytes
|
||||
to `dest` using `dest.write`. This continues until one of these operations signals
|
||||
an error, or until end of file is reached. It returns the number of bytes written,
|
||||
and uses `ec` to signal an error.
|
||||
|
||||
Here is one possible implementation:
|
||||
|
||||
```
|
||||
std::size_t file_copy( file& src, file& dest, sys::error_code& ec )
|
||||
{
|
||||
std::size_t r = 0;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
unsigned char buffer[ 1024 ];
|
||||
|
||||
std::size_t n = src.read( buffer, sizeof( buffer ), ec );
|
||||
|
||||
// read failed, leave the error in ec and return
|
||||
if( ec.failed() ) return r;
|
||||
|
||||
// end of file has been reached, exit loop
|
||||
if( n == 0 ) return r;
|
||||
|
||||
r += dest.write( buffer, n, ec );
|
||||
|
||||
// write failed, leave the error in ec and return
|
||||
if( ec.failed() ) return r;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that there is no longer any difference between POSIX and Windows
|
||||
implementations; their differences are contained in `file::read` and
|
||||
`file::write`. `file_copy` is portable and works under any platform.
|
||||
|
||||
The general pattern in writing such higher-level functions is that
|
||||
they pass the output `error_code` parameter `ec` they received from
|
||||
the caller directly as the output parameter to the lower-level functions
|
||||
they are built upon. This way, when they detect a failure in an intermediate
|
||||
operation (by testing `ec.failed()`), they can immediately return to the
|
||||
caller, because the error code is already in its proper place.
|
||||
|
||||
Note that `file_copy` doesn't even need to clear `ec` on success, by
|
||||
using `ec = {};`. Since we've already tested `ec.failed()`, we know that
|
||||
`ec` contains a value that means success.
|
||||
|
||||
## Providing Dual (Throwing and Nonthrowing) Overloads
|
||||
|
||||
Functions that signal errors via an output `error_code& ec` parameter
|
||||
require that the caller check `ec` after calling them, and take appropriate
|
||||
action (such as return immediately, as above.) Forgetting to check `ec`
|
||||
results in logic errors.
|
||||
|
||||
While this is a preferred coding style for some, others prefer exceptions,
|
||||
which one cannot forget to check.
|
||||
|
||||
An approach that has been introduced by
|
||||
link:../../../filesystem/index.html[Boost.Filesystem] (which later turned
|
||||
into `std::filesystem`) is to provide both alternatives: a nonthrowing
|
||||
function taking `error_code& ec`, as `file_copy` above, and a throwing
|
||||
function that does not take an `error_code` output parameter, and throws
|
||||
exceptions on failure.
|
||||
|
||||
This is how this second throwing function is typically implemented:
|
||||
|
||||
```
|
||||
std::size_t file_copy( file& src, file& dest )
|
||||
{
|
||||
sys::error_code ec;
|
||||
std::size_t r = file_copy( src, dest, ec );
|
||||
|
||||
if( ec.failed() ) throw sys::system_error( ec, __func__ );
|
||||
|
||||
return r;
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
exceptions (although we haven't done so in the preceding examples in order
|
||||
to keep the code {cpp}03-friendly.)
|
||||
|
||||
## result<T> as an Alternative to Dual APIs
|
||||
|
||||
Instead of providing two functions for every operation, an alternative
|
||||
approach is to make the function return `sys::result<T>` instead of `T`.
|
||||
`result<T>` is a class holding either `T` or `error_code`, similar to
|
||||
link:../../../variant2/index.html[`variant<T, error_code>`].
|
||||
|
||||
Clients that prefer to check for errors and not rely on exceptions can
|
||||
test whether a `result<T> r` contains a value via `if( r )` or its more
|
||||
verbose equivalent `if( r.has_value() )`, then obtain the value via
|
||||
`*r` or `r.value()`. If `r` doesn't contain a value, the `error_code`
|
||||
it holds can be obtained with `r.error()`.
|
||||
|
||||
Those who prefer exceptions just call `r.value()` directly, without
|
||||
checking. In the no-value case, this will automatically throw a
|
||||
`system_error` corresponding to the `error_code` in `r`.
|
||||
|
||||
Assuming our base `file` API is unchanged, this variation of `file_copy`
|
||||
would look like this:
|
||||
|
||||
```
|
||||
sys::result<std::size_t> file_copy( file& src, file& dest )
|
||||
{
|
||||
std::size_t r = 0;
|
||||
sys::error_code ec;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
unsigned char buffer[ 1024 ];
|
||||
|
||||
std::size_t n = src.read( buffer, sizeof( buffer ), ec );
|
||||
|
||||
if( ec.failed() ) return ec;
|
||||
if( n == 0 ) return r;
|
||||
|
||||
r += dest.write( buffer, n, ec );
|
||||
|
||||
if( ec.failed() ) return ec;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The only difference here is that we return `ec` on error, instead of
|
||||
`r`.
|
||||
|
||||
Note, however, that we can no longer return both an error code and a
|
||||
number of transferred bytes; that is, we can no longer signal _partial
|
||||
success_. This is often not an issue at higher levels, but lower-level
|
||||
primitives such as `file::read` and `file::write` might be better off
|
||||
written using the old style.
|
||||
|
||||
Nevertheless, to demonstrate how `result` returning APIs are composed,
|
||||
we'll show how `file_copy` would look if `file::read` and `file::write`
|
||||
returned `result<size_t>`:
|
||||
|
||||
```
|
||||
class file
|
||||
{
|
||||
public:
|
||||
|
||||
// ...
|
||||
|
||||
sys::result<std::size_t> read( void * buffer, std::size_t size );
|
||||
sys::result<std::size_t> write( void const * buffer, std::size_t size );
|
||||
};
|
||||
|
||||
sys::result<std::size_t> file_copy( file& src, file& dest )
|
||||
{
|
||||
std::size_t m = 0;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
unsigned char buffer[ 1024 ];
|
||||
|
||||
auto r = src.read( buffer, sizeof( buffer ) );
|
||||
if( !r ) return r;
|
||||
|
||||
std::size_t n = *r;
|
||||
if( n == 0 ) return m;
|
||||
|
||||
auto r2 = dest.write( buffer, n );
|
||||
if( !r2 ) return r2;
|
||||
|
||||
std::size_t n2 = *r2;
|
||||
m += n2;
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace system
|
||||
{
|
||||
|
||||
@@ -91,7 +90,6 @@ inline char const * error_category::message( int ev, char * buffer, std::size_t
|
||||
}
|
||||
|
||||
} // namespace system
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// interoperability with std::error_code, std::error_condition
|
||||
@@ -100,28 +98,54 @@ inline char const * error_category::message( int ev, char * buffer, std::size_t
|
||||
|
||||
#include <boost/system/detail/std_category.hpp>
|
||||
|
||||
inline boost::system::error_category::operator std::error_category const & () const
|
||||
namespace boost
|
||||
{
|
||||
if( id_ == boost::system::detail::system_category_id )
|
||||
namespace system
|
||||
{
|
||||
|
||||
inline error_category::operator std::error_category const & () const
|
||||
{
|
||||
if( id_ == detail::generic_category_id )
|
||||
{
|
||||
static const boost::system::detail::std_category system_instance( this, 0x1F4D7 );
|
||||
return system_instance;
|
||||
// This condition must be the same as the one in error_condition.hpp
|
||||
#if defined(BOOST_GCC) && BOOST_GCC < 50000
|
||||
|
||||
static const boost::system::detail::std_category generic_instance( this, 0x1F4D3 );
|
||||
return generic_instance;
|
||||
|
||||
#else
|
||||
|
||||
return std::generic_category();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
if( id_ == boost::system::detail::generic_category_id )
|
||||
if( id_ == detail::system_category_id )
|
||||
{
|
||||
static const boost::system::detail::std_category generic_instance( this, 0x1F4D3 );
|
||||
return generic_instance;
|
||||
// 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
|
||||
|
||||
static const boost::system::detail::std_category system_instance( this, 0x1F4D7 );
|
||||
return system_instance;
|
||||
|
||||
#else
|
||||
|
||||
return std::system_category();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
boost::system::detail::std_category* p = ps_.load( std::memory_order_acquire );
|
||||
detail::std_category* p = ps_.load( std::memory_order_acquire );
|
||||
|
||||
if( p != 0 )
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
boost::system::detail::std_category* q = new detail::std_category( this, 0 );
|
||||
detail::std_category* q = new detail::std_category( this, 0 );
|
||||
|
||||
if( ps_.compare_exchange_strong( p, q, std::memory_order_release, std::memory_order_acquire ) )
|
||||
{
|
||||
@@ -134,6 +158,9 @@ inline boost::system::error_category::operator std::error_category const & () co
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace system
|
||||
} // namespace boost
|
||||
|
||||
#endif // #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
|
||||
|
||||
#endif // #ifndef BOOST_SYSTEM_DETAIL_ERROR_CATEGORY_IMPL_HPP_INCLUDED
|
||||
|
||||
@@ -107,10 +107,30 @@ public:
|
||||
}
|
||||
|
||||
template<class ErrorCodeEnum> BOOST_SYSTEM_CONSTEXPR error_code( ErrorCodeEnum e,
|
||||
typename detail::enable_if<
|
||||
is_error_code_enum<ErrorCodeEnum>::value
|
||||
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
|
||||
|| std::is_error_code_enum<ErrorCodeEnum>::value
|
||||
#endif
|
||||
>::type* = 0 ) BOOST_NOEXCEPT: d1_(), lc_flags_( 0 )
|
||||
{
|
||||
*this = make_error_code( e );
|
||||
}
|
||||
|
||||
template<class ErrorCodeEnum> error_code( ErrorCodeEnum e, source_location const * loc,
|
||||
typename detail::enable_if<is_error_code_enum<ErrorCodeEnum>::value>::type* = 0 ) BOOST_NOEXCEPT:
|
||||
d1_(), lc_flags_( 0 )
|
||||
{
|
||||
*this = make_error_code( e );
|
||||
error_code e2 = make_error_code( e );
|
||||
|
||||
if( e2.lc_flags_ == 0 || e2.lc_flags_ == 1 )
|
||||
{
|
||||
*this = e2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*this = error_code( e2.d1_.val_, *e2.d1_.cat_, loc );
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
|
||||
@@ -143,6 +163,13 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename ErrorCodeEnum>
|
||||
typename detail::enable_if<is_error_code_enum<ErrorCodeEnum>::value, void>::type
|
||||
assign( ErrorCodeEnum val, source_location const * loc ) BOOST_NOEXCEPT
|
||||
{
|
||||
*this = error_code( val, loc );
|
||||
}
|
||||
|
||||
BOOST_SYSTEM_CONSTEXPR void clear() BOOST_NOEXCEPT
|
||||
{
|
||||
*this = error_code();
|
||||
@@ -504,8 +531,16 @@ public:
|
||||
}
|
||||
else if( lc_flags_ == 0 )
|
||||
{
|
||||
//return std::error_code();
|
||||
// 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)
|
||||
|
||||
return std::error_code( 0, boost::system::system_category() );
|
||||
|
||||
#else
|
||||
|
||||
return std::error_code();
|
||||
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -571,6 +606,23 @@ public:
|
||||
{
|
||||
return os << ec.to_string();
|
||||
}
|
||||
|
||||
std::string what() const
|
||||
{
|
||||
std::string r = message();
|
||||
|
||||
r += " [";
|
||||
r += to_string();
|
||||
|
||||
if( has_location() )
|
||||
{
|
||||
r += " at ";
|
||||
r += location().to_string();
|
||||
}
|
||||
|
||||
r += "]";
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::size_t hash_value( error_code const & ec )
|
||||
|
||||
@@ -222,7 +222,23 @@ 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
|
||||
|
||||
return std::error_condition( value(), category() );
|
||||
|
||||
#else
|
||||
|
||||
if( cat_ )
|
||||
{
|
||||
return std::error_condition( val_, *cat_ );
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::error_condition( val_, std::generic_category() );
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
inline friend bool operator==( std::error_code const & lhs, error_condition const & rhs ) BOOST_NOEXCEPT
|
||||
|
||||
@@ -49,6 +49,9 @@ inline void snprintf( char * buffer, std::size_t len, char const * format, ... )
|
||||
|
||||
#else
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||
__attribute__((__format__ (__printf__, 3, 4)))
|
||||
#endif
|
||||
inline void snprintf( char * buffer, std::size_t len, char const * format, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
||||
@@ -62,35 +62,10 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// explicit, value
|
||||
template<class A, class En = typename std::enable_if<
|
||||
std::is_constructible<T, A>::value &&
|
||||
!std::is_convertible<A, T>::value &&
|
||||
!std::is_constructible<E, A>::value
|
||||
>::type>
|
||||
explicit constexpr result( A&& a )
|
||||
noexcept( std::is_nothrow_constructible<T, A>::value )
|
||||
: v_( in_place_value, std::forward<A>(a) )
|
||||
{
|
||||
}
|
||||
|
||||
// explicit, error
|
||||
template<class A, class En2 = void, class En = typename std::enable_if<
|
||||
std::is_constructible<E, A>::value &&
|
||||
!std::is_convertible<A, E>::value &&
|
||||
!std::is_constructible<T, A>::value
|
||||
>::type>
|
||||
explicit constexpr result( A&& a )
|
||||
noexcept( std::is_nothrow_constructible<E, A>::value )
|
||||
: v_( in_place_error, std::forward<A>(a) )
|
||||
{
|
||||
}
|
||||
|
||||
// implicit, value
|
||||
template<class A, class En2 = void, class En3 = void, class En = typename std::enable_if<
|
||||
template<class A = T, typename std::enable_if<
|
||||
std::is_convertible<A, T>::value &&
|
||||
!std::is_constructible<E, A>::value
|
||||
>::type>
|
||||
!std::is_constructible<E, A>::value, int>::type = 0>
|
||||
constexpr result( A&& a )
|
||||
noexcept( std::is_nothrow_constructible<T, A>::value )
|
||||
: v_( in_place_value, std::forward<A>(a) )
|
||||
@@ -98,35 +73,32 @@ public:
|
||||
}
|
||||
|
||||
// implicit, error
|
||||
template<class A, class En2 = void, class En3 = void, class En4 = void, class En = typename std::enable_if<
|
||||
template<class A = E, class = void, typename std::enable_if<
|
||||
std::is_convertible<A, E>::value &&
|
||||
!std::is_constructible<T, A>::value
|
||||
>::type>
|
||||
!std::is_constructible<T, A>::value, int>::type = 0>
|
||||
constexpr result( A&& a )
|
||||
noexcept( std::is_nothrow_constructible<E, A>::value )
|
||||
: v_( in_place_error, std::forward<A>(a) )
|
||||
{
|
||||
}
|
||||
|
||||
// more than one arg, value
|
||||
// explicit, value
|
||||
template<class... A, class En = typename std::enable_if<
|
||||
std::is_constructible<T, A...>::value &&
|
||||
!std::is_constructible<E, A...>::value &&
|
||||
sizeof...(A) >= 2
|
||||
!std::is_constructible<E, A...>::value
|
||||
>::type>
|
||||
constexpr result( A&&... a )
|
||||
explicit constexpr result( A&&... a )
|
||||
noexcept( std::is_nothrow_constructible<T, A...>::value )
|
||||
: v_( in_place_value, std::forward<A>(a)... )
|
||||
{
|
||||
}
|
||||
|
||||
// more than one arg, error
|
||||
// explicit, error
|
||||
template<class... A, class En2 = void, class En = typename std::enable_if<
|
||||
!std::is_constructible<T, A...>::value &&
|
||||
std::is_constructible<E, A...>::value &&
|
||||
sizeof...(A) >= 2
|
||||
std::is_constructible<E, A...>::value
|
||||
>::type>
|
||||
constexpr result( A&&... a )
|
||||
explicit constexpr result( A&&... a )
|
||||
noexcept( std::is_nothrow_constructible<E, A...>::value )
|
||||
: v_( in_place_error, std::forward<A>(a)... )
|
||||
{
|
||||
@@ -210,12 +182,31 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR T&& value() &&
|
||||
template<class U = T>
|
||||
BOOST_CXX14_CONSTEXPR
|
||||
typename std::enable_if<std::is_move_constructible<U>::value, T>::type
|
||||
value() &&
|
||||
{
|
||||
return std::move( value() );
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR T const&& value() const&&
|
||||
template<class U = T>
|
||||
BOOST_CXX14_CONSTEXPR
|
||||
typename std::enable_if<!std::is_move_constructible<U>::value, T&&>::type
|
||||
value() &&
|
||||
{
|
||||
return std::move( value() );
|
||||
}
|
||||
|
||||
template<class U = T>
|
||||
BOOST_CXX14_CONSTEXPR
|
||||
typename std::enable_if<std::is_move_constructible<U>::value, T>::type
|
||||
value() const && = delete;
|
||||
|
||||
template<class U = T>
|
||||
BOOST_CXX14_CONSTEXPR
|
||||
typename std::enable_if<!std::is_move_constructible<U>::value, T const&&>::type
|
||||
value() const &&
|
||||
{
|
||||
return std::move( value() );
|
||||
}
|
||||
@@ -274,12 +265,31 @@ public:
|
||||
return *p;
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR T&& operator*() && noexcept
|
||||
template<class U = T>
|
||||
BOOST_CXX14_CONSTEXPR
|
||||
typename std::enable_if<std::is_move_constructible<U>::value, T>::type
|
||||
operator*() && noexcept(std::is_nothrow_move_constructible<T>::value)
|
||||
{
|
||||
return std::move(**this);
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR T const&& operator*() const && noexcept
|
||||
template<class U = T>
|
||||
BOOST_CXX14_CONSTEXPR
|
||||
typename std::enable_if<!std::is_move_constructible<U>::value, T&&>::type
|
||||
operator*() && noexcept
|
||||
{
|
||||
return std::move(**this);
|
||||
}
|
||||
|
||||
template<class U = T>
|
||||
BOOST_CXX14_CONSTEXPR
|
||||
typename std::enable_if<std::is_move_constructible<U>::value, T>::type
|
||||
operator*() const && noexcept = delete;
|
||||
|
||||
template<class U = T>
|
||||
BOOST_CXX14_CONSTEXPR
|
||||
typename std::enable_if<!std::is_move_constructible<U>::value, T const&&>::type
|
||||
operator*() const && noexcept
|
||||
{
|
||||
return std::move(**this);
|
||||
}
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/system/errc.hpp>
|
||||
#include <boost/system/detail/error_code.hpp>
|
||||
#include <boost/system/detail/error_category_impl.hpp>
|
||||
#include <boost/system/detail/snprintf.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
@@ -26,14 +25,6 @@ private:
|
||||
|
||||
private:
|
||||
|
||||
static std::string to_string( int v )
|
||||
{
|
||||
char buffer[ 32 ];
|
||||
detail::snprintf( buffer, sizeof( buffer ), "%d", v );
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static std::string build_message( char const * prefix, error_code const & ec )
|
||||
{
|
||||
std::string r;
|
||||
@@ -44,32 +35,7 @@ private:
|
||||
r += ": ";
|
||||
}
|
||||
|
||||
r += ec.message();
|
||||
|
||||
if( ec.has_location() )
|
||||
{
|
||||
r += " [";
|
||||
r += ec.to_string();
|
||||
r += " at ";
|
||||
|
||||
boost::source_location loc = ec.location();
|
||||
|
||||
r += loc.file_name();
|
||||
|
||||
r += ':';
|
||||
r += to_string( loc.line() );
|
||||
|
||||
if( loc.column() != 0 )
|
||||
{
|
||||
r += ':';
|
||||
r += to_string( loc.column() );
|
||||
}
|
||||
|
||||
r += " in function '";
|
||||
r += loc.function_name();
|
||||
r += "\']";
|
||||
}
|
||||
|
||||
r += ec.what();
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,14 @@ boost_test(TYPE run SOURCES ec_location_test.cpp)
|
||||
|
||||
boost_test(TYPE run SOURCES error_condition_test3.cpp)
|
||||
boost_test(TYPE run SOURCES error_code_test2.cpp)
|
||||
boost_test(TYPE run SOURCES system_error_test2.cpp)
|
||||
boost_test(TYPE run SOURCES std_interop_test10.cpp)
|
||||
|
||||
boost_test(TYPE run SOURCES ec_location_test2.cpp)
|
||||
boost_test(TYPE run SOURCES ec_what_test.cpp)
|
||||
boost_test(TYPE run SOURCES system_error_test3.cpp)
|
||||
|
||||
boost_test(TYPE run SOURCES std_interop_test11.cpp)
|
||||
|
||||
# result
|
||||
|
||||
@@ -119,3 +127,6 @@ boost_test(TYPE run SOURCES result_value_access.cpp)
|
||||
boost_test(TYPE run SOURCES result_error_access.cpp)
|
||||
boost_test(TYPE run SOURCES result_swap.cpp)
|
||||
boost_test(TYPE run SOURCES result_eq.cpp)
|
||||
boost_test(TYPE run SOURCES result_range_for.cpp)
|
||||
boost_test(TYPE run SOURCES result_value_construct2.cpp)
|
||||
boost_test(TYPE run SOURCES result_error_construct2.cpp)
|
||||
|
||||
@@ -73,8 +73,8 @@ system-run failed_constexpr_test.cpp ;
|
||||
# Quick (CI) test
|
||||
run quick.cpp ;
|
||||
|
||||
compile warnings_test.cpp
|
||||
: <warnings>pedantic
|
||||
run warnings_test.cpp
|
||||
: : : <warnings>pedantic
|
||||
<toolset>msvc:<warnings-as-errors>on
|
||||
<toolset>gcc:<warnings-as-errors>on
|
||||
<toolset>clang:<warnings-as-errors>on ;
|
||||
@@ -125,6 +125,14 @@ run ec_location_test.cpp ;
|
||||
|
||||
run error_condition_test3.cpp ;
|
||||
run error_code_test2.cpp ;
|
||||
run system_error_test2.cpp ;
|
||||
run std_interop_test10.cpp ;
|
||||
|
||||
run ec_location_test2.cpp ;
|
||||
run ec_what_test.cpp ;
|
||||
run system_error_test3.cpp ;
|
||||
|
||||
run std_interop_test11.cpp ;
|
||||
|
||||
# result
|
||||
|
||||
@@ -143,3 +151,6 @@ run result_value_access.cpp : : : $(CPP11) ;
|
||||
run result_error_access.cpp : : : $(CPP11) ;
|
||||
run result_swap.cpp : : : $(CPP11) <toolset>gcc-10:<cxxflags>"-Wno-maybe-uninitialized" ;
|
||||
run result_eq.cpp : : : $(CPP11) ;
|
||||
run result_range_for.cpp : : : $(CPP11) ;
|
||||
run result_value_construct2.cpp : : : $(CPP11) ;
|
||||
run result_error_construct2.cpp : : : $(CPP11) ;
|
||||
|
||||
@@ -40,5 +40,5 @@ int main()
|
||||
boost::system::system_error x( bc, "prefix" );
|
||||
|
||||
BOOST_TEST_EQ( x.code(), bc );
|
||||
BOOST_TEST_EQ( std::string( x.what() ), "prefix: " + bc.message() );
|
||||
BOOST_TEST_EQ( std::string( x.what() ), "prefix: " + bc.what() );
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ add_subdirectory(../../../config boostorg/config)
|
||||
add_subdirectory(../../../core boostorg/core)
|
||||
add_subdirectory(../../../mp11 boostorg/mp11)
|
||||
add_subdirectory(../../../predef boostorg/predef)
|
||||
add_subdirectory(../../../static_assert boostorg/static_assert)
|
||||
add_subdirectory(../../../throw_exception boostorg/throw_exception)
|
||||
add_subdirectory(../../../variant2 boostorg/variant2)
|
||||
add_subdirectory(../../../winapi boostorg/winapi)
|
||||
|
||||
287
test/ec_location_test2.cpp
Normal file
287
test/ec_location_test2.cpp
Normal file
@@ -0,0 +1,287 @@
|
||||
// Copyright 2021 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/system.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <cerrno>
|
||||
|
||||
namespace sys = boost::system;
|
||||
|
||||
enum E
|
||||
{
|
||||
none = 0,
|
||||
einval = EINVAL
|
||||
};
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace system
|
||||
{
|
||||
|
||||
template<> struct is_error_code_enum< ::E >
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
} // namespace system
|
||||
} // namespace boost
|
||||
|
||||
sys::error_code make_error_code( E e )
|
||||
{
|
||||
return e == 0? sys::error_code(): sys::error_code( e, sys::generic_category() );
|
||||
}
|
||||
|
||||
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
|
||||
|
||||
enum E2
|
||||
{
|
||||
e2inval = EINVAL
|
||||
};
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace system
|
||||
{
|
||||
|
||||
template<> struct is_error_code_enum< ::E2 >
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
} // namespace system
|
||||
} // namespace boost
|
||||
|
||||
std::error_code make_error_code( E2 e )
|
||||
{
|
||||
return std::error_code( e, std::generic_category() );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
sys::error_code ec( einval );
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), EINVAL );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::generic_category() );
|
||||
|
||||
BOOST_TEST( ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
sys::error_code ec( einval, &loc );
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), EINVAL );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::generic_category() );
|
||||
|
||||
BOOST_TEST( ec.failed() );
|
||||
|
||||
BOOST_TEST( ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 77 );
|
||||
}
|
||||
|
||||
{
|
||||
sys::error_code ec( none );
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 0 );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::system_category() );
|
||||
|
||||
BOOST_TEST( !ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
sys::error_code ec( none, &loc );
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 0 );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::system_category() );
|
||||
|
||||
BOOST_TEST( !ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
}
|
||||
|
||||
{
|
||||
sys::error_code ec;
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 0 );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::system_category() );
|
||||
|
||||
BOOST_TEST( !ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
ec = sys::error_code( einval, &loc );
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), EINVAL );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::generic_category() );
|
||||
|
||||
BOOST_TEST( ec.failed() );
|
||||
|
||||
BOOST_TEST( ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 127 );
|
||||
}
|
||||
|
||||
{
|
||||
sys::error_code ec;
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 0 );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::system_category() );
|
||||
|
||||
BOOST_TEST( !ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
ec = sys::error_code( none, &loc );
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 0 );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::system_category() );
|
||||
|
||||
BOOST_TEST( !ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
}
|
||||
|
||||
{
|
||||
sys::error_code ec;
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 0 );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::system_category() );
|
||||
|
||||
BOOST_TEST( !ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
ec.assign( einval, &loc );
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), EINVAL );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::generic_category() );
|
||||
|
||||
BOOST_TEST( ec.failed() );
|
||||
|
||||
BOOST_TEST( ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 175 );
|
||||
}
|
||||
|
||||
{
|
||||
sys::error_code ec;
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 0 );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::system_category() );
|
||||
|
||||
BOOST_TEST( !ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
ec.assign( none, &loc );
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 0 );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::system_category() );
|
||||
|
||||
BOOST_TEST( !ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
}
|
||||
|
||||
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
|
||||
|
||||
{
|
||||
sys::error_code ec( e2inval );
|
||||
|
||||
BOOST_TEST_EQ( ec, std::error_code( EINVAL, std::generic_category() ) );
|
||||
|
||||
BOOST_TEST( ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
sys::error_code ec( e2inval, &loc );
|
||||
|
||||
BOOST_TEST_EQ( ec, std::error_code( EINVAL, std::generic_category() ) );
|
||||
|
||||
BOOST_TEST( ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
}
|
||||
|
||||
{
|
||||
sys::error_code ec;
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 0 );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::system_category() );
|
||||
|
||||
BOOST_TEST( !ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
ec = sys::error_code( e2inval, &loc );
|
||||
|
||||
BOOST_TEST_EQ( ec, std::error_code( EINVAL, std::generic_category() ) );
|
||||
|
||||
BOOST_TEST( ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
}
|
||||
|
||||
{
|
||||
sys::error_code ec;
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 0 );
|
||||
BOOST_TEST_EQ( &ec.category(), &sys::system_category() );
|
||||
|
||||
BOOST_TEST( !ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
ec.assign( e2inval, &loc );
|
||||
|
||||
BOOST_TEST_EQ( ec, std::error_code( EINVAL, std::generic_category() ) );
|
||||
|
||||
BOOST_TEST( ec.failed() );
|
||||
|
||||
BOOST_TEST( !ec.has_location() );
|
||||
BOOST_TEST_EQ( ec.location().line(), 0 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
91
test/ec_what_test.cpp
Normal file
91
test/ec_what_test.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright 2020, 2021 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/generic_category.hpp>
|
||||
#include <boost/system/system_category.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace sys = boost::system;
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
sys::error_code ec;
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 0 );
|
||||
BOOST_TEST( ec.category() == sys::system_category() );
|
||||
|
||||
BOOST_TEST_EQ( ec.what(), ec.message() + " [system:0]" );
|
||||
}
|
||||
|
||||
{
|
||||
sys::error_code ec( 5, sys::generic_category() );
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 5 );
|
||||
BOOST_TEST( ec.category() == sys::generic_category() );
|
||||
|
||||
BOOST_TEST_EQ( ec.what(), ec.message() + " [generic:5]" );
|
||||
}
|
||||
|
||||
{
|
||||
sys::error_code ec( 5, sys::system_category() );
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 5 );
|
||||
BOOST_TEST( ec.category() == sys::system_category() );
|
||||
|
||||
BOOST_TEST_EQ( ec.what(), ec.message() + " [system:5]" );
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
sys::error_code ec( 5, sys::generic_category(), &loc );
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 5 );
|
||||
BOOST_TEST( ec.category() == sys::generic_category() );
|
||||
BOOST_TEST_EQ( &ec.location(), &loc );
|
||||
|
||||
BOOST_TEST_EQ( ec.what(), ec.message() + " [generic:5 at " + loc.to_string() + "]" );
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
sys::error_code ec( 5, sys::system_category(), &loc );
|
||||
|
||||
BOOST_TEST_EQ( ec.value(), 5 );
|
||||
BOOST_TEST( ec.category() == sys::system_category() );
|
||||
BOOST_TEST_EQ( &ec.location(), &loc );
|
||||
|
||||
BOOST_TEST_EQ( ec.what(), ec.message() + " [system:5 at " + loc.to_string() + "]" );
|
||||
}
|
||||
|
||||
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
|
||||
|
||||
{
|
||||
std::error_code ec;
|
||||
sys::error_code ec2( ec );
|
||||
|
||||
BOOST_TEST_EQ( ec2.what(), ec2.message() + " [std:system:0]" );
|
||||
}
|
||||
|
||||
{
|
||||
std::error_code ec( 5, std::generic_category() );
|
||||
sys::error_code ec2( ec );
|
||||
|
||||
BOOST_TEST_EQ( ec2.what(), ec2.message() + " [std:generic:5]" );
|
||||
}
|
||||
|
||||
{
|
||||
std::error_code ec( 5, std::system_category() );
|
||||
sys::error_code ec2( ec );
|
||||
|
||||
BOOST_TEST_EQ( ec2.what(), ec2.message() + " [std:system:5]" );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -37,7 +37,7 @@ int main()
|
||||
boost::system::system_error x( bc, "prefix" );
|
||||
|
||||
BOOST_TEST_EQ( x.code(), bc );
|
||||
BOOST_TEST_EQ( std::string( x.what() ), "prefix: " + bc.message() );
|
||||
BOOST_TEST_EQ( std::string( x.what() ), "prefix: " + bc.what() );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
57
test/result_error_construct2.cpp
Normal file
57
test/result_error_construct2.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
// 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.hpp>
|
||||
#include <string>
|
||||
|
||||
using namespace boost::system;
|
||||
|
||||
struct X
|
||||
{
|
||||
int a, b;
|
||||
};
|
||||
|
||||
result<X> fx1()
|
||||
{
|
||||
return {{ EINVAL, generic_category() }};
|
||||
}
|
||||
|
||||
struct Y
|
||||
{
|
||||
std::string v;
|
||||
};
|
||||
|
||||
struct E
|
||||
{
|
||||
int v;
|
||||
};
|
||||
|
||||
result<Y, E> fy1()
|
||||
{
|
||||
return {{ 42 }};
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
result<X> r = fx1();
|
||||
|
||||
BOOST_TEST( !r.has_value() );
|
||||
BOOST_TEST( r.has_error() );
|
||||
|
||||
BOOST_TEST_EQ( r.error(), std::error_code( EINVAL, generic_category() ) );
|
||||
}
|
||||
|
||||
{
|
||||
result<Y, E> r = fy1();
|
||||
|
||||
BOOST_TEST( !r.has_value() );
|
||||
BOOST_TEST( r.has_error() );
|
||||
|
||||
BOOST_TEST_EQ( r.error().v, 42 );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
30
test/result_range_for.cpp
Normal file
30
test/result_range_for.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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.hpp>
|
||||
#include <vector>
|
||||
|
||||
using namespace boost::system;
|
||||
|
||||
result<std::vector<int>> f()
|
||||
{
|
||||
return std::vector<int>{ 1, 2, 3 };
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
int s = 0;
|
||||
|
||||
for( int x: f().value() )
|
||||
{
|
||||
s += x;
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ( s, 6 );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
152
test/result_value_construct2.cpp
Normal file
152
test/result_value_construct2.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
// 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.hpp>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
using namespace boost::system;
|
||||
|
||||
struct X
|
||||
{
|
||||
int a;
|
||||
};
|
||||
|
||||
struct Y
|
||||
{
|
||||
int a, b;
|
||||
};
|
||||
|
||||
struct E
|
||||
{
|
||||
std::string v;
|
||||
};
|
||||
|
||||
result<X> fx0()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
result<X> fx1()
|
||||
{
|
||||
return {{ 1 }};
|
||||
}
|
||||
|
||||
result<Y> fy0()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
result<Y> fy2()
|
||||
{
|
||||
return {{ 1, 2 }};
|
||||
}
|
||||
|
||||
result<X, E> fxe0()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
result<X, E> fxe1()
|
||||
{
|
||||
return {{ 1 }};
|
||||
}
|
||||
|
||||
result<std::vector<int>> fv0()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
result<std::vector<int>> fv1()
|
||||
{
|
||||
return {{ 1 }};
|
||||
}
|
||||
|
||||
result<std::vector<int>> fv2()
|
||||
{
|
||||
return {{ 1, 2 }};
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
result<X> r = fx0();
|
||||
|
||||
BOOST_TEST( r.has_value() );
|
||||
|
||||
BOOST_TEST_EQ( r->a, 0 );
|
||||
}
|
||||
|
||||
{
|
||||
result<X> r = fx1();
|
||||
|
||||
BOOST_TEST( r.has_value() );
|
||||
|
||||
BOOST_TEST_EQ( r->a, 1 );
|
||||
}
|
||||
|
||||
{
|
||||
result<Y> r = fy0();
|
||||
|
||||
BOOST_TEST( r.has_value() );
|
||||
|
||||
BOOST_TEST_EQ( r->a, 0 );
|
||||
BOOST_TEST_EQ( r->b, 0 );
|
||||
}
|
||||
|
||||
{
|
||||
result<Y> r = fy2();
|
||||
|
||||
BOOST_TEST( r.has_value() );
|
||||
|
||||
BOOST_TEST_EQ( r->a, 1 );
|
||||
BOOST_TEST_EQ( r->b, 2 );
|
||||
}
|
||||
|
||||
{
|
||||
result<X, E> r = fxe0();
|
||||
|
||||
BOOST_TEST( r.has_value() );
|
||||
|
||||
BOOST_TEST_EQ( r->a, 0 );
|
||||
}
|
||||
|
||||
{
|
||||
result<X, E> r = fxe1();
|
||||
|
||||
BOOST_TEST( r.has_value() );
|
||||
|
||||
BOOST_TEST_EQ( r->a, 1 );
|
||||
}
|
||||
|
||||
{
|
||||
result<std::vector<int>> r = fv0();
|
||||
|
||||
BOOST_TEST( r.has_value() );
|
||||
|
||||
BOOST_TEST_EQ( r->size(), 0 );
|
||||
}
|
||||
|
||||
{
|
||||
result<std::vector<int>> r = fv1();
|
||||
|
||||
BOOST_TEST( r.has_value() );
|
||||
|
||||
BOOST_TEST_EQ( r->size(), 1 );
|
||||
BOOST_TEST_EQ( r->at(0), 1 );
|
||||
}
|
||||
|
||||
{
|
||||
result<std::vector<int>> r = fv2();
|
||||
|
||||
BOOST_TEST( r.has_value() );
|
||||
|
||||
BOOST_TEST_EQ( r->size(), 2 );
|
||||
BOOST_TEST_EQ( r->at(0), 1 );
|
||||
BOOST_TEST_EQ( r->at(1), 2 );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -44,7 +44,8 @@ static void test_generic_category()
|
||||
|
||||
int ev = ENOENT;
|
||||
|
||||
BOOST_TEST_EQ( bt.message( ev ), st.message( ev ) );
|
||||
// Under MSVC, it's "no such file or directory" instead of "No such file or directory"
|
||||
BOOST_TEST_EQ( bt.message( ev ).substr( 1 ), st.message( ev ).substr( 1 ) );
|
||||
|
||||
{
|
||||
boost::system::error_code bc( ev, bt );
|
||||
@@ -82,34 +83,13 @@ static void test_system_category()
|
||||
|
||||
BOOST_TEST_CSTR_EQ( bt.name(), st.name() );
|
||||
|
||||
for( int ev = 1; ev < 6; ++ev )
|
||||
{
|
||||
int ev = 5;
|
||||
BOOST_TEST_EQ( bt.message( ev ), st.message( ev ) );
|
||||
std::string bm = bt.message( ev );
|
||||
std::string sm = st.message( ev );
|
||||
|
||||
{
|
||||
boost::system::error_code bc( ev, bt );
|
||||
|
||||
BOOST_TEST_EQ( bc.value(), ev );
|
||||
BOOST_TEST_EQ( &bc.category(), &bt );
|
||||
|
||||
std::error_code sc( bc );
|
||||
|
||||
BOOST_TEST_EQ( sc.value(), ev );
|
||||
BOOST_TEST_EQ( &sc.category(), &st );
|
||||
}
|
||||
|
||||
{
|
||||
boost::system::error_condition bn = bt.default_error_condition( ev );
|
||||
BOOST_TEST( bt.equivalent( ev, bn ) );
|
||||
|
||||
std::error_condition sn( bn );
|
||||
BOOST_TEST( st.equivalent( ev, sn ) );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int ev = 4;
|
||||
BOOST_TEST_EQ( bt.message( ev ), st.message( ev ) );
|
||||
// We strip whitespace and the trailing dot, MSVC not so much
|
||||
BOOST_TEST_EQ( bm, sm.substr( 0, bm.size() ) );
|
||||
|
||||
{
|
||||
boost::system::error_code bc( ev, bt );
|
||||
|
||||
66
test/std_interop_test10.cpp
Normal file
66
test/std_interop_test10.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2021 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 <boost/config/pragma_message.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>
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
boost::system::error_code e1;
|
||||
boost::system::error_code e2( 0, boost::system::system_category() );
|
||||
|
||||
BOOST_TEST_EQ( e1, e2 );
|
||||
|
||||
std::error_code e3( e1 );
|
||||
std::error_code e4( e2 );
|
||||
|
||||
BOOST_TEST_EQ( e3, e4 );
|
||||
}
|
||||
|
||||
{
|
||||
boost::system::error_code e1;
|
||||
|
||||
std::error_code e2( e1 );
|
||||
std::error_code e3( e1.value(), e1.category() );
|
||||
|
||||
BOOST_TEST_EQ( e2, e3 );
|
||||
}
|
||||
|
||||
{
|
||||
boost::system::error_condition e1;
|
||||
boost::system::error_condition e2( 0, boost::system::generic_category() );
|
||||
|
||||
BOOST_TEST_EQ( e1, e2 );
|
||||
|
||||
std::error_condition e3( e1 );
|
||||
std::error_condition e4( e2 );
|
||||
|
||||
BOOST_TEST( e3 == e4 );
|
||||
}
|
||||
|
||||
{
|
||||
boost::system::error_condition e1;
|
||||
|
||||
std::error_condition e2( e1 );
|
||||
std::error_condition e3( e1.value(), e1.category() );
|
||||
|
||||
BOOST_TEST( e2 == e3 );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
47
test/std_interop_test11.cpp
Normal file
47
test/std_interop_test11.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2021 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 <boost/config/pragma_message.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <ios>
|
||||
|
||||
#if !defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "Skipping test, BOOST_SYSTEM_HAS_SYSTEM_ERROR not defined" )
|
||||
int main() {}
|
||||
|
||||
#elif defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 50000
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "Skipping test, BOOST_LIBSTDCXX_VERSION < 50000" )
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
#include <system_error>
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
boost::system::error_code ec = std::io_errc::stream;
|
||||
|
||||
BOOST_TEST( ec == std::io_errc::stream );
|
||||
BOOST_TEST_NOT( ec != std::io_errc::stream );
|
||||
|
||||
ec.clear();
|
||||
|
||||
BOOST_TEST_NOT( ec == std::io_errc::stream );
|
||||
BOOST_TEST( ec != std::io_errc::stream );
|
||||
|
||||
ec = std::io_errc::stream;
|
||||
|
||||
BOOST_TEST( ec == std::io_errc::stream );
|
||||
BOOST_TEST_NOT( ec != std::io_errc::stream );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -30,13 +30,20 @@ int main()
|
||||
BOOST_TEST_EQ( e2, e1 );
|
||||
BOOST_TEST_NOT( e2 != e1 );
|
||||
|
||||
BOOST_TEST( e2 == en );
|
||||
#if defined(_LIBCPP_VERSION)
|
||||
|
||||
// Under MS STL and libstdc++, std::error_code() does not compare
|
||||
// equal to std::error_condition(). Go figure.
|
||||
|
||||
BOOST_TEST_EQ( e2, en );
|
||||
BOOST_TEST_NOT( e2 != en );
|
||||
|
||||
boost::system::error_code e3( e2 );
|
||||
|
||||
BOOST_TEST_EQ( e3, en );
|
||||
BOOST_TEST_NOT( e3 != en );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
@@ -51,13 +58,17 @@ int main()
|
||||
BOOST_TEST_EQ( e2, e1 );
|
||||
BOOST_TEST_NOT( e2 != e1 );
|
||||
|
||||
BOOST_TEST( e2 == en );
|
||||
#if defined(_LIBCPP_VERSION)
|
||||
|
||||
BOOST_TEST_EQ( e2, en );
|
||||
BOOST_TEST_NOT( e2 != en );
|
||||
|
||||
boost::system::error_code e3( e2 );
|
||||
|
||||
BOOST_TEST_EQ( e3, en );
|
||||
BOOST_TEST_NOT( e3 != en );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
@@ -72,7 +83,7 @@ int main()
|
||||
BOOST_TEST_EQ( e2, e1 );
|
||||
BOOST_TEST_NOT( e2 != e1 );
|
||||
|
||||
BOOST_TEST( e2 == en );
|
||||
BOOST_TEST_EQ( e2, en );
|
||||
BOOST_TEST_NOT( e2 != en );
|
||||
|
||||
boost::system::error_code e3( e2 );
|
||||
@@ -93,7 +104,7 @@ int main()
|
||||
BOOST_TEST_EQ( e2, e1 );
|
||||
BOOST_TEST_NOT( e2 != e1 );
|
||||
|
||||
BOOST_TEST( e2 == en );
|
||||
BOOST_TEST_EQ( e2, en );
|
||||
BOOST_TEST_NOT( e2 != en );
|
||||
|
||||
boost::system::error_code e3( e2 );
|
||||
@@ -114,7 +125,7 @@ int main()
|
||||
BOOST_TEST_EQ( e2, e1 );
|
||||
BOOST_TEST_NOT( e2 != e1 );
|
||||
|
||||
BOOST_TEST( e2 == en );
|
||||
BOOST_TEST_EQ( e2, en );
|
||||
BOOST_TEST_NOT( e2 != en );
|
||||
|
||||
boost::system::error_code e3( e2 );
|
||||
|
||||
@@ -81,27 +81,25 @@ int main( int, char *[] )
|
||||
system_error c6_0( 0, system_category(), "c6_0" );
|
||||
system_error c6_1( 1, system_category(), "c6_1" );
|
||||
|
||||
TEST( c1_0, 0, "The operation completed successfully" );
|
||||
TEST( c1_1, 1, "Incorrect function" );
|
||||
TEST( c1_2u, 2, "The system cannot find the file specified" );
|
||||
TEST( c1_0, 0, "The operation completed successfully [system:0]" );
|
||||
TEST( c1_1, 1, "Incorrect function [system:1]" );
|
||||
TEST( c1_2u, 2, "The system cannot find the file specified [system:2]" );
|
||||
|
||||
TEST( c2_0, 0, "c2_0: The operation completed successfully" );
|
||||
TEST( c2_1, 1, "c2_1: Incorrect function" );
|
||||
TEST( c2_0, 0, "c2_0: The operation completed successfully [system:0]" );
|
||||
TEST( c2_1, 1, "c2_1: Incorrect function [system:1]" );
|
||||
|
||||
TEST( c3_0, 0, "c3_0: The operation completed successfully" );
|
||||
TEST( c3_1, 1, "c3_1: Incorrect function" );
|
||||
TEST( c3_0, 0, "c3_0: The operation completed successfully [system:0]" );
|
||||
TEST( c3_1, 1, "c3_1: Incorrect function [system:1]" );
|
||||
|
||||
TEST( c4_0, 0, "The operation completed successfully" );
|
||||
TEST( c4_1, 1, "Incorrect function" );
|
||||
TEST( c4_2u, 2, "The system cannot find the file specified" );
|
||||
TEST( c4_0, 0, "The operation completed successfully [system:0]" );
|
||||
TEST( c4_1, 1, "Incorrect function [system:1]" );
|
||||
TEST( c4_2u, 2, "The system cannot find the file specified [system:2]" );
|
||||
|
||||
TEST( c5_0, 0, "c5_0: The operation completed successfully" );
|
||||
TEST( c5_1, 1, "c5_1: Incorrect function" );
|
||||
TEST( c5_0, 0, "c5_0: The operation completed successfully [system:0]" );
|
||||
TEST( c5_1, 1, "c5_1: Incorrect function [system:1]" );
|
||||
|
||||
TEST( c6_0, 0, "c6_0: The operation completed successfully" );
|
||||
TEST( c6_1, 1, "c6_1: Incorrect function" );
|
||||
TEST( c6_0, 0, "c6_0: The operation completed successfully [system:0]" );
|
||||
TEST( c6_1, 1, "c6_1: Incorrect function [system:1]" );
|
||||
|
||||
return ::boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
|
||||
41
test/system_error_test2.cpp
Normal file
41
test/system_error_test2.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2021 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/system/system_error.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <cerrno>
|
||||
|
||||
namespace sys = boost::system;
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
sys::error_code ec( 5, sys::generic_category() );
|
||||
sys::system_error x1( ec );
|
||||
(void)x1;
|
||||
}
|
||||
|
||||
{
|
||||
sys::error_code ec( 5, sys::system_category() );
|
||||
sys::system_error x1( ec );
|
||||
(void)x1;
|
||||
}
|
||||
|
||||
{
|
||||
sys::system_error x1( make_error_code( sys::errc::invalid_argument ) );
|
||||
(void)x1;
|
||||
}
|
||||
|
||||
{
|
||||
sys::system_error x1( 5, sys::generic_category() );
|
||||
(void)x1;
|
||||
}
|
||||
|
||||
{
|
||||
sys::system_error x1( 5, sys::system_category() );
|
||||
(void)x1;
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
42
test/system_error_test3.cpp
Normal file
42
test/system_error_test3.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright 2021 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/system/system_error.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <cerrno>
|
||||
|
||||
namespace sys = boost::system;
|
||||
|
||||
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_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION;
|
||||
|
||||
sys::error_code ec( 5, sys::system_category(), &loc );
|
||||
sys::system_error x1( ec, "prefix" );
|
||||
|
||||
BOOST_TEST_EQ( std::string( x1.what() ), "prefix: " + ec.what() );
|
||||
}
|
||||
|
||||
{
|
||||
sys::system_error x1( 5, sys::generic_category() );
|
||||
|
||||
BOOST_TEST_EQ( std::string( x1.what() ), sys::error_code( 5, sys::generic_category() ).what() );
|
||||
}
|
||||
|
||||
{
|
||||
sys::system_error x1( 5, sys::system_category(), "prefix" );
|
||||
|
||||
BOOST_TEST_EQ( std::string( x1.what() ), "prefix: " + sys::error_code( 5, sys::system_category() ).what() );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -46,7 +46,7 @@ int main()
|
||||
boost::system::system_error x( bc, "prefix" );
|
||||
|
||||
BOOST_TEST_EQ( x.code(), bc );
|
||||
BOOST_TEST_EQ( std::string( x.what() ), "prefix: " + bc.message() );
|
||||
BOOST_TEST_EQ( std::string( x.what() ), "prefix: " + bc.what() );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user