Compare commits

..

17 Commits

Author SHA1 Message Date
Peter Dimov
1caaacff57 Split reference into headers 2021-06-13 06:58:48 +03:00
Peter Dimov
75d5287558 Update copyright 2021-06-13 05:59:04 +03:00
Peter Dimov
25eaf0fdae Document comparisons as inline friends; use value() and category() instead of val_ and cat_; add subheadings 2021-06-13 05:58:16 +03:00
Peter Dimov
f43293f451 Increase ToC levels 2021-06-13 05:24:30 +03:00
Peter Dimov
88f7c2bf53 Revert "Update documentation"
This reverts commit 8962c9101a.
2021-06-13 04:47:19 +03:00
Peter Dimov
723daf5d57 Update changelog 2021-06-13 04:39:39 +03:00
Peter Dimov
3d4c31c213 Update test/Jamfile 2021-06-13 01:13:48 +03:00
Peter Dimov
c069ae048f Update Travis to use undefined-sanitizer; disable failed_constexpr_test 2021-06-13 01:08:54 +03:00
Peter Dimov
28e1b919ac Disable failing test 2021-06-12 22:36:12 +03:00
Peter Dimov
b20191f8d7 Disable failing tests on g++-7/c++17 2021-06-12 22:20:38 +03:00
Peter Dimov
d019c1cdae Remove detail/is_generic_value.hpp 2021-06-12 22:01:16 +03:00
Peter Dimov
ff77d4c094 Do not call generic_category() in system_error_category 2021-06-12 21:59:22 +03:00
Peter Dimov
a21a3050a5 Use nullptr for &generic_category() in error_condition 2021-06-12 21:51:51 +03:00
Peter Dimov
08d62ac444 Restore Sun workaround 2021-06-12 05:42:03 +03:00
Peter Dimov
45e9dfeba9 Declare operator std::error_category as BOOST_SYMBOL_VISIBLE 2021-06-12 05:12:58 +03:00
Peter Dimov
7d9eb384c6 Make error_category comparisons inline friends, to avoid clang 'member call on mutable' constexpr errors 2021-06-12 04:52:21 +03:00
Peter Dimov
04bfb05b19 Improve the implementation of the std::category conversion 2021-06-12 04:29:13 +03:00
16 changed files with 539 additions and 450 deletions

View File

@@ -206,7 +206,7 @@ install:
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}
- ./b2 -j3 libs/system/test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${UBSAN:+undefined-sanitizer=norecover define=UBSAN=1 debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}
notifications:
email:

View File

@@ -10,7 +10,7 @@ http://www.boost.org/LICENSE_1_0.txt
# Boost.System: Extensible Error Reporting
Beman Dawes, Christopher Kohlhoff, Peter Dimov
:toc: left
:toclevels: 3
:toclevels: 4
:idprefix:
:docinfo: private-footer

View File

@@ -1,5 +1,5 @@
////
Copyright 2018 Peter Dimov
Copyright 2018-2021 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
@@ -11,6 +11,27 @@ http://www.boost.org/LICENSE_1_0.txt
# Revision History
:idprefix:
## Changes in Boost 1.77
* The conversion operator from `error_category` to `std::error_category`
has been improved and no longer requires `<map>` or `<mutex>`.
* The comparison operators of `error_category` are now inline friends
instead of member functions (a side effect of the previous change.)
* `error_condition` now defers calling `generic_category()` to avoid
instantiating the object until it's actually needed.
* `error_condition::failed` and `error_condition::message` have been
undeprecated, and `operator bool()` now once again returns `failed()`.
* The system category now doesn't call `generic_category()`, to avoid
instantiating the object.
* The return value of `default_error_condition` changes in some cases into
an `error_condition` from the generic category, instead of from the system
category. This happens on POSIX when the input `error_code` is from
the system category and does not correspond to any `errc_t` value.
## Changes in Boost 1.76
* `windows_error.hpp` is no longer deprecated.
## Changes in Boost 1.75
* The platform-specific headers `windows_error.hpp`, `linux_error.hpp`,

View File

@@ -1,5 +1,5 @@
////
Copyright 2018 Peter Dimov
Copyright 2018-2021 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
@@ -14,6 +14,6 @@ http://www.boost.org/LICENSE_1_0.txt
This documentation is
* Copyright 2003-2017 Beman Dawes
* Copyright 2018 Peter Dimov
* Copyright 2018-2021 Peter Dimov
and is distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].

View File

@@ -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.
@@ -48,31 +48,53 @@ the old names, but will provide them when the macro `BOOST_SYSTEM_ENABLE_DEPRECA
|`native_ecat`|`system_category()`
|===
## <boost/system/error_code.hpp>
## <boost/system/{zwsp}is_error_code_enum.hpp>
### Synopsis
### is_error_code_enum
```
namespace boost {
namespace system {
class error_category;
constexpr const error_category & system_category() noexcept;
constexpr const error_category & generic_category() noexcept;
class error_code;
class error_condition;
// "Concept" helpers
template<class T>
struct is_error_code_enum { static const bool value = false; };
} // namespace system
} // namespace boost
```
Users may specialize `is_error_code_enum` for their error enumeration
types to indicate that they should be eligible for automatic conversions
to `error_code`. This conversion calls `make_error_code(e)`, which should
be provided in the same namespace as the enumeration type.
## <boost/system/{zwsp}is_error_condition_enum.hpp>
### is_error_condition_enum
```
namespace boost {
namespace system {
template<class T>
struct is_error_condition_enum { static const bool value = false; };
// generic error conditions
} // namespace system
} // namespace boost
```
Users may specialize `is_error_condition_enum` for their error enumeration
types to indicate that they should be eligible for automatic conversions
to `error_condition`. This conversion calls `make_error_condition(e)`, which
should be provided in the same namespace as the enumeration type.
## <boost/system/{zwsp}errc.hpp>
### errc
```
namespace boost {
namespace system {
namespace errc {
enum errc_t
@@ -163,52 +185,80 @@ namespace boost {
template<> struct is_error_condition_enum<errc::errc_t>
{ static const bool value = true; };
// non-member functions
constexpr bool operator==( const error_code & lhs,
const error_code & rhs ) noexcept;
bool operator==( const error_code & code,
const error_condition & condition ) noexcept;
bool operator==( const error_condition & condition,
const error_code & code ) noexcept;
constexpr bool operator==( const error_condition & lhs,
const error_condition & rhs ) noexcept;
constexpr bool operator!=( const error_code & lhs,
const error_code & rhs ) noexcept;
bool operator!=( const error_code & code,
const error_condition & condition ) noexcept;
bool operator!=( const error_condition & condition,
const error_code & code ) noexcept;
constexpr bool operator!=( const error_condition & lhs,
const error_condition & rhs ) noexcept;
constexpr bool operator<( const error_code & lhs,
const error_code & rhs ) noexcept;
constexpr bool operator<( const error_condition & lhs,
const error_condition & rhs ) noexcept;
constexpr error_code make_error_code( errc::errc_t e ) noexcept;
constexpr error_condition make_error_condition( errc::errc_t e ) noexcept;
template <class charT, class traits>
std::basic_ostream<charT, traits>&
operator<<( basic_ostream<charT, traits>& os, const error_code & ec );
std::size_t hash_value( const error_code & ec );
} // namespace system
} // namespace boost
```
The value of each `errc_t` constant is the same as the value of the `<cerrno>`
macro shown in the above synopsis.
The predefined enumeration type `errc::errc_t` provides named constants
corresponding to the values of the `<cerrno>` macros.
Users may specialize `is_error_code_enum` and `is_error_condition_enum`
templates to indicate that a type is eligible for class `error_code` and
`error_condition` automatic conversions respectively.
```
constexpr error_condition make_error_condition( errc::errc_t e ) noexcept;
```
[none]
* {blank}
+
Returns: :: `error_condition( e, generic_category() )`.
### Class error_category
Since `errc::errc_t` provides a specialization of `is_error_condition_enum`
and an overload of `make_error_condition`, it can be converted implicitly to
an `error_condition`. This is typically useful when comparing `error_code`
values returned from APIs to a portable condition, as in the below example:
* {blank}
+
```
void api_function( boost::system::error_code& ec );
void my_function()
{
boost::system::error_code ec;
api_function( ec );
if( ec == boost::system::errc::no_such_file_or_directory )
{
// an entity wasn't found (ENOENT)
// handle this condition
}
}
```
```
constexpr error_code make_error_code( errc::errc_t e ) noexcept;
```
[none]
* {blank}
+
Returns: :: `error_code( e, generic_category() )`.
In addition to `make_error_condition`, `errc::errc_t` provides an overload of
`make_error_code`. This allows the creation of generic error codes, an
operation typically useful when a function needs to signal a generic failure
that does not come from an underlying API, such as for instance an out of
memory condition:
* {blank}
+
```
void my_api_function( boost::system::error_code& ec )
{
void* p = std::malloc( 16 );
if( p == 0 )
{
// return ENOMEM
ec = make_error_code( boost::system::errc::out_of_memory );
return;
}
// use p
}
```
## <boost/system/{zwsp}error_category.hpp>
### error_category
The class `error_category` defines the base class for types used
to identify the source and encoding of a particular category of error code.
@@ -251,9 +301,13 @@ namespace boost {
virtual bool failed( int ev ) const noexcept;
constexpr bool operator==( const error_category & rhs ) const noexcept;
constexpr bool operator!=( const error_category & rhs ) const noexcept;
constexpr bool operator< ( const error_category & rhs ) const noexcept;
friend constexpr bool operator==( const error_category & lhs,
const error_category & rhs ) noexcept;
friend constexpr bool operator!=( const error_category & lhs,
const error_category & rhs ) noexcept;
friend constexpr bool operator< ( const error_category & lhs,
const error_category & rhs ) noexcept;
operator std::error_category const & () const;
@@ -397,37 +451,42 @@ Returns: ::
Remarks: ::
All calls to this function with the same `ev` must return the same value.
#### Nonvirtuals
#### Comparisons
```
constexpr bool operator==( const error_category & rhs ) const noexcept;
friend constexpr bool operator==( const error_category & lhs,
const error_category & rhs ) noexcept;
```
[none]
* {blank}
+
Returns: :: `rhs.id_ == 0? this == &rhs: id_ == rhs.id_`.
Remarks: :: Two category objects are considered equivalent when they have matching
nonzero identifiers, or are the same object.
Returns: :: `rhs.id_ == 0? &lhs == &rhs: lhs.id_ == rhs.id_`.
Remarks: :: Two category objects are considered equivalent when they have
matching nonzero identifiers, or are the same object.
```
constexpr bool operator!=( const error_category & rhs ) const noexcept;
friend constexpr bool operator!=( const error_category & lhs,
const error_category & rhs ) noexcept;
```
[none]
* {blank}
+
Returns: :: `!( *this == rhs )`.
Returns: :: `!( lhs == rhs )`.
```
constexpr bool operator< ( const error_category & rhs ) const noexcept;
constexpr bool operator< ( const error_category & lhs,
const error_category & rhs ) const noexcept;
```
[none]
* {blank}
+
Returns: ::
** If `id_ < rhs.id_`, `true`;
** Otherwise, if `id_ > rhs.id_`, `false`;
** If `lhs.id_ < rhs.id_`, `true`;
** Otherwise, if `lhs.id_ > rhs.id_`, `false`;
** Otherwise, if `rhs.id_ != 0`, `false`;
** Otherwise, `std::less<error_category const *>()( this, &rhs )`.
** Otherwise, `std::less<error_category const *>()( &lhs, &rhs )`.
#### Conversions
```
operator std::error_category const & () const;
@@ -438,7 +497,19 @@ operator std::error_category const & () const;
Returns: :: A reference to an `std::error_category` object corresponding
to `*this`.
### Predefined Categories
## <boost/system/{zwsp}system_category.hpp>
### system_category
```
namespace boost {
namespace system {
constexpr const error_category & system_category() noexcept;
} // namespace system
} // namespace boost
```
```
constexpr const error_category & system_category() noexcept;
@@ -446,8 +517,22 @@ constexpr const error_category & system_category() noexcept;
[none]
* {blank}
+
Returns: :: A reference to an `error_category` object identifying errors
originating from the operating system.
Returns: :: A reference to a predefined `error_category` object identifying
errors originating from the operating system.
## <boost/system/{zwsp}generic_category.hpp>
### generic_category
```
namespace boost {
namespace system {
constexpr const error_category & generic_category() noexcept;
} // namespace system
} // namespace boost
```
```
constexpr const error_category & generic_category() noexcept;
@@ -455,10 +540,12 @@ constexpr const error_category & generic_category() noexcept;
[none]
* {blank}
+
Returns: :: A reference to an `error_category` object identifying portable
error conditions.
Returns: :: A reference to a predefined `error_category` object identifying
portable error codes and conditions.
### Class error_code
## <boost/system/{zwsp}error_code.hpp>
### error_code
The class `error_code` describes an object used to hold error code
values, such as those originating from the operating system or other
@@ -502,14 +589,39 @@ namespace boost {
constexpr bool failed() const noexcept;
constexpr explicit operator bool() const noexcept;
// comparisons:
friend constexpr bool operator==( const error_code & lhs,
const error_code & rhs ) noexcept;
friend constexpr bool operator!=( const error_code & lhs,
const error_code & rhs ) noexcept;
friend constexpr bool operator<( const error_code & lhs,
const error_code & rhs ) noexcept;
// conversions:
operator std::error_code() const;
private: // exposition only
int val_;
const error_category * cat_;
};
// non-member functions
bool operator==( const error_code & code,
const error_condition & condition ) noexcept;
bool operator==( const error_condition & condition,
const error_code & code ) noexcept;
bool operator!=( const error_code & code,
const error_condition & condition ) noexcept;
bool operator!=( const error_condition & condition,
const error_code & code ) noexcept;
template <class charT, class traits>
std::basic_ostream<charT, traits>&
operator<<( basic_ostream<charT, traits>& os, const error_code & ec );
std::size_t hash_value( const error_code & ec );
}
}
```
@@ -522,7 +634,7 @@ constexpr error_code() noexcept;
[none]
* {blank}
+
Ensures: :: `val_ == 0`; `*cat_ == system_category()`.
Ensures: :: `value() == 0`; `category() == system_category()`.
```
constexpr error_code( int val, const error_category & cat ) noexcept;
@@ -530,7 +642,7 @@ constexpr error_code( int val, const error_category & cat ) noexcept;
[none]
* {blank}
+
Ensures: :: `val_ == val`; `cat_ == &cat`.
Ensures: :: `value() == val`; `category() == cat`.
```
template <class ErrorCodeEnum>
@@ -550,7 +662,7 @@ constexpr void assign( int val, const error_category & cat ) noexcept;
[none]
* {blank}
+
Ensures: :: `val_ == val`; `cat_ == &cat`.
Ensures: :: `value() == val`; `category() == cat`.
```
template<typename ErrorCodeEnum>
@@ -569,7 +681,7 @@ constexpr void clear() noexcept;
* {blank}
+
Ensures: ::
`val_ == 0`; `*cat_ == system_category()`.
`value() == 0`; `category() == system_category()`.
#### Observers
@@ -579,7 +691,7 @@ constexpr int value() const noexcept;
[none]
* {blank}
+
Returns: :: `val_`.
Returns: :: the error value.
```
constexpr const error_category & category() const noexcept;
@@ -587,7 +699,7 @@ constexpr const error_category & category() const noexcept;
[none]
* {blank}
+
Returns: :: `*cat_`.
Returns: :: the error category.
```
error_condition default_error_condition() const noexcept;
@@ -595,7 +707,7 @@ error_condition default_error_condition() const noexcept;
[none]
* {blank}
+
Returns: :: `cat_\->default_error_condition( val_ )`.
Returns: :: `category().default_error_condition( value() )`.
```
std::string message() const;
@@ -603,7 +715,7 @@ std::string message() const;
[none]
* {blank}
+
Returns: :: `cat_\->message( val_ )`.
Returns: :: `category().message( value() )`.
```
char const * message( char * buffer, std::size_t len ) const noexcept;
@@ -611,7 +723,7 @@ char const * message( char * buffer, std::size_t len ) const noexcept;
[none]
* {blank}
+
Returns: :: `cat_\->message( val_, buffer, len )`.
Returns: :: `category().message( value(), buffer, len )`.
```
constexpr bool failed() const noexcept;
@@ -619,7 +731,7 @@ constexpr bool failed() const noexcept;
[none]
* {blank}
+
Returns: :: `cat_\->failed( val_ )`.
Returns: :: `category().failed( value() )`.
```
constexpr explicit operator bool() const noexcept;
@@ -627,7 +739,40 @@ constexpr explicit operator bool() const noexcept;
[none]
* {blank}
+
Returns: :: `failed()`.
Returns: ::
`failed()`.
#### Comparisons
```
friend constexpr bool operator==( const error_code & lhs,
const error_code & rhs ) noexcept;
```
[none]
* {blank}
+
Returns: :: `lhs.value() == rhs.value() && lhs.category() == rhs.category()`.
```
friend constexpr bool operator!=( const error_code & lhs,
const error_code & rhs ) noexcept;
```
[none]
* {blank}
+
Returns: :: `!( lhs == rhs )`.
```
friend constexpr bool operator<( const error_code & lhs,
const error_code & rhs ) noexcept;
```
[none]
* {blank}
+
Returns: ::
`lhs.category() < rhs.category() || (lhs.category() == rhs.category() && lhs.value() < rhs.value())`.
#### Conversions
```
operator std::error_code() const;
@@ -636,9 +781,55 @@ operator std::error_code() const;
* {blank}
+
Returns: ::
`std::error_code( val_, *cat_ )`.
`std::error_code( value(), category() )`.
### Class error_condition
#### Nonmembers
```
bool operator==( const error_code & code,
const error_condition & condition ) noexcept;
bool operator==( const error_condition & condition,
const error_code & code ) noexcept;
```
[none]
* {blank}
+
Returns: :: `code.category().equivalent(code.value(), condition) || condition.category().equivalent(code, condition.value())`.
```
bool operator!=( const error_code & code,
const error_condition & condition ) noexcept;
bool operator!=( const error_condition & condition,
const error_code & code ) noexcept;
```
[none]
* {blank}
+
Returns: :: `!( lhs == rhs )`.
```
template <class charT, class traits>
std::basic_ostream<charT, traits>&
operator<<( basic_ostream<charT, traits>& os, const error_code & ec );
```
[none]
* {blank}
+
Effects: :: `os << ec.category().name() << ':' << ec.value()`.
Returns: :: `os`.
```
std::size_t hash_value( const error_code & ec );
```
[none]
* {blank}
+
Returns: ::
A hash value representing `ec`.
## <boost/system/{zwsp}error_condition.hpp>
### error_condition
```
namespace boost {
@@ -670,21 +861,24 @@ namespace boost {
constexpr const error_category & category() const noexcept;
std::string message() const;
char const * message( char * buffer, std::size_t len ) const noexcept;
constexpr bool failed() const noexcept;
constexpr explicit operator bool() const noexcept;
// comparisons:
friend constexpr bool operator==( const error_condition & lhs,
const error_condition & rhs ) noexcept;
friend constexpr bool operator!=( const error_condition & lhs,
const error_condition & rhs ) noexcept;
friend constexpr bool operator<( const error_condition & lhs,
const error_condition & rhs ) noexcept;
// conversions:
operator std::error_condition() const;
// deprecated members; do not use
char const * message( char * buffer, std::size_t len ) const noexcept;
constexpr bool failed() const noexcept;
private: // exposition only
int val_;
const error_category * cat_;
};
}
}
@@ -698,7 +892,7 @@ constexpr error_condition() noexcept;
[none]
* {blank}
+
Ensures: :: `val_ == 0`; `*cat_ == generic_category()`.
Ensures: :: `value() == 0`; `category() == generic_category()`.
```
constexpr error_condition( int val, const error_category & cat ) noexcept;
@@ -706,7 +900,7 @@ constexpr error_condition( int val, const error_category & cat ) noexcept;
[none]
* {blank}
+
Ensures: :: `val_ == val`; `cat_ == &cat`.
Ensures: :: `value() == val`; `category() == cat`.
```
template <class ErrorConditionEnum>
@@ -727,7 +921,7 @@ constexpr void assign( int val, const error_category & cat ) noexcept;
[none]
* {blank}
+
Ensures: :: `val_ == val`; `cat_ == &cat`.
Ensures: :: `value() == val`; `category() == cat`.
```
template <class ErrorConditionEnum>
@@ -746,7 +940,7 @@ constexpr void clear() noexcept;
* {blank}
+
Ensures: ::
`val_ == 0`; `*cat_ == generic_category()`.
`value() == 0`; `category() == generic_category()`.
#### Observers
@@ -756,7 +950,7 @@ constexpr int value() const noexcept;
[none]
* {blank}
+
Returns: :: `val_`.
Returns: :: the error value.
```
constexpr const error_category & category() const noexcept;
@@ -764,7 +958,7 @@ constexpr const error_category & category() const noexcept;
[none]
* {blank}
+
Returns: :: `*cat_`.
Returns: :: the error category.
```
std::string message() const;
@@ -772,26 +966,7 @@ std::string message() const;
[none]
* {blank}
+
Returns: :: `cat_\->message( val_ )`.
```
constexpr explicit operator bool() const noexcept;
```
[none]
* {blank}
+
Returns: :: `value() != 0`.
```
operator std::error_condition() const;
```
[none]
* {blank}
+
Returns: ::
`std::error_condition( val_, *cat_ )`.
#### Deprecated members
Returns: :: `category().message( value() )`.
```
char const * message( char * buffer, std::size_t len ) const noexcept;
@@ -799,12 +974,7 @@ char const * message( char * buffer, std::size_t len ) const noexcept;
[none]
* {blank}
+
Returns: :: `cat_\->message( val_, buffer, len )`.
WARNING: This member function is deprecated and will be removed. This is done
for compatibility with `std::error_condition` as the next release is
expected to improve interoperability with `<system_error>` even further.
_Note that this does not affect_ `error_code::message`.
Returns: :: `category().message( value(), buffer, len )`.
```
constexpr bool failed() const noexcept;
@@ -812,19 +982,21 @@ constexpr bool failed() const noexcept;
[none]
* {blank}
+
Returns: :: `cat_\->failed( val_ )`.
WARNING: This member function is deprecated and will be removed. This is done
for compatibility with `std::error_condition` as the next release is
expected to improve interoperability with `<system_error>` even further.
_Note that this does not affect_ `error_code::failed`.
### Nonmember functions
Returns: :: `category().failed( value() )`.
```
constexpr bool operator==( const error_code & lhs,
const error_code & rhs ) noexcept;
constexpr bool operator==( const error_condition & lhs,
constexpr explicit operator bool() const noexcept;
```
[none]
* {blank}
+
Returns: ::
`failed()`.
#### Comparisons
```
friend constexpr bool operator==( const error_condition & lhs,
const error_condition & rhs ) noexcept;
```
[none]
@@ -833,25 +1005,8 @@ constexpr bool operator==( const error_condition & lhs,
Returns: :: `lhs.value() == rhs.value() && lhs.category() == rhs.category()`.
```
bool operator==( const error_code & code,
const error_condition & condition ) noexcept;
bool operator==( const error_condition & condition,
const error_code & code ) noexcept;
```
[none]
* {blank}
+
Returns: :: `code.category().equivalent( code.value(), condition ) || condition.category().equivalent( code, condition.value() )`.
```
constexpr bool operator!=( const error_code & lhs,
const error_code & rhs ) noexcept;
constexpr bool operator!=( const error_condition & lhs,
friend constexpr bool operator!=( const error_condition & lhs,
const error_condition & rhs ) noexcept;
bool operator!=( const error_code & code,
const error_condition & condition ) noexcept;
bool operator!=( const error_condition & condition,
const error_code & code ) noexcept;
```
[none]
* {blank}
@@ -859,53 +1014,27 @@ bool operator!=( const error_condition & condition,
Returns: :: `!( lhs == rhs )`.
```
constexpr bool operator<( const error_code & lhs,
const error_code & rhs ) noexcept;
constexpr bool operator<( const error_condition & lhs,
friend constexpr bool operator<( const error_condition & lhs,
const error_condition & rhs ) noexcept;
```
[none]
* {blank}
+
Returns: :: `lhs.category() < rhs.category() || ( lhs.category() == rhs.category() && lhs.value() < rhs.value() )`.
Returns: ::
`lhs.category() < rhs.category() || (lhs.category() == rhs.category() && lhs.value() < rhs.value())`.
#### Conversions
```
constexpr error_code make_error_code( errc::errc_t e ) noexcept;
```
[none]
* {blank}
+
Returns: :: `error_code( e, generic_category() )`.
```
constexpr error_condition make_error_condition( errc::errc_t e ) noexcept;
```
[none]
* {blank}
+
Returns: :: `error_condition( e, generic_category() )`.
```
template <class charT, class traits>
std::basic_ostream<charT, traits>&
operator<<( basic_ostream<charT, traits>& os, const error_code & ec );
```
[none]
* {blank}
+
Effects: :: `os << ec.category().name() << ':' << ec.value()`.
Returns: :: `os`.
```
std::size_t hash_value( const error_code & ec );
operator std::error_condition() const;
```
[none]
* {blank}
+
Returns: ::
A hash value representing `ec`.
`std::error_condition( value(), category() )`.
## <boost/system/system_error.hpp>
## <boost/system/{zwsp}system_error.hpp>
### Class system_error
@@ -982,4 +1111,8 @@ const char * what() const noexcept;
* {blank}
+
Returns: :: A null-terminated character string incorporating the arguments supplied
in the constructor, typically of the form `what_arg + ": " + code.message()`.
in the constructor, typically of the form `what_arg + ": " + code().message()`.
## <boost/system.hpp>
This convenience header includes all the headers previously described.

View File

@@ -13,20 +13,10 @@
// BOOST_SYSTEM_HAS_SYSTEM_ERROR
#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR) && !defined(BOOST_NO_CXX11_HDR_ATOMIC)
# define BOOST_SYSTEM_HAS_SYSTEM_ERROR
#endif
#if BOOST_WORKAROUND(BOOST_GCC, < 40600)
// g++ 4.4's <map> is not good enough
# undef BOOST_SYSTEM_HAS_SYSTEM_ERROR
#endif
#if defined(BOOST_NO_CXX11_HDR_MUTEX)
// Required for thread-safe map manipulation
# undef BOOST_SYSTEM_HAS_SYSTEM_ERROR
#endif
// BOOST_SYSTEM_NOEXCEPT
// Retained for backward compatibility

View File

@@ -19,6 +19,7 @@
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
# include <system_error>
# include <atomic>
#endif
namespace boost
@@ -38,11 +39,7 @@ namespace detail
BOOST_SYSTEM_CONSTEXPR bool failed_impl( int ev, error_category const & cat );
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
std::error_category const & to_std_category( error_category const & cat );
#endif
class std_category;
} // namespace detail
@@ -58,10 +55,6 @@ private:
friend std::size_t hash_value( error_code const & ec );
friend BOOST_SYSTEM_CONSTEXPR bool detail::failed_impl( int ev, error_category const & cat );
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
friend std::error_category const & detail::to_std_category( error_category const & cat );
#endif
#if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS)
public:
@@ -80,6 +73,16 @@ private:
boost::ulong_long_type id_;
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
mutable std::atomic< boost::system::detail::std_category* > ps_;
#else
boost::system::detail::std_category* ps_;
#endif
protected:
#if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) && !defined(BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS)
@@ -97,11 +100,11 @@ protected:
#endif
BOOST_SYSTEM_CONSTEXPR error_category() BOOST_NOEXCEPT: id_( 0 )
BOOST_SYSTEM_CONSTEXPR error_category() BOOST_NOEXCEPT: id_( 0 ), ps_()
{
}
explicit BOOST_SYSTEM_CONSTEXPR error_category( boost::ulong_long_type id ) BOOST_NOEXCEPT: id_( id )
explicit BOOST_SYSTEM_CONSTEXPR error_category( boost::ulong_long_type id ) BOOST_NOEXCEPT: id_( id ), ps_()
{
}
@@ -121,24 +124,24 @@ public:
return ev != 0;
}
BOOST_SYSTEM_CONSTEXPR bool operator==( const error_category & rhs ) const BOOST_NOEXCEPT
friend BOOST_SYSTEM_CONSTEXPR bool operator==( error_category const & lhs, error_category const & rhs ) BOOST_NOEXCEPT
{
return rhs.id_ == 0? this == &rhs: id_ == rhs.id_;
return rhs.id_ == 0? &lhs == &rhs: lhs.id_ == rhs.id_;
}
BOOST_SYSTEM_CONSTEXPR bool operator!=( const error_category & rhs ) const BOOST_NOEXCEPT
friend BOOST_SYSTEM_CONSTEXPR bool operator!=( error_category const & lhs, error_category const & rhs ) BOOST_NOEXCEPT
{
return !( *this == rhs );
return !( lhs == rhs );
}
BOOST_SYSTEM_CONSTEXPR bool operator<( const error_category & rhs ) const BOOST_NOEXCEPT
friend BOOST_SYSTEM_CONSTEXPR bool operator<( error_category const & lhs, error_category const & rhs ) BOOST_NOEXCEPT
{
if( id_ < rhs.id_ )
if( lhs.id_ < rhs.id_ )
{
return true;
}
if( id_ > rhs.id_ )
if( lhs.id_ > rhs.id_ )
{
return false;
}
@@ -148,13 +151,15 @@ public:
return false; // equal
}
return std::less<error_category const *>()( this, &rhs );
return std::less<error_category const *>()( &lhs, &rhs );
}
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
# if defined(__SUNPRO_CC) // trailing __global is not supported
operator std::error_category const & () const;
# else
operator std::error_category const & () const BOOST_SYMBOL_VISIBLE;
# endif
#endif
};

View File

@@ -96,11 +96,40 @@ inline char const * error_category::message( int ev, char * buffer, std::size_t
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
#include <boost/system/detail/to_std_category.hpp>
#include <boost/system/detail/std_category.hpp>
inline boost::system::error_category::operator std::error_category const & () const
{
return boost::system::detail::to_std_category( *this );
if( id_ == boost::system::detail::system_category_id )
{
static const boost::system::detail::std_category system_instance( this, 0x1F4D7 );
return system_instance;
}
if( id_ == boost::system::detail::generic_category_id )
{
static const boost::system::detail::std_category generic_instance( this, 0x1F4D3 );
return generic_instance;
}
boost::system::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 );
if( ps_.compare_exchange_strong( p, q, std::memory_order_release, std::memory_order_acquire ) )
{
return *q;
}
else
{
delete q;
return *p;
}
}
#endif // #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)

View File

@@ -13,6 +13,8 @@
#include <boost/system/detail/error_category.hpp>
#include <boost/system/detail/generic_category.hpp>
#include <boost/system/detail/enable_if.hpp>
#include <boost/system/detail/is_same.hpp>
#include <boost/system/detail/errc.hpp>
#include <boost/system/is_error_condition_enum.hpp>
#include <boost/system/detail/config.hpp>
#include <boost/config.hpp>
@@ -27,6 +29,17 @@ namespace system
// error_conditions are portable, error_codes are system or library specific
namespace detail
{
struct generic_value_tag
{
int value;
BOOST_SYSTEM_CONSTEXPR explicit generic_value_tag( int v ): value( v ) {}
};
} // namespace detail
class error_condition
{
private:
@@ -39,7 +52,7 @@ public:
// constructors:
BOOST_SYSTEM_CONSTEXPR error_condition() BOOST_NOEXCEPT:
val_( 0 ), cat_( &generic_category() )
val_( 0 ), cat_( 0 )
{
}
@@ -48,12 +61,25 @@ public:
{
}
BOOST_SYSTEM_CONSTEXPR explicit error_condition( boost::system::detail::generic_value_tag vt ) BOOST_NOEXCEPT:
val_( vt.value ), cat_( 0 )
{
}
template<class ErrorConditionEnum> BOOST_SYSTEM_CONSTEXPR error_condition( ErrorConditionEnum e,
typename detail::enable_if<is_error_condition_enum<ErrorConditionEnum>::value>::type* = 0) BOOST_NOEXCEPT
typename detail::enable_if<
is_error_condition_enum<ErrorConditionEnum>::value && !boost::system::detail::is_same<ErrorConditionEnum, errc::errc_t>::value
>::type* = 0) BOOST_NOEXCEPT
{
*this = make_error_condition( e );
}
template<class ErrorConditionEnum> BOOST_SYSTEM_CONSTEXPR error_condition( ErrorConditionEnum e,
typename detail::enable_if<boost::system::detail::is_same<ErrorConditionEnum, errc::errc_t>::value>::type* = 0) BOOST_NOEXCEPT:
val_( e ), cat_( 0 )
{
}
// modifiers:
BOOST_SYSTEM_CONSTEXPR void assign( int val, const error_category & cat ) BOOST_NOEXCEPT
@@ -66,14 +92,14 @@ public:
BOOST_SYSTEM_CONSTEXPR typename detail::enable_if<is_error_condition_enum<ErrorConditionEnum>::value, error_condition>::type &
operator=( ErrorConditionEnum val ) BOOST_NOEXCEPT
{
*this = make_error_condition( val );
*this = error_condition( val );
return *this;
}
BOOST_SYSTEM_CONSTEXPR void clear() BOOST_NOEXCEPT
{
val_ = 0;
cat_ = &generic_category();
cat_ = 0;
}
// observers:
@@ -85,29 +111,50 @@ public:
BOOST_SYSTEM_CONSTEXPR const error_category & category() const BOOST_NOEXCEPT
{
return *cat_;
return cat_? *cat_: generic_category();
}
std::string message() const
{
return cat_->message( value() );
if( cat_ )
{
return cat_->message( value() );
}
else
{
return generic_category().message( value() );
}
}
BOOST_SYSTEM_DEPRECATED("this function is slated for removal") char const * message( char * buffer, std::size_t len ) const BOOST_NOEXCEPT
char const * message( char * buffer, std::size_t len ) const BOOST_NOEXCEPT
{
return cat_->message( value(), buffer, len );
if( cat_ )
{
return cat_->message( value(), buffer, len );
}
else
{
return generic_category().message( value(), buffer, len );
}
}
BOOST_SYSTEM_DEPRECATED("this function is slated for removal") BOOST_SYSTEM_CONSTEXPR bool failed() const BOOST_NOEXCEPT
BOOST_SYSTEM_CONSTEXPR bool failed() const BOOST_NOEXCEPT
{
return detail::failed_impl( val_, *cat_ );
if( cat_ )
{
return detail::failed_impl( val_, *cat_ );
}
else
{
return val_ != 0;
}
}
#if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
BOOST_SYSTEM_CONSTEXPR explicit operator bool() const BOOST_NOEXCEPT // true if error
{
return val_ != 0;
return failed();
}
#else
@@ -117,12 +164,12 @@ public:
BOOST_SYSTEM_CONSTEXPR operator unspecified_bool_type() const BOOST_NOEXCEPT // true if error
{
return val_ != 0? unspecified_bool_true: 0;
return failed()? unspecified_bool_true: 0;
}
BOOST_SYSTEM_CONSTEXPR bool operator!() const BOOST_NOEXCEPT // true if no error
{
return val_ == 0;
return !failed();
}
#endif
@@ -133,12 +180,19 @@ public:
BOOST_SYSTEM_CONSTEXPR inline friend bool operator==( const error_condition & lhs, const error_condition & rhs ) BOOST_NOEXCEPT
{
return lhs.val_ == rhs.val_ && *lhs.cat_ == *rhs.cat_;
return lhs.val_ == rhs.val_ && lhs.category() == rhs.category();
}
BOOST_SYSTEM_CONSTEXPR inline friend bool operator<( const error_condition & lhs, const error_condition & rhs ) BOOST_NOEXCEPT
{
return *lhs.cat_ < *rhs.cat_ || ( *lhs.cat_ == *rhs.cat_ && lhs.val_ < rhs.val_ );
error_category const& lcat = lhs.category();
error_category const& rcat = rhs.category();
return lcat < rcat || ( lcat == rcat && lhs.val_ < rhs.val_ );
}
BOOST_SYSTEM_CONSTEXPR inline friend bool operator!=( const error_condition & lhs, const error_condition & rhs ) BOOST_NOEXCEPT
{
return !( lhs == rhs );
}
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
@@ -151,11 +205,6 @@ public:
#endif
};
BOOST_SYSTEM_CONSTEXPR inline bool operator!=( const error_condition & lhs, const error_condition & rhs ) BOOST_NOEXCEPT
{
return !( lhs == rhs );
}
} // namespace system
} // namespace boost

View File

@@ -1,125 +0,0 @@
#ifndef BOOST_SYSTEM_DETAIL_IS_GENERIC_VALUE_HPP_INCLUDED
#define BOOST_SYSTEM_DETAIL_IS_GENERIC_VALUE_HPP_INCLUDED
// Copyright 2018 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/detail/errc.hpp>
namespace boost
{
namespace system
{
namespace detail
{
inline bool is_generic_value( int ev ) BOOST_NOEXCEPT
{
using namespace errc;
static int const gen[] =
{
success,
address_family_not_supported,
address_in_use,
address_not_available,
already_connected,
argument_list_too_long,
argument_out_of_domain,
bad_address,
bad_file_descriptor,
bad_message,
broken_pipe,
connection_aborted,
connection_already_in_progress,
connection_refused,
connection_reset,
cross_device_link,
destination_address_required,
device_or_resource_busy,
directory_not_empty,
executable_format_error,
file_exists,
file_too_large,
filename_too_long,
function_not_supported,
host_unreachable,
identifier_removed,
illegal_byte_sequence,
inappropriate_io_control_operation,
interrupted,
invalid_argument,
invalid_seek,
io_error,
is_a_directory,
message_size,
network_down,
network_reset,
network_unreachable,
no_buffer_space,
no_child_process,
no_link,
no_lock_available,
no_message_available,
no_message,
no_protocol_option,
no_space_on_device,
no_stream_resources,
no_such_device_or_address,
no_such_device,
no_such_file_or_directory,
no_such_process,
not_a_directory,
not_a_socket,
not_a_stream,
not_connected,
not_enough_memory,
not_supported,
operation_canceled,
operation_in_progress,
operation_not_permitted,
operation_not_supported,
operation_would_block,
owner_dead,
permission_denied,
protocol_error,
protocol_not_supported,
read_only_file_system,
resource_deadlock_would_occur,
resource_unavailable_try_again,
result_out_of_range,
state_not_recoverable,
stream_timeout,
text_file_busy,
timed_out,
too_many_files_open_in_system,
too_many_files_open,
too_many_links,
too_many_symbolic_link_levels,
value_too_large,
wrong_protocol_type
};
int const n = sizeof( gen ) / sizeof( gen[0] );
for( int i = 0; i < n; ++i )
{
if( ev == gen[ i ] ) return true;
}
return false;
}
} // namespace detail
} // namespace system
} // namespace boost
#endif // #ifndef BOOST_SYSTEM_DETAIL_IS_GENERIC_VALUE_HPP_INCLUDED

View File

@@ -0,0 +1,33 @@
#ifndef BOOST_SYSTEM_DETAIL_IS_SAME_HPP_INCLUDED
#define BOOST_SYSTEM_DETAIL_IS_SAME_HPP_INCLUDED
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0
// http://www.boost.org/LICENSE_1_0.txt
namespace boost
{
namespace system
{
namespace detail
{
template<class T1, class T2> struct is_same
{
enum _vt { value = 0 };
};
template<class T> struct is_same<T, T>
{
enum _vt { value = 1 };
};
} // namespace detail
} // namespace system
} // namespace boost
#endif // #ifndef BOOST_SYSTEM_DETAIL_IS_SAME_HPP_INCLUDED

View File

@@ -1,9 +1,9 @@
#ifndef BOOST_SYSTEM_DETAIL_TO_STD_CATEGORY_HPP_INCLUDED
#define BOOST_SYSTEM_DETAIL_TO_STD_CATEGORY_HPP_INCLUDED
#ifndef BOOST_SYSTEM_DETAIL_STD_CATEGORY_HPP_INCLUDED
#define BOOST_SYSTEM_DETAIL_STD_CATEGORY_HPP_INCLUDED
// Support for interoperability between Boost.System and <system_error>
//
// Copyright 2018 Peter Dimov
// Copyright 2018, 2021 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)
@@ -15,9 +15,6 @@
#include <boost/system/detail/error_code.hpp>
#include <boost/system/detail/generic_category.hpp>
#include <system_error>
#include <map>
#include <memory>
#include <mutex>
//
@@ -73,54 +70,6 @@ public:
bool equivalent( const std::error_code & code, int condition ) const BOOST_NOEXCEPT BOOST_OVERRIDE;
};
#if !defined(__SUNPRO_CC) // trailing __global is not supported
inline std::error_category const & to_std_category( boost::system::error_category const & cat ) BOOST_SYMBOL_VISIBLE;
#endif
struct cat_ptr_less
{
bool operator()( boost::system::error_category const * p1, boost::system::error_category const * p2 ) const BOOST_NOEXCEPT
{
return *p1 < *p2;
}
};
inline std::error_category const & to_std_category( boost::system::error_category const & cat )
{
if( cat.id_ == boost::system::detail::system_category_id )
{
static const std_category system_instance( &cat, 0x1F4D7 );
return system_instance;
}
else if( cat.id_ == boost::system::detail::generic_category_id )
{
static const std_category generic_instance( &cat, 0x1F4D3 );
return generic_instance;
}
else
{
typedef std::map< boost::system::error_category const *, std::unique_ptr<std_category>, cat_ptr_less > map_type;
static map_type map_;
static std::mutex map_mx_;
std::lock_guard<std::mutex> guard( map_mx_ );
map_type::iterator i = map_.find( &cat );
if( i == map_.end() )
{
std::unique_ptr<std_category> p( new std_category( &cat, 0 ) );
std::pair<map_type::iterator, bool> r = map_.insert( map_type::value_type( &cat, std::move( p ) ) );
i = r.first;
}
return *i->second;
}
}
inline bool std_category::equivalent( int code, const std::error_condition & condition ) const BOOST_NOEXCEPT
{
if( condition.category() == *this )
@@ -170,6 +119,7 @@ inline bool std_category::equivalent( const std::error_code & code, int conditio
boost::system::error_code bc( code.value(), *pc2->pc_ );
return pc_->equivalent( bc, condition );
}
#endif
else if( *pc_ == boost::system::generic_category() )
@@ -188,4 +138,4 @@ inline bool std_category::equivalent( const std::error_code & code, int conditio
} // namespace boost
#endif // #ifndef BOOST_SYSTEM_DETAIL_TO_STD_CATEGORY_HPP_INCLUDED
#endif // #ifndef BOOST_SYSTEM_DETAIL_STD_CATEGORY_HPP_INCLUDED

View File

@@ -12,9 +12,7 @@
#include <boost/system/detail/system_category.hpp>
#include <boost/system/detail/error_condition.hpp>
#include <boost/system/detail/generic_category.hpp>
#include <boost/system/api_config.hpp>
#include <boost/config.hpp>
#if !defined(BOOST_POSIX_API) && !defined(BOOST_WINDOWS_API)
# error BOOST_POSIX_API or BOOST_WINDOWS_API must be defined
@@ -37,7 +35,7 @@ inline boost::system::error_condition boost::system::detail::system_error_catego
}
else
{
return error_condition( e2, generic_category() );
return error_condition( boost::system::detail::generic_value_tag( e2 ) );
}
}
@@ -54,18 +52,10 @@ inline char const * boost::system::detail::system_error_category::message( int e
#else // #if defined(BOOST_WINDOWS_API)
#include <boost/system/detail/generic_category_message.hpp>
#include <boost/system/detail/is_generic_value.hpp>
inline boost::system::error_condition boost::system::detail::system_error_category::default_error_condition( int ev ) const BOOST_NOEXCEPT
{
if( is_generic_value( ev ) )
{
return error_condition( ev, generic_category() );
}
else
{
return error_condition( ev, *this );
}
return error_condition( boost::system::detail::generic_value_tag( ev ) );
}
inline std::string boost::system::detail::system_error_category::message( int ev ) const

View File

@@ -56,7 +56,7 @@ system-run generic_category_test.cpp ;
system-run system_category_test.cpp ;
system-run after_main_test.cpp ;
system-run failed_test.cpp ;
system-run failed_constexpr_test.cpp ;
compile failed_constexpr_test.cpp : <toolset>gcc,<undefined-sanitizer>norecover:<build>no ;
# Quick (CI) test
run quick.cpp ;

View File

@@ -35,16 +35,28 @@ BOOST_STATIC_ASSERT( !ec3 );
constexpr error_condition en1( 1, system_category() );
#if __GNUC__ == 7 && __cplusplus == 201703L
// `cat_ != 0` is not a constant expression
#else
BOOST_STATIC_ASSERT( en1.failed() );
BOOST_STATIC_ASSERT( en1 );
BOOST_STATIC_ASSERT( !!en1 );
#endif
constexpr error_condition en2( 2, generic_category() );
#if __GNUC__ == 7 && __cplusplus == 201703L
// `cat_ != 0` is not a constant expression
#else
BOOST_STATIC_ASSERT( en2.failed() );
BOOST_STATIC_ASSERT( en2 );
BOOST_STATIC_ASSERT( !!en2 );
#endif
constexpr error_condition en3;
BOOST_STATIC_ASSERT( !en3.failed() );

View File

@@ -18,7 +18,9 @@ int main()
// default_error_condition
BOOST_TEST( cat.default_error_condition( 0 ) == sys::error_condition() );
BOOST_TEST( cat.default_error_condition( -1 ) == sys::error_condition( -1, cat ) );
// No longer holds; returns a generic condition
// BOOST_TEST( cat.default_error_condition( -1 ) == sys::error_condition( -1, cat ) );
#if defined(BOOST_WINDOWS_API)