Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
e6f6dab9
Commit
e6f6dab9
authored
Mar 10, 2023
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/neverlord/expected'
parents
d9aca2e1
747abb49
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
1620 additions
and
188 deletions
+1620
-188
CHANGELOG.md
CHANGELOG.md
+10
-0
examples/message_passing/cell.cpp
examples/message_passing/cell.cpp
+3
-2
examples/message_passing/fan_out_request.cpp
examples/message_passing/fan_out_request.cpp
+9
-8
examples/remoting/remote_spawn.cpp
examples/remoting/remote_spawn.cpp
+2
-1
libcaf_core/caf/detail/type_traits.hpp
libcaf_core/caf/detail/type_traits.hpp
+3
-0
libcaf_core/caf/expected.hpp
libcaf_core/caf/expected.hpp
+658
-81
libcaf_core/caf/function_view.hpp
libcaf_core/caf/function_view.hpp
+18
-26
libcaf_core/test/expected.cpp
libcaf_core/test/expected.cpp
+903
-60
libcaf_io/src/io/network/default_multiplexer.cpp
libcaf_io/src/io/network/default_multiplexer.cpp
+3
-3
libcaf_io/src/io/network/native_socket.cpp
libcaf_io/src/io/network/native_socket.cpp
+7
-7
libcaf_test/caf/test/bdd_dsl.hpp
libcaf_test/caf/test/bdd_dsl.hpp
+4
-0
No files found.
CHANGELOG.md
View file @
e6f6dab9
...
@@ -24,6 +24,8 @@ is based on [Keep a Changelog](https://keepachangelog.com).
...
@@ -24,6 +24,8 @@ is based on [Keep a Changelog](https://keepachangelog.com).
-
Not initializing the meta objects table now prints a diagnosis message before
-
Not initializing the meta objects table now prints a diagnosis message before
aborting the program. Previously, the application would usually just crash due
aborting the program. Previously, the application would usually just crash due
to a
`nullptr`
-access inside some CAF function.
to a
`nullptr`
-access inside some CAF function.
-
The class
`expected`
now implements the monadic member functions from C++23
`std::expected`
as well as
`value_or`
.
### Fixed
### Fixed
...
@@ -46,6 +48,14 @@ is based on [Keep a Changelog](https://keepachangelog.com).
...
@@ -46,6 +48,14 @@ is based on [Keep a Changelog](https://keepachangelog.com).
actors or activities, scheduled actors now limit the amount of actions that
actors or activities, scheduled actors now limit the amount of actions that
may run in one iteration (#1364).
may run in one iteration (#1364).
### Deprecated
-
All member functions from
`caf::expected`
that have no equivalent in
`std::expected`
are now deprecated. Further,
`caf::expected<unit_t>`
as well
as constructing from
`unit_t`
are deprecated as well. The reasoning behind
this decision is that
`caf::expected`
should eventually become an alias for
`std::expected<T, caf::error>`
.
## [0.19.0-rc.1] - 2022-10-31
## [0.19.0-rc.1] - 2022-10-31
### Added
### Added
...
...
examples/message_passing/cell.cpp
View file @
e6f6dab9
...
@@ -46,9 +46,10 @@ void caf_main(actor_system& system) {
...
@@ -46,9 +46,10 @@ void caf_main(actor_system& system) {
auto
cell2
=
system
.
spawn
(
unchecked_cell
);
auto
cell2
=
system
.
spawn
(
unchecked_cell
);
// --(rst-spawn-cell-end)--
// --(rst-spawn-cell-end)--
auto
f
=
make_function_view
(
cell1
);
auto
f
=
make_function_view
(
cell1
);
cout
<<
"cell value: "
<<
f
(
get_atom_v
)
<<
endl
;
cout
<<
"cell value: "
<<
caf
::
to_string
(
f
(
get_atom_v
)
)
<<
endl
;
f
(
put_atom_v
,
20
);
f
(
put_atom_v
,
20
);
cout
<<
"cell value (after setting to 20): "
<<
f
(
get_atom_v
)
<<
endl
;
cout
<<
"cell value (after setting to 20): "
<<
caf
::
to_string
(
f
(
get_atom_v
))
<<
endl
;
// Get an unchecked cell and send it some garbage. Triggers an "unexpected
// Get an unchecked cell and send it some garbage. Triggers an "unexpected
// message" error (and terminates cell2!).
// message" error (and terminates cell2!).
anon_send
(
cell2
,
"hello there!"
);
anon_send
(
cell2
,
"hello there!"
);
...
...
examples/message_passing/fan_out_request.cpp
View file @
e6f6dab9
...
@@ -125,6 +125,7 @@ std::ostream& operator<<(std::ostream& out, const expected<int>& x) {
...
@@ -125,6 +125,7 @@ std::ostream& operator<<(std::ostream& out, const expected<int>& x) {
}
}
void
caf_main
(
actor_system
&
sys
)
{
void
caf_main
(
actor_system
&
sys
)
{
using
std
::
cout
;
// Spawn our matrix.
// Spawn our matrix.
static
constexpr
int
rows
=
3
;
static
constexpr
int
rows
=
3
;
static
constexpr
int
columns
=
6
;
static
constexpr
int
columns
=
6
;
...
@@ -140,18 +141,18 @@ void caf_main(actor_system& sys) {
...
@@ -140,18 +141,18 @@ void caf_main(actor_system& sys) {
// Print out matrix.
// Print out matrix.
for
(
int
row
=
0
;
row
<
rows
;
++
row
)
{
for
(
int
row
=
0
;
row
<
rows
;
++
row
)
{
for
(
int
column
=
0
;
column
<
columns
;
++
column
)
for
(
int
column
=
0
;
column
<
columns
;
++
column
)
std
::
cout
<<
std
::
setw
(
4
)
<<
f
(
get_atom_v
,
row
,
column
)
<<
' '
;
cout
<<
std
::
setw
(
4
)
<<
f
(
get_atom_v
,
row
,
column
)
<<
' '
;
std
::
cout
<<
'\n'
;
cout
<<
'\n'
;
}
}
// Print out AVG for each row and column.
// Print out AVG for each row and column.
for
(
int
row
=
0
;
row
<
rows
;
++
row
)
for
(
int
row
=
0
;
row
<
rows
;
++
row
)
std
::
cout
<<
"AVG(row "
<<
row
cout
<<
"AVG(row "
<<
row
<<
") = "
<<
") = "
<<
f
(
get_atom_v
,
average_atom_v
,
row_atom_v
,
row
)
<<
caf
::
to_string
(
f
(
get_atom_v
,
average_atom_v
,
row_atom_v
,
row
)
)
<<
'\n'
;
<<
'\n'
;
for
(
int
column
=
0
;
column
<
columns
;
++
column
)
for
(
int
column
=
0
;
column
<
columns
;
++
column
)
std
::
cout
<<
"AVG(column "
<<
column
cout
<<
"AVG(column "
<<
column
<<
") = "
<<
") = "
<<
f
(
get_atom_v
,
average_atom_v
,
column_atom_v
,
column
)
<<
caf
::
to_string
(
f
(
get_atom_v
,
average_atom_v
,
column_atom_v
,
column
)
)
<<
'\n'
;
<<
'\n'
;
}
}
CAF_MAIN
(
id_block
::
fan_out_request
)
CAF_MAIN
(
id_block
::
fan_out_request
)
examples/remoting/remote_spawn.cpp
View file @
e6f6dab9
...
@@ -94,7 +94,8 @@ void client_repl(function_view<calculator> f) {
...
@@ -94,7 +94,8 @@ void client_repl(function_view<calculator> f) {
usage
();
usage
();
else
else
cout
<<
" = "
cout
<<
" = "
<<
(
words
[
1
]
==
"+"
?
f
(
add_atom_v
,
*
x
,
*
y
)
:
f
(
sub_atom_v
,
*
x
,
*
y
))
<<
caf
::
to_string
(
words
[
1
]
==
"+"
?
f
(
add_atom_v
,
*
x
,
*
y
)
:
f
(
sub_atom_v
,
*
x
,
*
y
))
<<
"
\n
"
;
<<
"
\n
"
;
}
}
}
}
...
...
libcaf_core/caf/detail/type_traits.hpp
View file @
e6f6dab9
...
@@ -544,6 +544,9 @@ struct is_expected : std::false_type {};
...
@@ -544,6 +544,9 @@ struct is_expected : std::false_type {};
template
<
class
T
>
template
<
class
T
>
struct
is_expected
<
expected
<
T
>>
:
std
::
true_type
{};
struct
is_expected
<
expected
<
T
>>
:
std
::
true_type
{};
template
<
class
T
>
constexpr
bool
is_expected_v
=
is_expected
<
T
>::
value
;
// Checks whether `T` and `U` are integers of the same size and signedness.
// Checks whether `T` and `U` are integers of the same size and signedness.
// clang-format off
// clang-format off
template
<
class
T
,
class
U
,
template
<
class
T
,
class
U
,
...
...
libcaf_core/caf/expected.hpp
View file @
e6f6dab9
...
@@ -10,24 +10,47 @@
...
@@ -10,24 +10,47 @@
#include <new>
#include <new>
#include <ostream>
#include <ostream>
#include <type_traits>
#include <type_traits>
#include <utility>
#include "caf/deep_to_string.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/error.hpp"
#include "caf/error.hpp"
#include "caf/is_error_code_enum.hpp"
#include "caf/is_error_code_enum.hpp"
#include "caf/raise_error.hpp"
#include "caf/unit.hpp"
#include "caf/unit.hpp"
namespace
caf
{
namespace
caf
{
namespace
detail
{
template
<
class
F
,
class
...
Ts
>
auto
expected_from_fn
(
F
&&
f
,
Ts
&&
...
xs
)
{
using
res_t
=
decltype
(
f
(
std
::
forward
<
Ts
>
(
xs
)...));
if
constexpr
(
std
::
is_void_v
<
res_t
>
)
{
f
(
std
::
forward
<
Ts
>
(
xs
)...);
return
expected
<
res_t
>
{};
}
else
{
return
expected
<
res_t
>
{
f
(
std
::
forward
<
Ts
>
(
xs
)...)};
}
}
}
// namespace detail
/// Represents the result of a computation which can either complete
/// Represents the result of a computation which can either complete
/// successfully with an instance of type `T` or fail with an `error`.
/// successfully with an instance of type `T` or fail with an `error`.
/// @tparam T The type of the result.
/// @tparam T The type of the result.
template
<
typename
T
>
template
<
class
T
>
class
expected
{
class
expected
{
public:
public:
// -- member types -----------------------------------------------------------
// -- member types -----------------------------------------------------------
using
value_type
=
T
;
using
value_type
=
T
;
using
error_type
=
caf
::
error
;
template
<
class
U
>
using
rebind
=
expected
<
U
>
;
// -- static member variables ------------------------------------------------
// -- static member variables ------------------------------------------------
/// Stores whether move construct and move assign never throw.
/// Stores whether move construct and move assign never throw.
...
@@ -40,25 +63,32 @@ public:
...
@@ -40,25 +63,32 @@ public:
=
std
::
is_nothrow_copy_constructible
<
T
>::
value
=
std
::
is_nothrow_copy_constructible
<
T
>::
value
&&
std
::
is_nothrow_copy_assignable
<
T
>::
value
;
&&
std
::
is_nothrow_copy_assignable
<
T
>::
value
;
/// Stores whether swap() never throws.
static
constexpr
bool
nothrow_swap
=
std
::
is_nothrow_swappable_v
<
T
>
;
// -- constructors, destructors, and assignment operators --------------------
// -- constructors, destructors, and assignment operators --------------------
template
<
class
U
>
template
<
class
U
,
class
=
std
::
enable_if_t
<
std
::
is_convertible_v
<
U
,
T
>
expected
(
||
is_error_code_enum_v
<
U
>>>
U
x
,
expected
(
U
x
)
{
typename
std
::
enable_if
<
std
::
is_convertible
<
U
,
T
>::
value
>::
type
*
=
nullptr
)
if
constexpr
(
std
::
is_convertible_v
<
U
,
T
>
)
{
:
engaged_
(
true
)
{
has_value_
=
true
;
new
(
std
::
addressof
(
value_
))
T
(
std
::
move
(
x
));
new
(
std
::
addressof
(
value_
))
T
(
std
::
move
(
x
));
}
else
{
has_value_
=
false
;
new
(
std
::
addressof
(
error_
))
caf
::
error
(
x
);
}
}
}
expected
(
T
&&
x
)
noexcept
(
nothrow_move
)
:
engaged
_
(
true
)
{
expected
(
T
&&
x
)
noexcept
(
nothrow_move
)
:
has_value
_
(
true
)
{
new
(
std
::
addressof
(
value_
))
T
(
std
::
move
(
x
));
new
(
std
::
addressof
(
value_
))
T
(
std
::
move
(
x
));
}
}
expected
(
const
T
&
x
)
noexcept
(
nothrow_copy
)
:
engaged
_
(
true
)
{
expected
(
const
T
&
x
)
noexcept
(
nothrow_copy
)
:
has_value
_
(
true
)
{
new
(
std
::
addressof
(
value_
))
T
(
x
);
new
(
std
::
addressof
(
value_
))
T
(
x
);
}
}
expected
(
caf
::
error
e
)
noexcept
:
engaged
_
(
false
)
{
expected
(
caf
::
error
e
)
noexcept
:
has_value
_
(
false
)
{
new
(
std
::
addressof
(
error_
))
caf
::
error
{
std
::
move
(
e
)};
new
(
std
::
addressof
(
error_
))
caf
::
error
{
std
::
move
(
e
)};
}
}
...
@@ -66,23 +96,23 @@ public:
...
@@ -66,23 +96,23 @@ public:
construct
(
other
);
construct
(
other
);
}
}
template
<
class
Enum
,
class
=
std
::
enable_if_t
<
is_error_code_enum_v
<
Enum
>
>>
expected
(
Enum
code
)
:
engaged_
(
false
)
{
new
(
std
::
addressof
(
error_
))
caf
::
error
(
code
);
}
expected
(
expected
&&
other
)
noexcept
(
nothrow_move
)
{
expected
(
expected
&&
other
)
noexcept
(
nothrow_move
)
{
construct
(
std
::
move
(
other
));
construct
(
std
::
move
(
other
));
}
}
template
<
class
...
Ts
>
expected
(
std
::
in_place_t
,
Ts
&&
...
xs
)
:
has_value_
(
true
)
{
new
(
std
::
addressof
(
value_
))
T
(
std
::
forward
<
Ts
>
(
xs
)...);
}
~
expected
()
{
~
expected
()
{
destroy
();
destroy
();
}
}
expected
&
operator
=
(
const
expected
&
other
)
noexcept
(
nothrow_copy
)
{
expected
&
operator
=
(
const
expected
&
other
)
noexcept
(
nothrow_copy
)
{
if
(
engaged_
&&
other
.
engaged
_
)
if
(
has_value
()
&&
other
.
has_value
_
)
value_
=
other
.
value_
;
value_
=
other
.
value_
;
else
if
(
!
engaged_
&&
!
other
.
engaged
_
)
else
if
(
!
has_value
()
&&
!
other
.
has_value
_
)
error_
=
other
.
error_
;
error_
=
other
.
error_
;
else
{
else
{
destroy
();
destroy
();
...
@@ -92,9 +122,9 @@ public:
...
@@ -92,9 +122,9 @@ public:
}
}
expected
&
operator
=
(
expected
&&
other
)
noexcept
(
nothrow_move
)
{
expected
&
operator
=
(
expected
&&
other
)
noexcept
(
nothrow_move
)
{
if
(
engaged_
&&
other
.
engaged
_
)
if
(
has_value
()
&&
other
.
has_value
_
)
value_
=
std
::
move
(
other
.
value_
);
value_
=
std
::
move
(
other
.
value_
);
else
if
(
!
engaged_
&&
!
other
.
engaged
_
)
else
if
(
!
has_value
()
&&
!
other
.
has_value
_
)
error_
=
std
::
move
(
other
.
error_
);
error_
=
std
::
move
(
other
.
error_
);
else
{
else
{
destroy
();
destroy
();
...
@@ -104,22 +134,22 @@ public:
...
@@ -104,22 +134,22 @@ public:
}
}
expected
&
operator
=
(
const
T
&
x
)
noexcept
(
nothrow_copy
)
{
expected
&
operator
=
(
const
T
&
x
)
noexcept
(
nothrow_copy
)
{
if
(
engaged_
)
{
if
(
has_value
()
)
{
value_
=
x
;
value_
=
x
;
}
else
{
}
else
{
destroy
();
destroy
();
engaged
_
=
true
;
has_value
_
=
true
;
new
(
std
::
addressof
(
value_
))
T
(
x
);
new
(
std
::
addressof
(
value_
))
T
(
x
);
}
}
return
*
this
;
return
*
this
;
}
}
expected
&
operator
=
(
T
&&
x
)
noexcept
(
nothrow_move
)
{
expected
&
operator
=
(
T
&&
x
)
noexcept
(
nothrow_move
)
{
if
(
engaged_
)
{
if
(
has_value
()
)
{
value_
=
std
::
move
(
x
);
value_
=
std
::
move
(
x
);
}
else
{
}
else
{
destroy
();
destroy
();
engaged
_
=
true
;
has_value
_
=
true
;
new
(
std
::
addressof
(
value_
))
T
(
std
::
move
(
x
));
new
(
std
::
addressof
(
value_
))
T
(
std
::
move
(
x
));
}
}
return
*
this
;
return
*
this
;
...
@@ -132,11 +162,11 @@ public:
...
@@ -132,11 +162,11 @@ public:
}
}
expected
&
operator
=
(
caf
::
error
e
)
noexcept
{
expected
&
operator
=
(
caf
::
error
e
)
noexcept
{
if
(
!
engaged_
)
if
(
!
has_value
()
)
error_
=
std
::
move
(
e
);
error_
=
std
::
move
(
e
);
else
{
else
{
destroy
();
destroy
();
engaged
_
=
false
;
has_value
_
=
false
;
new
(
std
::
addressof
(
error_
))
caf
::
error
(
std
::
move
(
e
));
new
(
std
::
addressof
(
error_
))
caf
::
error
(
std
::
move
(
e
));
}
}
return
*
this
;
return
*
this
;
...
@@ -147,106 +177,387 @@ public:
...
@@ -147,106 +177,387 @@ public:
return
*
this
=
make_error
(
code
);
return
*
this
=
make_error
(
code
);
}
}
// -- observers --------------------------------------------------------------
/// @copydoc engaged
explicit
operator
bool
()
const
noexcept
{
return
has_value_
;
}
/// Returns `true` if the object holds a value (is engaged).
bool
has_value
()
const
noexcept
{
return
has_value_
;
}
/// Returns `true` if the object holds a value (is engaged).
[[
deprecated
(
"use has_value() instead"
)]]
bool
engaged
()
const
noexcept
{
return
has_value_
;
}
// -- modifiers --------------------------------------------------------------
// -- modifiers --------------------------------------------------------------
template
<
class
...
Args
>
std
::
enable_if_t
<
std
::
is_nothrow_constructible_v
<
T
,
Args
...
>
,
T
&>
emplace
(
Args
&&
...
args
)
noexcept
{
destroy
();
has_value_
=
true
;
new
(
std
::
addressof
(
value_
))
T
(
std
::
forward
<
Args
>
(
args
)...);
return
value_
;
}
void
swap
(
expected
&
other
)
noexcept
(
nothrow_move
&&
nothrow_swap
)
{
expected
tmp
{
std
::
move
(
other
)};
other
=
std
::
move
(
*
this
);
*
this
=
std
::
move
(
tmp
);
}
// -- value access -----------------------------------------------------------
/// Returns the contained value.
/// @pre `has_value() == true`.
[[
deprecated
(
"use value() instead"
)]]
const
T
&
cvalue
()
const
noexcept
{
if
(
!
has_value
())
CAF_RAISE_ERROR
(
"bad_expected_access"
);
return
value_
;
}
/// @copydoc cvalue
/// @copydoc cvalue
T
&
value
()
noexcept
{
T
&
value
()
&
{
CAF_ASSERT
(
engaged_
);
if
(
!
has_value
())
CAF_RAISE_ERROR
(
"bad_expected_access"
);
return
value_
;
return
value_
;
}
}
/// @copydoc cvalue
/// @copydoc cvalue
T
&
operator
*
()
noexcept
{
const
T
&
value
()
const
&
{
return
value
();
if
(
!
has_value
())
CAF_RAISE_ERROR
(
"bad_expected_access"
);
return
value_
;
}
}
/// @copydoc cvalue
/// @copydoc cvalue
T
*
operator
->
()
noexcept
{
T
&&
value
()
&&
{
return
&
value
();
if
(
!
has_value
())
CAF_RAISE_ERROR
(
"bad_expected_access"
);
return
std
::
move
(
value_
);
}
}
/// @copydoc cerror
/// @copydoc cvalue
caf
::
error
&
error
()
noexcept
{
const
T
&&
value
()
const
&&
{
CAF_ASSERT
(
!
engaged_
);
if
(
!
has_value
())
return
error_
;
CAF_RAISE_ERROR
(
"bad_expected_access"
);
return
std
::
move
(
value_
);
}
}
// -- observers --------------------------------------------------------------
/// Returns the contained value if there is one, otherwise returns `fallback`.
template
<
class
U
>
T
value_or
(
U
&&
fallback
)
const
&
{
if
(
has_value
())
return
value_
;
else
return
T
{
std
::
forward
<
U
>
(
fallback
)};
}
/// Returns the contained value.
/// Returns the contained value if there is one, otherwise returns `fallback`.
/// @pre `engaged() == true`.
template
<
class
U
>
const
T
&
cvalue
()
const
noexcept
{
T
value_or
(
U
&&
fallback
)
&&
{
CAF_ASSERT
(
engaged_
);
if
(
has_value
())
return
std
::
move
(
value_
);
else
return
T
{
std
::
forward
<
U
>
(
fallback
)};
}
/// @copydoc cvalue
T
&
operator
*
()
&
noexcept
{
return
value_
;
return
value_
;
}
}
/// @copydoc cvalue
/// @copydoc cvalue
const
T
&
value
()
const
noexcept
{
const
T
&
operator
*
()
const
&
noexcept
{
CAF_ASSERT
(
engaged_
);
return
value_
;
return
value_
;
}
}
/// @copydoc cvalue
/// @copydoc cvalue
const
T
&
operator
*
()
const
noexcept
{
T
&&
operator
*
()
&&
noexcept
{
return
value
(
);
return
std
::
move
(
value_
);
}
}
/// @copydoc cvalue
/// @copydoc cvalue
const
T
*
operator
->
()
const
noexcept
{
const
T
&&
operator
*
()
const
&&
noexcept
{
return
&
value
(
);
return
std
::
move
(
value_
);
}
}
/// @copydoc
engaged
/// @copydoc
cvalue
explicit
operator
bool
()
const
noexcept
{
T
*
operator
->
()
noexcept
{
return
engaged
()
;
return
&
value_
;
}
}
///
Returns `true` if the object holds a value (is engaged).
///
@copydoc cvalue
bool
engaged
()
const
noexcept
{
const
T
*
operator
->
()
const
noexcept
{
return
engaged
_
;
return
&
value
_
;
}
}
// -- error access -----------------------------------------------------------
/// Returns the contained error.
/// Returns the contained error.
/// @pre `engaged() == false`.
/// @pre `has_value() == false`.
const
caf
::
error
&
cerror
()
const
noexcept
{
[[
deprecated
(
"use error() instead"
)]]
const
caf
::
error
&
CAF_ASSERT
(
!
engaged_
);
cerror
()
const
noexcept
{
CAF_ASSERT
(
!
has_value_
);
return
error_
;
return
error_
;
}
}
/// @copydoc cerror
/// @copydoc cerror
c
onst
caf
::
error
&
error
()
const
noexcept
{
c
af
::
error
&
error
()
&
noexcept
{
CAF_ASSERT
(
!
engaged
_
);
CAF_ASSERT
(
!
has_value
_
);
return
error_
;
return
error_
;
}
}
/// @copydoc cerror
const
caf
::
error
&
error
()
const
&
noexcept
{
CAF_ASSERT
(
!
has_value_
);
return
error_
;
}
/// @copydoc cerror
caf
::
error
&&
error
()
&&
noexcept
{
CAF_ASSERT
(
!
has_value_
);
return
std
::
move
(
error_
);
}
/// @copydoc cerror
const
caf
::
error
&&
error
()
const
&&
noexcept
{
CAF_ASSERT
(
!
has_value_
);
return
std
::
move
(
error_
);
}
// -- monadic functions ------------------------------------------------------
template
<
class
F
>
auto
and_then
(
F
&&
f
)
&
{
using
res_t
=
decltype
(
f
(
value_
));
static_assert
(
detail
::
is_expected_v
<
res_t
>
,
"F must return an expected"
);
if
(
has_value
())
return
f
(
value_
);
else
return
res_t
{
error_
};
}
template
<
class
F
>
auto
and_then
(
F
&&
f
)
&&
{
using
res_t
=
decltype
(
f
(
std
::
move
(
value_
)));
static_assert
(
detail
::
is_expected_v
<
res_t
>
,
"F must return an expected"
);
if
(
has_value
())
return
f
(
std
::
move
(
value_
));
else
return
res_t
{
std
::
move
(
error_
)};
}
template
<
class
F
>
auto
and_then
(
F
&&
f
)
const
&
{
using
res_t
=
decltype
(
f
(
value_
));
static_assert
(
detail
::
is_expected_v
<
res_t
>
,
"F must return an expected"
);
if
(
has_value
())
return
f
(
value_
);
else
return
res_t
{
error_
};
}
template
<
class
F
>
auto
and_then
(
F
&&
f
)
const
&&
{
using
res_t
=
decltype
(
f
(
std
::
move
(
value_
)));
static_assert
(
detail
::
is_expected_v
<
res_t
>
,
"F must return an expected"
);
if
(
has_value
())
return
f
(
std
::
move
(
value_
));
else
return
res_t
{
std
::
move
(
error_
)};
}
template
<
class
F
>
expected
or_else
(
F
&&
f
)
&
{
using
res_t
=
decltype
(
f
(
error_
));
if
constexpr
(
std
::
is_void_v
<
res_t
>
)
{
if
(
!
has_value
())
f
(
error_
);
return
*
this
;
}
else
{
static_assert
(
std
::
is_same_v
<
expected
,
res_t
>
,
"F must return expected<T> or void"
);
if
(
has_value
())
return
expected
{
std
::
in_place
,
value_
};
else
return
f
(
error_
);
}
}
template
<
class
F
>
expected
or_else
(
F
&&
f
)
&&
{
using
res_t
=
decltype
(
f
(
std
::
move
(
error_
)));
if
constexpr
(
std
::
is_void_v
<
res_t
>
)
{
if
(
!
has_value
())
f
(
std
::
move
(
error_
));
return
std
::
move
(
*
this
);
}
else
{
static_assert
(
std
::
is_same_v
<
expected
,
res_t
>
,
"F must return expected<T> or void"
);
if
(
has_value
())
return
expected
{
std
::
in_place
,
std
::
move
(
value_
)};
else
return
f
(
std
::
move
(
error_
));
}
}
template
<
class
F
>
expected
or_else
(
F
&&
f
)
const
&
{
using
res_t
=
decltype
(
f
(
error_
));
if
constexpr
(
std
::
is_void_v
<
res_t
>
)
{
if
(
!
has_value
())
f
(
error_
);
return
*
this
;
}
else
{
static_assert
(
std
::
is_same_v
<
expected
,
res_t
>
,
"F must return expected<T> or void"
);
if
(
has_value
())
return
expected
{
std
::
in_place
,
value_
};
else
return
f
(
error_
);
}
}
template
<
class
F
>
expected
or_else
(
F
&&
f
)
const
&&
{
using
res_t
=
decltype
(
f
(
std
::
move
(
error_
)));
if
constexpr
(
std
::
is_void_v
<
res_t
>
)
{
if
(
!
has_value
())
f
(
std
::
move
(
error_
));
return
std
::
move
(
*
this
);
}
else
{
static_assert
(
std
::
is_same_v
<
expected
,
res_t
>
,
"F must return expected<T> or void"
);
if
(
has_value
())
return
expected
{
std
::
in_place
,
std
::
move
(
value_
)};
else
return
f
(
std
::
move
(
error_
));
}
}
template
<
class
F
>
auto
transform
(
F
&&
f
)
&
{
using
res_t
=
decltype
(
f
(
value_
));
static_assert
(
!
detail
::
is_expected_v
<
res_t
>
,
"F must not return an expected"
);
if
(
has_value
())
return
detail
::
expected_from_fn
(
std
::
forward
<
F
>
(
f
),
value_
);
else
return
expected
<
res_t
>
{
error_
};
}
template
<
class
F
>
auto
transform
(
F
&&
f
)
&&
{
using
res_t
=
decltype
(
f
(
value_
));
static_assert
(
!
detail
::
is_expected_v
<
res_t
>
,
"F must not return an expected"
);
if
(
has_value
())
return
detail
::
expected_from_fn
(
std
::
forward
<
F
>
(
f
),
std
::
move
(
value_
));
else
return
expected
<
res_t
>
{
std
::
move
(
error_
)};
}
template
<
class
F
>
auto
transform
(
F
&&
f
)
const
&
{
using
res_t
=
decltype
(
f
(
value_
));
static_assert
(
!
detail
::
is_expected_v
<
res_t
>
,
"F must not return an expected"
);
if
(
has_value
())
return
detail
::
expected_from_fn
(
std
::
forward
<
F
>
(
f
),
value_
);
else
return
expected
<
res_t
>
{
error_
};
}
template
<
class
F
>
auto
transform
(
F
&&
f
)
const
&&
{
using
res_t
=
decltype
(
f
(
value_
));
static_assert
(
!
detail
::
is_expected_v
<
res_t
>
,
"F must not return an expected"
);
if
(
has_value
())
return
detail
::
expected_from_fn
(
std
::
forward
<
F
>
(
f
),
std
::
move
(
value_
));
else
return
expected
<
res_t
>
{
std
::
move
(
error_
)};
}
template
<
class
F
>
expected
transform_or
(
F
&&
f
)
&
{
using
res_t
=
decltype
(
f
(
error_
));
static_assert
(
std
::
is_same_v
<
caf
::
error
,
res_t
>
,
"F must return an error"
);
if
(
has_value
())
return
{
std
::
in_place
,
value_
};
else
return
expected
{
f
(
error_
)};
}
template
<
class
F
>
expected
transform_or
(
F
&&
f
)
&&
{
using
res_t
=
decltype
(
f
(
error_
));
static_assert
(
std
::
is_same_v
<
caf
::
error
,
res_t
>
,
"F must return an error"
);
if
(
has_value
())
return
{
std
::
in_place
,
std
::
move
(
value_
)};
else
return
expected
{
f
(
std
::
move
(
error_
))};
}
template
<
class
F
>
expected
transform_or
(
F
&&
f
)
const
&
{
using
res_t
=
decltype
(
f
(
error_
));
static_assert
(
std
::
is_same_v
<
caf
::
error
,
res_t
>
,
"F must return an error"
);
if
(
has_value
())
return
{
std
::
in_place
,
value_
};
else
return
expected
{
f
(
error_
)};
}
template
<
class
F
>
expected
transform_or
(
F
&&
f
)
const
&&
{
using
res_t
=
decltype
(
f
(
error_
));
static_assert
(
std
::
is_same_v
<
caf
::
error
,
res_t
>
,
"F must return an error"
);
if
(
has_value
())
return
{
std
::
in_place
,
std
::
move
(
value_
)};
else
return
expected
{
f
(
std
::
move
(
error_
))};
}
private:
private:
void
construct
(
expected
&&
other
)
noexcept
(
nothrow_move
)
{
void
construct
(
expected
&&
other
)
noexcept
(
nothrow_move
)
{
if
(
other
.
engaged
_
)
if
(
other
.
has_value
_
)
new
(
std
::
addressof
(
value_
))
T
(
std
::
move
(
other
.
value_
));
new
(
std
::
addressof
(
value_
))
T
(
std
::
move
(
other
.
value_
));
else
else
new
(
std
::
addressof
(
error_
))
caf
::
error
(
std
::
move
(
other
.
error_
));
new
(
std
::
addressof
(
error_
))
caf
::
error
(
std
::
move
(
other
.
error_
));
engaged_
=
other
.
engaged
_
;
has_value_
=
other
.
has_value
_
;
}
}
void
construct
(
const
expected
&
other
)
noexcept
(
nothrow_copy
)
{
void
construct
(
const
expected
&
other
)
noexcept
(
nothrow_copy
)
{
if
(
other
.
engaged
_
)
if
(
other
.
has_value
_
)
new
(
std
::
addressof
(
value_
))
T
(
other
.
value_
);
new
(
std
::
addressof
(
value_
))
T
(
other
.
value_
);
else
else
new
(
std
::
addressof
(
error_
))
caf
::
error
(
other
.
error_
);
new
(
std
::
addressof
(
error_
))
caf
::
error
(
other
.
error_
);
engaged_
=
other
.
engaged
_
;
has_value_
=
other
.
has_value
_
;
}
}
void
destroy
()
{
void
destroy
()
{
if
(
engaged_
)
if
(
has_value
()
)
value_
.
~
T
();
value_
.
~
T
();
else
else
error_
.
~
error
();
error_
.
~
error
();
}
}
bool
engaged_
;
/// Denotes whether `value_` may be accessed. When false, error_ may be
/// accessed.
bool
has_value_
;
union
{
union
{
/// Stores the contained value.
T
value_
;
T
value_
;
/// Stores an error in case there is no value.
caf
::
error
error_
;
caf
::
error
error_
;
};
};
};
};
...
@@ -346,46 +657,311 @@ operator!=(Enum x, const expected<T>& y) {
...
@@ -346,46 +657,311 @@ operator!=(Enum x, const expected<T>& y) {
template
<
>
template
<
>
class
expected
<
void
>
{
class
expected
<
void
>
{
public:
public:
expected
()
=
default
;
// -- member types -----------------------------------------------------------
expected
(
unit_t
)
noexcept
{
using
value_type
=
void
;
// nop
}
using
error_type
=
caf
::
error
;
template
<
class
U
>
using
rebind
=
expected
<
U
>
;
// -- constructors, destructors, and assignment operators --------------------
expected
(
caf
::
error
e
)
noexcept
:
error_
(
std
::
move
(
e
))
{
template
<
class
Enum
,
class
=
std
::
enable_if_t
<
is_error_code_enum_v
<
Enum
>
>>
expected
(
Enum
x
)
:
error_
(
std
::
in_place
,
x
)
{
// nop
// nop
}
}
expected
(
const
expected
&
other
)
noexcept
:
error_
(
other
.
error_
)
{
expected
()
noexcept
=
default
;
[[
deprecated
(
"use the default constructor instead"
)]]
//
expected
(
unit_t
)
noexcept
{
// nop
// nop
}
}
expected
(
expected
&&
other
)
noexcept
:
error_
(
std
::
move
(
other
.
error_
))
{
expected
(
caf
::
error
err
)
noexcept
:
error_
(
std
::
move
(
err
))
{
// nop
// nop
}
}
template
<
class
Enum
,
class
=
std
::
enable_if_t
<
is_error_code_enum_v
<
Enum
>
>>
expected
(
const
expected
&
other
)
=
default
;
expected
(
Enum
code
)
:
error_
(
code
)
{
expected
(
expected
&&
other
)
noexcept
=
default
;
explicit
expected
(
std
::
in_place_t
)
{
// nop
// nop
}
}
expected
&
operator
=
(
const
expected
&
other
)
=
default
;
expected
&
operator
=
(
const
expected
&
other
)
=
default
;
expected
&
operator
=
(
expected
&&
other
)
noexcept
{
expected
&
operator
=
(
expected
&&
other
)
noexcept
=
default
;
error_
=
std
::
move
(
other
.
error_
);
expected
&
operator
=
(
caf
::
error
err
)
noexcept
{
error_
=
std
::
move
(
err
);
return
*
this
;
return
*
this
;
}
}
explicit
operator
bool
()
const
{
template
<
class
Enum
,
class
=
std
::
enable_if_t
<
is_error_code_enum_v
<
Enum
>
>>
expected
&
operator
=
(
Enum
code
)
{
error_
=
make_error
(
code
);
return
*
this
;
}
// -- observers --------------------------------------------------------------
/// Returns `true` if the object does *not* hold an error.
explicit
operator
bool
()
const
noexcept
{
return
!
error_
;
return
!
error_
;
}
}
const
caf
::
error
&
error
()
const
{
/// Returns `true` if the object does *not* hold an error.
return
error_
;
bool
has_value
()
const
noexcept
{
return
!
error_
;
}
// -- modifiers --------------------------------------------------------------
template
<
class
...
Args
>
void
emplace
()
noexcept
{
error_
=
std
::
nullopt
;
}
void
swap
(
expected
&
other
)
noexcept
{
error_
.
swap
(
other
.
error_
);
}
// -- value access -----------------------------------------------------------
void
value
()
const
&
{
// nop
}
void
value
()
&&
{
// nop
}
void
operator
*
()
const
noexcept
{
// nop
}
// -- error access -----------------------------------------------------------
caf
::
error
&
error
()
&
noexcept
{
CAF_ASSERT
(
!
has_value
());
return
*
error_
;
}
const
caf
::
error
&
error
()
const
&
noexcept
{
CAF_ASSERT
(
!
has_value
());
return
*
error_
;
}
caf
::
error
&&
error
()
&&
noexcept
{
CAF_ASSERT
(
!
has_value
());
return
std
::
move
(
*
error_
);
}
const
caf
::
error
&&
error
()
const
&&
noexcept
{
CAF_ASSERT
(
!
has_value
());
return
std
::
move
(
*
error_
);
}
// -- monadic functions ------------------------------------------------------
template
<
class
F
>
auto
and_then
(
F
&&
f
)
&
{
using
res_t
=
decltype
(
f
());
static_assert
(
detail
::
is_expected_v
<
res_t
>
,
"F must return an expected"
);
if
(
has_value
())
return
f
();
else
return
res_t
{
*
error_
};
}
template
<
class
F
>
auto
and_then
(
F
&&
f
)
&&
{
using
res_t
=
decltype
(
f
());
static_assert
(
detail
::
is_expected_v
<
res_t
>
,
"F must return an expected"
);
if
(
has_value
())
return
f
();
else
return
res_t
{
std
::
move
(
*
error_
)};
}
template
<
class
F
>
auto
and_then
(
F
&&
f
)
const
&
{
using
res_t
=
decltype
(
f
());
static_assert
(
detail
::
is_expected_v
<
res_t
>
,
"F must return an expected"
);
if
(
has_value
())
return
f
();
else
return
res_t
{
*
error_
};
}
template
<
class
F
>
auto
and_then
(
F
&&
f
)
const
&&
{
using
res_t
=
decltype
(
f
());
static_assert
(
detail
::
is_expected_v
<
res_t
>
,
"F must return an expected"
);
if
(
has_value
())
return
f
();
else
return
res_t
{
std
::
move
(
*
error_
)};
}
template
<
class
F
>
expected
or_else
(
F
&&
f
)
&
{
using
res_t
=
decltype
(
f
(
*
error_
));
if
constexpr
(
std
::
is_void_v
<
res_t
>
)
{
if
(
!
has_value
())
f
(
*
error_
);
return
*
this
;
}
else
{
static_assert
(
std
::
is_same_v
<
expected
,
res_t
>
,
"F must return expected<T> or void"
);
if
(
has_value
())
return
expected
{
std
::
in_place
};
else
return
f
(
*
error_
);
}
}
template
<
class
F
>
expected
or_else
(
F
&&
f
)
&&
{
using
res_t
=
decltype
(
f
(
std
::
move
(
*
error_
)));
if
constexpr
(
std
::
is_void_v
<
res_t
>
)
{
if
(
!
has_value
())
f
(
std
::
move
(
*
error_
));
return
std
::
move
(
*
this
);
}
else
{
static_assert
(
std
::
is_same_v
<
expected
,
res_t
>
,
"F must return expected<T> or void"
);
if
(
has_value
())
return
expected
{
std
::
in_place
};
else
return
f
(
std
::
move
(
*
error_
));
}
}
template
<
class
F
>
expected
or_else
(
F
&&
f
)
const
&
{
using
res_t
=
decltype
(
f
(
*
error_
));
if
constexpr
(
std
::
is_void_v
<
res_t
>
)
{
if
(
!
has_value
())
f
(
*
error_
);
return
*
this
;
}
else
{
static_assert
(
std
::
is_same_v
<
expected
,
res_t
>
,
"F must return expected<T> or void"
);
if
(
has_value
())
return
expected
{
std
::
in_place
};
else
return
f
(
*
error_
);
}
}
template
<
class
F
>
expected
or_else
(
F
&&
f
)
const
&&
{
using
res_t
=
decltype
(
f
(
std
::
move
(
*
error_
)));
if
constexpr
(
std
::
is_void_v
<
res_t
>
)
{
if
(
!
has_value
())
f
(
std
::
move
(
*
error_
));
return
std
::
move
(
*
this
);
}
else
{
static_assert
(
std
::
is_same_v
<
expected
,
res_t
>
,
"F must return expected<T> or void"
);
if
(
has_value
())
return
expected
{
std
::
in_place
};
else
return
f
(
std
::
move
(
*
error_
));
}
}
template
<
class
F
>
auto
transform
(
F
&&
f
)
&
{
using
res_t
=
decltype
(
f
());
static_assert
(
!
detail
::
is_expected_v
<
res_t
>
,
"F must not return an expected"
);
if
(
has_value
())
return
detail
::
expected_from_fn
(
std
::
forward
<
F
>
(
f
));
else
return
expected
<
res_t
>
{
*
error_
};
}
template
<
class
F
>
auto
transform
(
F
&&
f
)
&&
{
using
res_t
=
decltype
(
f
());
static_assert
(
!
detail
::
is_expected_v
<
res_t
>
,
"F must not return an expected"
);
if
(
has_value
())
return
detail
::
expected_from_fn
(
std
::
forward
<
F
>
(
f
));
else
return
expected
<
res_t
>
{
std
::
move
(
*
error_
)};
}
template
<
class
F
>
auto
transform
(
F
&&
f
)
const
&
{
using
res_t
=
decltype
(
f
());
static_assert
(
!
detail
::
is_expected_v
<
res_t
>
,
"F must not return an expected"
);
if
(
has_value
())
return
detail
::
expected_from_fn
(
std
::
forward
<
F
>
(
f
));
else
return
expected
<
res_t
>
{
*
error_
};
}
template
<
class
F
>
auto
transform
(
F
&&
f
)
const
&&
{
using
res_t
=
decltype
(
f
());
static_assert
(
!
detail
::
is_expected_v
<
res_t
>
,
"F must not return an expected"
);
if
(
has_value
())
return
detail
::
expected_from_fn
(
std
::
forward
<
F
>
(
f
));
else
return
expected
<
res_t
>
{
std
::
move
(
*
error_
)};
}
template
<
class
F
>
expected
transform_or
(
F
&&
f
)
&
{
using
res_t
=
decltype
(
f
(
*
error_
));
static_assert
(
std
::
is_same_v
<
caf
::
error
,
res_t
>
,
"F must return an error"
);
if
(
has_value
())
return
expected
{};
else
return
expected
{
f
(
*
error_
)};
}
template
<
class
F
>
expected
transform_or
(
F
&&
f
)
&&
{
using
res_t
=
decltype
(
f
(
std
::
move
(
*
error_
)));
static_assert
(
std
::
is_same_v
<
caf
::
error
,
res_t
>
,
"F must return an error"
);
if
(
has_value
())
return
expected
{};
else
return
expected
{
f
(
std
::
move
(
*
error_
))};
}
template
<
class
F
>
expected
transform_or
(
F
&&
f
)
const
&
{
using
res_t
=
decltype
(
f
(
*
error_
));
static_assert
(
std
::
is_same_v
<
caf
::
error
,
res_t
>
,
"F must return an error"
);
if
(
has_value
())
return
expected
{
std
::
in_place
};
else
return
expected
{
f
(
*
error_
)};
}
template
<
class
F
>
expected
transform_or
(
F
&&
f
)
const
&&
{
using
res_t
=
decltype
(
f
(
std
::
move
(
*
error_
)));
static_assert
(
std
::
is_same_v
<
caf
::
error
,
res_t
>
,
"F must return an error"
);
if
(
has_value
())
return
expected
{};
else
return
expected
{
f
(
std
::
move
(
*
error_
))};
}
}
private:
private:
caf
::
error
error_
;
std
::
optional
<
caf
::
error
>
error_
;
};
};
/// @relates expected
/// @relates expected
...
@@ -399,7 +975,8 @@ inline bool operator!=(const expected<void>& x, const expected<void>& y) {
...
@@ -399,7 +975,8 @@ inline bool operator!=(const expected<void>& x, const expected<void>& y) {
}
}
template
<
>
template
<
>
class
expected
<
unit_t
>
:
public
expected
<
void
>
{
class
[[
deprecated
(
"use expected<void> instead"
)]]
expected
<
unit_t
>
:
public
expected
<
void
>
{
public:
public:
using
expected
<
void
>::
expected
;
using
expected
<
void
>::
expected
;
};
};
...
@@ -422,8 +999,8 @@ inline std::string to_string(const expected<void>& x) {
...
@@ -422,8 +999,8 @@ inline std::string to_string(const expected<void>& x) {
namespace
std
{
namespace
std
{
template
<
class
T
>
template
<
class
T
>
auto
operator
<<
(
ostream
&
oss
,
const
caf
::
expected
<
T
>&
x
)
[[
deprecated
(
"use caf::to_string instead"
)]]
auto
->
decltype
(
oss
<<
*
x
)
{
operator
<<
(
ostream
&
oss
,
const
caf
::
expected
<
T
>&
x
)
->
decltype
(
oss
<<
*
x
)
{
if
(
x
)
if
(
x
)
oss
<<
*
x
;
oss
<<
*
x
;
else
else
...
...
libcaf_core/caf/function_view.hpp
View file @
e6f6dab9
...
@@ -52,20 +52,6 @@ private:
...
@@ -52,20 +52,6 @@ private:
std
::
tuple
<
Ts
...
>*
storage_
;
std
::
tuple
<
Ts
...
>*
storage_
;
};
};
template
<
>
class
function_view_storage
<
unit_t
>
{
public:
using
type
=
function_view_storage
;
explicit
function_view_storage
(
unit_t
&
)
{
// nop
}
void
operator
()()
{
// nop
}
};
struct
CAF_CORE_EXPORT
function_view_storage_catch_all
{
struct
CAF_CORE_EXPORT
function_view_storage_catch_all
{
message
*
storage_
;
message
*
storage_
;
...
@@ -95,11 +81,6 @@ struct function_view_flattened_result<std::tuple<T>> {
...
@@ -95,11 +81,6 @@ struct function_view_flattened_result<std::tuple<T>> {
using
type
=
T
;
using
type
=
T
;
};
};
template
<
>
struct
function_view_flattened_result
<
std
::
tuple
<
void
>>
{
using
type
=
unit_t
;
};
template
<
class
T
>
template
<
class
T
>
using
function_view_flattened_result_t
=
using
function_view_flattened_result_t
=
typename
function_view_flattened_result
<
T
>::
type
;
typename
function_view_flattened_result
<
T
>::
type
;
...
@@ -174,13 +155,24 @@ public:
...
@@ -174,13 +155,24 @@ public:
if
(
!
impl_
)
if
(
!
impl_
)
return
result_type
{
sec
::
bad_function_call
};
return
result_type
{
sec
::
bad_function_call
};
error
err
;
error
err
;
function_view_result
<
value_type
>
result
;
if
constexpr
(
std
::
is_void_v
<
value_type
>
)
{
self_
->
request
(
impl_
,
timeout
,
std
::
forward
<
Ts
>
(
xs
)...)
self_
->
request
(
impl_
,
timeout
,
std
::
forward
<
Ts
>
(
xs
)...)
.
receive
([
&
](
error
&
x
)
{
err
=
std
::
move
(
x
);
},
.
receive
([
&
](
error
&
x
)
{
err
=
std
::
move
(
x
);
},
[]
{});
typename
function_view_storage
<
value_type
>::
type
{
result
.
value
});
if
(
err
)
if
(
err
)
return
result_type
{
err
};
return
result_type
{
err
};
else
return
result_type
{
flatten
(
result
.
value
)};
return
result_type
{};
}
else
{
function_view_result
<
value_type
>
result
;
self_
->
request
(
impl_
,
timeout
,
std
::
forward
<
Ts
>
(
xs
)...)
.
receive
([
&
](
error
&
x
)
{
err
=
std
::
move
(
x
);
},
typename
function_view_storage
<
value_type
>::
type
{
result
.
value
});
if
(
err
)
return
result_type
{
err
};
else
return
result_type
{
flatten
(
result
.
value
)};
}
}
}
void
assign
(
type
x
)
{
void
assign
(
type
x
)
{
...
...
libcaf_core/test/expected.cpp
View file @
e6f6dab9
...
@@ -10,85 +10,928 @@
...
@@ -10,85 +10,928 @@
#include "caf/sec.hpp"
#include "caf/sec.hpp"
#include <cassert>
using
namespace
caf
;
using
namespace
caf
;
using
namespace
std
::
literals
;
namespace
{
namespace
{
class
counted_int
:
public
ref_counted
{
public:
explicit
counted_int
(
int
initial_value
)
:
value_
(
initial_value
)
{
// nop
}
int
value
()
const
{
return
value_
;
}
void
value
(
int
new_value
)
{
value_
=
new_value
;
}
private:
int
value_
;
};
using
counted_int_ptr
=
intrusive_ptr
<
counted_int
>
;
using
e_int
=
expected
<
int
>
;
using
e_int
=
expected
<
int
>
;
using
e_str
=
expected
<
std
::
string
>
;
using
e_str
=
expected
<
std
::
string
>
;
using
e_void
=
expected
<
void
>
;
using
e_iptr
=
expected
<
counted_int_ptr
>
;
}
// namespace
}
// namespace
CAF_TEST
(
both_engaged_equal
)
{
TEST_CASE
(
"expected reports its status via has_value() or operator bool()"
)
{
e_int
x
{
42
};
e_int
x
{
42
};
e_int
y
{
42
};
CHECK
(
x
);
CHECK
(
x
);
CHECK
(
y
);
CHECK
(
x
.
has_value
());
CHECK_EQ
(
x
,
y
);
e_int
y
{
sec
::
runtime_error
};
CHECK_EQ
(
x
,
42
);
CHECK
(
!
y
);
CHECK_EQ
(
y
,
42
);
CHECK
(
!
y
.
has_value
());
}
TEST_CASE
(
"an expected exposed its value via value()"
)
{
auto
i
=
make_counted
<
counted_int
>
(
42
);
SUBCASE
(
"mutable lvalue access"
)
{
auto
ex
=
e_iptr
{
i
};
auto
val
=
counted_int_ptr
{
ex
.
value
()};
// must make a copy
CHECK_EQ
(
val
,
i
);
if
(
CHECK
(
ex
.
has_value
()))
CHECK_EQ
(
ex
.
value
(),
i
);
e_void
ev
;
ev
.
value
();
// fancy no-op
}
SUBCASE
(
"const lvalue access"
)
{
const
auto
ex
=
e_iptr
{
i
};
auto
val
=
counted_int_ptr
{
ex
.
value
()};
// must make a copy
CHECK_EQ
(
val
,
i
);
if
(
CHECK
(
ex
.
has_value
()))
CHECK_EQ
(
ex
.
value
(),
i
);
const
e_void
ev
;
ev
.
value
();
// fancy no-op
}
SUBCASE
(
"mutable rvalue access"
)
{
auto
ex
=
e_iptr
{
i
};
auto
val
=
counted_int_ptr
{
std
::
move
(
ex
).
value
()};
// must move the value
CHECK_EQ
(
val
,
i
);
if
(
CHECK
(
ex
.
has_value
()))
CHECK_EQ
(
ex
.
value
(),
nullptr
);
e_void
ev
;
std
::
move
(
ev
).
value
();
// fancy no-op
}
SUBCASE
(
"const rvalue access"
)
{
const
auto
ex
=
e_iptr
{
i
};
auto
val
=
counted_int_ptr
{
std
::
move
(
ex
).
value
()};
// must make a copy
CHECK_EQ
(
val
,
i
);
if
(
CHECK
(
ex
.
has_value
()))
CHECK_EQ
(
ex
.
value
(),
i
);
const
e_void
ev
;
std
::
move
(
ev
).
value
();
// fancy no-op
}
#ifdef CAF_ENABLE_EXCEPTIONS
SUBCASE
(
"value() throws if has_value() would return false"
)
{
auto
val
=
e_iptr
{
sec
::
runtime_error
};
const
auto
&
cval
=
val
;
CHECK_THROWS_AS
(
val
.
value
(),
std
::
runtime_error
);
CHECK_THROWS_AS
(
std
::
move
(
val
).
value
(),
std
::
runtime_error
);
CHECK_THROWS_AS
(
cval
.
value
(),
std
::
runtime_error
);
CHECK_THROWS_AS
(
std
::
move
(
cval
).
value
(),
std
::
runtime_error
);
}
#endif
}
TEST_CASE
(
"an expected exposed its value via operator*()"
)
{
auto
i
=
make_counted
<
counted_int
>
(
42
);
SUBCASE
(
"mutable lvalue access"
)
{
auto
ex
=
e_iptr
{
i
};
auto
val
=
counted_int_ptr
{
*
ex
};
// must make a copy
CHECK_EQ
(
val
,
i
);
if
(
CHECK
(
ex
.
has_value
()))
CHECK_EQ
(
*
ex
,
i
);
e_void
ev
;
*
ev
;
// fancy no-op
}
SUBCASE
(
"const lvalue access"
)
{
const
auto
ex
=
e_iptr
{
i
};
auto
val
=
counted_int_ptr
{
*
ex
};
// must make a copy
CHECK_EQ
(
val
,
i
);
if
(
CHECK
(
ex
.
has_value
()))
CHECK_EQ
(
*
ex
,
i
);
const
e_void
ev
;
*
ev
;
// fancy no-op
}
SUBCASE
(
"mutable rvalue access"
)
{
auto
ex
=
e_iptr
{
i
};
auto
val
=
counted_int_ptr
{
*
std
::
move
(
ex
)};
// must move the value
CHECK_EQ
(
val
,
i
);
if
(
CHECK
(
ex
.
has_value
()))
CHECK_EQ
(
*
ex
,
nullptr
);
e_void
ev
;
*
std
::
move
(
ev
);
// fancy no-op
}
SUBCASE
(
"const rvalue access"
)
{
const
auto
ex
=
e_iptr
{
i
};
auto
val
=
counted_int_ptr
{
*
std
::
move
(
ex
)};
// must make a copy
CHECK_EQ
(
val
,
i
);
if
(
CHECK
(
ex
.
has_value
()))
CHECK_EQ
(
*
ex
,
i
);
const
e_void
ev
;
*
std
::
move
(
ev
);
// fancy no-op
}
}
TEST_CASE
(
"an expected exposed its value via operator->()"
)
{
SUBCASE
(
"mutable lvalue access"
)
{
auto
val
=
e_str
{
std
::
in_place
,
"foo"
};
CHECK_EQ
(
val
->
c_str
(),
"foo"
s
);
val
->
push_back
(
'!'
);
CHECK_EQ
(
val
->
c_str
(),
"foo!"
s
);
}
SUBCASE
(
"const lvalue access"
)
{
const
auto
val
=
e_str
{
std
::
in_place
,
"foo"
};
CHECK_EQ
(
val
->
c_str
(),
"foo"
s
);
using
pointer_t
=
decltype
(
val
.
operator
->
());
static_assert
(
std
::
is_same_v
<
pointer_t
,
const
std
::
string
*>
);
}
}
TEST_CASE
(
"value_or() returns the stored value or a fallback"
)
{
auto
i
=
make_counted
<
counted_int
>
(
42
);
auto
j
=
make_counted
<
counted_int
>
(
24
);
SUBCASE
(
"lvalue access with value"
)
{
auto
val
=
e_iptr
{
i
};
auto
k
=
counted_int_ptr
{
val
.
value_or
(
j
)};
CHECK_EQ
(
val
,
i
);
CHECK_EQ
(
k
,
i
);
}
SUBCASE
(
"lvalue access with error"
)
{
auto
val
=
e_iptr
{
sec
::
runtime_error
};
auto
k
=
counted_int_ptr
{
val
.
value_or
(
j
)};
CHECK_EQ
(
val
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
k
,
j
);
}
SUBCASE
(
"rvalue access with value"
)
{
auto
val
=
e_iptr
{
i
};
auto
k
=
counted_int_ptr
{
std
::
move
(
val
).
value_or
(
j
)};
CHECK_EQ
(
val
,
nullptr
);
CHECK_EQ
(
k
,
i
);
}
SUBCASE
(
"rvalue access with error"
)
{
auto
val
=
e_iptr
{
sec
::
runtime_error
};
auto
k
=
counted_int_ptr
{
std
::
move
(
val
).
value_or
(
j
)};
CHECK_EQ
(
val
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
k
,
j
);
}
}
}
CAF_TEST
(
both_engaged_not_equal
)
{
TEST_CASE
(
"emplace destroys an old value or error and constructs a new value"
)
{
SUBCASE
(
"non-void value type"
)
{
e_int
x
{
42
};
CHECK_EQ
(
x
.
value
(),
42
);
x
.
emplace
(
23
);
CHECK_EQ
(
x
.
value
(),
23
);
e_int
y
{
sec
::
runtime_error
};
CHECK
(
!
y
);
y
.
emplace
(
23
);
CHECK_EQ
(
y
.
value
(),
23
);
}
SUBCASE
(
"void value type"
)
{
e_void
x
;
CHECK
(
x
.
has_value
());
x
.
emplace
();
CHECK
(
x
.
has_value
());
e_void
y
{
sec
::
runtime_error
};
CHECK
(
!
y
);
y
.
emplace
();
CHECK
(
y
);
}
}
TEST_CASE
(
"swap exchanges the content of two expected"
)
{
SUBCASE
(
"lhs: value, rhs: value"
)
{
e_str
lhs
{
std
::
in_place
,
"this is value 1"
};
e_str
rhs
{
std
::
in_place
,
"this is value 2"
};
CHECK_EQ
(
lhs
,
"this is value 1"
s
);
CHECK_EQ
(
rhs
,
"this is value 2"
s
);
lhs
.
swap
(
rhs
);
CHECK_EQ
(
lhs
,
"this is value 2"
s
);
CHECK_EQ
(
rhs
,
"this is value 1"
s
);
}
SUBCASE
(
"lhs: value, rhs: error"
)
{
e_str
lhs
{
std
::
in_place
,
"this is a value"
};
e_str
rhs
{
sec
::
runtime_error
};
CHECK_EQ
(
lhs
,
"this is a value"
s
);
CHECK_EQ
(
rhs
,
error
{
sec
::
runtime_error
});
lhs
.
swap
(
rhs
);
CHECK_EQ
(
lhs
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
rhs
,
"this is a value"
s
);
}
SUBCASE
(
"lhs: error, rhs: value"
)
{
e_str
lhs
{
sec
::
runtime_error
};
e_str
rhs
{
std
::
in_place
,
"this is a value"
};
CHECK_EQ
(
lhs
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
rhs
,
"this is a value"
s
);
lhs
.
swap
(
rhs
);
CHECK_EQ
(
lhs
,
"this is a value"
s
);
CHECK_EQ
(
rhs
,
error
{
sec
::
runtime_error
});
}
SUBCASE
(
"lhs: error, rhs: error"
)
{
e_str
lhs
{
sec
::
runtime_error
};
e_str
rhs
{
sec
::
logic_error
};
CHECK_EQ
(
lhs
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
rhs
,
error
{
sec
::
logic_error
});
lhs
.
swap
(
rhs
);
CHECK_EQ
(
lhs
,
error
{
sec
::
logic_error
});
CHECK_EQ
(
rhs
,
error
{
sec
::
runtime_error
});
}
SUBCASE
(
"lhs: void, rhs: void"
)
{
e_void
lhs
;
e_void
rhs
;
CHECK
(
lhs
);
CHECK
(
rhs
);
lhs
.
swap
(
rhs
);
// fancy no-op
CHECK
(
lhs
);
CHECK
(
rhs
);
}
SUBCASE
(
"lhs: void, rhs: error"
)
{
e_void
lhs
;
e_void
rhs
{
sec
::
runtime_error
};
CHECK
(
lhs
);
CHECK_EQ
(
rhs
,
error
{
sec
::
runtime_error
});
lhs
.
swap
(
rhs
);
CHECK_EQ
(
lhs
,
error
{
sec
::
runtime_error
});
CHECK
(
rhs
);
}
SUBCASE
(
"lhs: error, rhs: void"
)
{
e_void
lhs
{
sec
::
runtime_error
};
e_void
rhs
;
CHECK_EQ
(
lhs
,
error
{
sec
::
runtime_error
});
CHECK
(
rhs
);
lhs
.
swap
(
rhs
);
CHECK
(
lhs
);
CHECK_EQ
(
rhs
,
error
{
sec
::
runtime_error
});
}
SUBCASE
(
"lhs: error, rhs: error"
)
{
e_void
lhs
{
sec
::
runtime_error
};
e_void
rhs
{
sec
::
logic_error
};
CHECK_EQ
(
lhs
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
rhs
,
error
{
sec
::
logic_error
});
lhs
.
swap
(
rhs
);
CHECK_EQ
(
lhs
,
error
{
sec
::
logic_error
});
CHECK_EQ
(
rhs
,
error
{
sec
::
runtime_error
});
}
}
TEST_CASE
(
"an expected can be compared to its expected type and errors"
)
{
SUBCASE
(
"non-void value type"
)
{
e_int
x
{
42
};
CHECK_EQ
(
x
,
42
);
CHECK_NE
(
x
,
24
);
CHECK_NE
(
x
,
make_error
(
sec
::
runtime_error
));
e_int
y
{
sec
::
runtime_error
};
CHECK_NE
(
y
,
42
);
CHECK_NE
(
y
,
24
);
CHECK_EQ
(
y
,
make_error
(
sec
::
runtime_error
));
CHECK_NE
(
y
,
make_error
(
sec
::
logic_error
));
}
SUBCASE
(
"void value type"
)
{
e_void
x
;
CHECK
(
x
);
e_void
y
{
sec
::
runtime_error
};
CHECK_EQ
(
y
,
make_error
(
sec
::
runtime_error
));
CHECK_NE
(
y
,
make_error
(
sec
::
logic_error
));
}
}
TEST_CASE
(
"two expected with the same value are equal"
)
{
SUBCASE
(
"non-void value type"
)
{
e_int
x
{
42
};
e_int
y
{
42
};
CHECK_EQ
(
x
,
y
);
CHECK_EQ
(
y
,
x
);
}
SUBCASE
(
"void value type"
)
{
e_void
x
;
e_void
y
;
CHECK_EQ
(
x
,
y
);
CHECK_EQ
(
y
,
x
);
}
}
TEST_CASE
(
"two expected with different values are unequal"
)
{
e_int
x
{
42
};
e_int
x
{
42
};
e_int
y
{
24
};
e_int
y
{
24
};
CHECK
(
x
);
CHECK
(
y
);
CHECK_NE
(
x
,
y
);
CHECK_NE
(
x
,
y
);
CHECK_NE
(
x
,
sec
::
unexpected_message
);
CHECK_NE
(
y
,
x
);
CHECK_NE
(
y
,
sec
::
unexpected_message
);
CHECK_EQ
(
x
,
42
);
CHECK_EQ
(
y
,
24
);
}
}
CAF_TEST
(
engaged_plus_not_engaged
)
{
TEST_CASE
(
"an expected with value is not equal to an expected with an error"
)
{
e_int
x
{
42
};
SUBCASE
(
"non-void value type"
)
{
e_int
y
{
sec
::
unexpected_message
};
// Use the same "underlying value" for both objects.
CHECK
(
x
);
e_int
x
{
static_cast
<
int
>
(
sec
::
runtime_error
)};
CHECK
(
!
y
);
e_int
y
{
sec
::
runtime_error
};
CHECK_EQ
(
x
,
42
);
CHECK_NE
(
x
,
y
);
CHECK_EQ
(
y
,
sec
::
unexpected_message
);
CHECK_NE
(
y
,
x
);
CHECK_NE
(
x
,
sec
::
unexpected_message
);
}
CHECK_NE
(
x
,
y
);
SUBCASE
(
"void value type"
)
{
CHECK_NE
(
y
,
42
);
e_void
x
;
CHECK_NE
(
y
,
sec
::
unsupported_sys_key
);
e_void
y
{
sec
::
runtime_error
};
CHECK_NE
(
x
,
y
);
CHECK_NE
(
y
,
x
);
}
}
}
CAF_TEST
(
both_not_engaged
)
{
TEST_CASE
(
"two expected with the same error are equal"
)
{
e_int
x
{
sec
::
unexpected_message
};
SUBCASE
(
"non-void value type"
)
{
e_int
y
{
sec
::
unexpected_message
};
e_int
x
{
sec
::
runtime_error
};
CHECK
(
!
x
);
e_int
y
{
sec
::
runtime_error
};
CHECK
(
!
y
);
CHECK_EQ
(
x
,
y
);
CHECK_EQ
(
x
,
y
);
CHECK_EQ
(
y
,
x
);
CHECK_EQ
(
x
,
sec
::
unexpected_message
);
}
CHECK_EQ
(
y
,
sec
::
unexpected_message
);
SUBCASE
(
"void value type"
)
{
CHECK_EQ
(
x
.
error
(),
y
.
error
());
e_void
x
{
sec
::
runtime_error
};
CHECK_NE
(
x
,
sec
::
unsupported_sys_key
);
e_void
y
{
sec
::
runtime_error
};
CHECK_NE
(
y
,
sec
::
unsupported_sys_key
);
CHECK_EQ
(
x
,
y
);
}
CHECK_EQ
(
y
,
x
);
}
CAF_TEST
(
move_and_copy
)
{
}
e_str
x
{
sec
::
unexpected_message
};
e_str
y
{
"hello"
};
TEST_CASE
(
"two expected with different errors are unequal"
)
{
x
=
"hello"
;
SUBCASE
(
"non-void value type"
)
{
CHECK_NE
(
x
,
sec
::
unexpected_message
);
e_int
x
{
sec
::
logic_error
};
CHECK_EQ
(
x
,
"hello"
);
e_int
y
{
sec
::
runtime_error
};
CHECK_EQ
(
x
,
y
);
CHECK_NE
(
x
,
y
);
y
=
"world"
;
CHECK_NE
(
y
,
x
);
x
=
std
::
move
(
y
);
}
CHECK_EQ
(
x
,
"world"
);
SUBCASE
(
"void value type"
)
{
e_str
z
{
std
::
move
(
x
)};
e_void
x
{
sec
::
logic_error
};
CHECK_EQ
(
z
,
"world"
);
e_void
y
{
sec
::
runtime_error
};
e_str
z_cpy
{
z
};
CHECK_NE
(
x
,
y
);
CHECK_EQ
(
z_cpy
,
"world"
);
CHECK_NE
(
y
,
x
);
CHECK_EQ
(
z
,
z_cpy
);
}
z
=
e_str
{
sec
::
unsupported_sys_key
};
}
CHECK_NE
(
z
,
z_cpy
);
CHECK_EQ
(
z
,
sec
::
unsupported_sys_key
);
TEST_CASE
(
"expected is copyable"
)
{
}
SUBCASE
(
"non-void value type"
)
{
SUBCASE
(
"copy-constructible"
)
{
CAF_TEST
(
construction_with_none
)
{
e_int
x
{
42
};
e_int
y
{
x
};
CHECK_EQ
(
x
,
y
);
}
SUBCASE
(
"copy-assignable"
)
{
e_int
x
{
42
};
e_int
y
{
0
};
CHECK_NE
(
x
,
y
);
y
=
x
;
CHECK_EQ
(
x
,
y
);
}
}
SUBCASE
(
"void value type"
)
{
SUBCASE
(
"copy-constructible"
)
{
e_void
x
;
e_void
y
{
x
};
CHECK_EQ
(
x
,
y
);
}
SUBCASE
(
"copy-assignable"
)
{
e_void
x
;
e_void
y
;
CHECK_EQ
(
x
,
y
);
y
=
x
;
CHECK_EQ
(
x
,
y
);
}
}
}
TEST_CASE
(
"expected is movable"
)
{
SUBCASE
(
"non-void value type"
)
{
SUBCASE
(
"move-constructible"
)
{
auto
iptr
=
make_counted
<
counted_int
>
(
42
);
CHECK_EQ
(
iptr
->
get_reference_count
(),
1u
);
e_iptr
x
{
std
::
in_place
,
iptr
};
e_iptr
y
{
std
::
move
(
x
)};
CHECK_EQ
(
iptr
->
get_reference_count
(),
2u
);
CHECK_NE
(
x
,
iptr
);
CHECK_EQ
(
y
,
iptr
);
}
SUBCASE
(
"move-assignable"
)
{
auto
iptr
=
make_counted
<
counted_int
>
(
42
);
CHECK_EQ
(
iptr
->
get_reference_count
(),
1u
);
e_iptr
x
{
std
::
in_place
,
iptr
};
e_iptr
y
{
std
::
in_place
,
nullptr
};
CHECK_EQ
(
x
,
iptr
);
CHECK_NE
(
y
,
iptr
);
y
=
std
::
move
(
x
);
CHECK_EQ
(
iptr
->
get_reference_count
(),
2u
);
CHECK_NE
(
x
,
iptr
);
CHECK_EQ
(
y
,
iptr
);
}
}
SUBCASE
(
"non-void value type"
)
{
SUBCASE
(
"move-constructible"
)
{
e_void
x
;
e_void
y
{
std
::
move
(
x
)};
CHECK_EQ
(
x
,
y
);
}
SUBCASE
(
"move-assignable"
)
{
e_void
x
;
e_void
y
;
CHECK_EQ
(
x
,
y
);
y
=
std
::
move
(
x
);
CHECK_EQ
(
x
,
y
);
}
}
}
TEST_CASE
(
"expected is convertible from none"
)
{
e_int
x
{
none
};
e_int
x
{
none
};
CHECK
(
!
x
);
if
(
CHECK
(
!
x
))
CHECK
(
!
x
.
error
());
CHECK
(
!
x
.
error
());
e_void
y
{
none
};
if
(
CHECK
(
!
y
))
CHECK
(
!
y
.
error
());
}
TEST_CASE
(
"and_then composes a chain of functions returning an expected"
)
{
SUBCASE
(
"non-void value type"
)
{
auto
inc
=
[](
counted_int_ptr
ptr
)
{
ptr
->
value
(
ptr
->
value
()
+
1
);
return
e_iptr
{
std
::
move
(
ptr
)};
};
SUBCASE
(
"and_then makes copies when called on a mutable lvalue"
)
{
auto
i
=
make_counted
<
counted_int
>
(
1
);
auto
v1
=
e_iptr
{
std
::
in_place
,
i
};
auto
v2
=
v1
.
and_then
(
inc
);
CHECK_EQ
(
v1
,
i
);
CHECK_EQ
(
v2
,
i
);
CHECK_EQ
(
i
->
value
(),
2
);
}
SUBCASE
(
"and_then makes copies when called on a const lvalue"
)
{
auto
i
=
make_counted
<
counted_int
>
(
1
);
const
auto
v1
=
e_iptr
{
std
::
in_place
,
i
};
const
auto
v2
=
v1
.
and_then
(
inc
);
CHECK_EQ
(
v1
,
i
);
CHECK_EQ
(
v2
,
i
);
CHECK_EQ
(
i
->
value
(),
2
);
}
SUBCASE
(
"and_then moves when called on a mutable rvalue"
)
{
auto
i
=
make_counted
<
counted_int
>
(
1
);
auto
v1
=
e_iptr
{
std
::
in_place
,
i
};
auto
v2
=
std
::
move
(
v1
).
and_then
(
inc
);
CHECK_EQ
(
v1
,
nullptr
);
CHECK_EQ
(
v2
,
i
);
CHECK_EQ
(
i
->
value
(),
2
);
}
SUBCASE
(
"and_then makes copies when called on a const rvalue"
)
{
auto
i
=
make_counted
<
counted_int
>
(
1
);
const
auto
v1
=
e_iptr
{
std
::
in_place
,
i
};
const
auto
v2
=
std
::
move
(
v1
).
and_then
(
inc
);
CHECK_EQ
(
v1
,
i
);
CHECK_EQ
(
v2
,
i
);
CHECK_EQ
(
i
->
value
(),
2
);
}
}
SUBCASE
(
"void value type"
)
{
auto
called
=
false
;
auto
fn
=
[
&
called
]
{
called
=
true
;
return
e_void
{};
};
SUBCASE
(
"mutable lvalue"
)
{
called
=
false
;
auto
v1
=
e_void
{};
auto
v2
=
v1
.
and_then
(
fn
);
CHECK
(
called
);
CHECK_EQ
(
v1
,
v2
);
}
SUBCASE
(
"const lvalue"
)
{
called
=
false
;
const
auto
v1
=
e_void
{};
const
auto
v2
=
v1
.
and_then
(
fn
);
CHECK
(
called
);
CHECK_EQ
(
v1
,
v2
);
}
SUBCASE
(
"mutable rvalue"
)
{
called
=
false
;
auto
v1
=
e_void
{};
auto
v2
=
std
::
move
(
v1
).
and_then
(
fn
);
CHECK
(
called
);
CHECK_EQ
(
v1
,
v2
);
}
SUBCASE
(
"const rvalue"
)
{
called
=
false
;
const
auto
v1
=
e_void
{};
const
auto
v2
=
std
::
move
(
v1
).
and_then
(
fn
);
CHECK
(
called
);
CHECK_EQ
(
v1
,
v2
);
}
}
}
TEST_CASE
(
"and_then does nothing when called with an error"
)
{
SUBCASE
(
"non-void value type"
)
{
auto
inc
=
[](
counted_int_ptr
ptr
)
{
ptr
->
value
(
ptr
->
value
()
+
1
);
return
e_iptr
{
std
::
move
(
ptr
)};
};
auto
v1
=
e_iptr
{
sec
::
runtime_error
};
auto
v2
=
v1
.
and_then
(
inc
);
// mutable lvalue
const
auto
v3
=
std
::
move
(
v2
).
and_then
(
inc
);
// mutable rvalue
const
auto
v4
=
v3
.
and_then
(
inc
);
// const lvalue
auto
v5
=
std
::
move
(
v4
).
and_then
(
inc
);
// const rvalue
CHECK_EQ
(
v1
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v2
,
error
{});
// has been moved-from
CHECK_EQ
(
v3
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v4
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v5
,
error
{
sec
::
runtime_error
});
}
SUBCASE
(
"void value type"
)
{
auto
fn
=
[]
{
return
e_void
{};
};
auto
v1
=
e_void
{
sec
::
runtime_error
};
auto
v2
=
v1
.
and_then
(
fn
);
// mutable lvalue
const
auto
v3
=
std
::
move
(
v2
).
and_then
(
fn
);
// mutable rvalue
const
auto
v4
=
v3
.
and_then
(
fn
);
// const lvalue
auto
v5
=
std
::
move
(
v4
).
and_then
(
fn
);
// const rvalue
CHECK_EQ
(
v1
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v2
,
error
{});
// has been moved-from
CHECK_EQ
(
v3
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v4
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v5
,
error
{
sec
::
runtime_error
});
}
}
TEST_CASE
(
"transform applies a function to change the value"
)
{
SUBCASE
(
"non-void value type"
)
{
auto
inc
=
[](
counted_int_ptr
ptr
)
{
return
make_counted
<
counted_int
>
(
ptr
->
value
()
+
1
);
};
SUBCASE
(
"transform makes copies when called on a mutable lvalue"
)
{
auto
i
=
make_counted
<
counted_int
>
(
1
);
auto
v1
=
e_iptr
{
std
::
in_place
,
i
};
auto
v2
=
v1
.
transform
(
inc
);
CHECK_EQ
(
i
->
value
(),
1
);
CHECK_EQ
(
v1
,
i
);
if
(
CHECK
(
v2
))
CHECK_EQ
((
*
v2
)
->
value
(),
2
);
}
SUBCASE
(
"transform makes copies when called on a const lvalue"
)
{
auto
i
=
make_counted
<
counted_int
>
(
1
);
const
auto
v1
=
e_iptr
{
std
::
in_place
,
i
};
const
auto
v2
=
v1
.
transform
(
inc
);
CHECK_EQ
(
i
->
value
(),
1
);
CHECK_EQ
(
v1
,
i
);
if
(
CHECK
(
v2
))
CHECK_EQ
((
*
v2
)
->
value
(),
2
);
}
SUBCASE
(
"transform moves when called on a mutable rvalue"
)
{
auto
i
=
make_counted
<
counted_int
>
(
1
);
auto
v1
=
e_iptr
{
std
::
in_place
,
i
};
auto
v2
=
std
::
move
(
v1
).
transform
(
inc
);
CHECK_EQ
(
i
->
value
(),
1
);
CHECK_EQ
(
v1
,
nullptr
);
if
(
CHECK
(
v2
))
CHECK_EQ
((
*
v2
)
->
value
(),
2
);
}
SUBCASE
(
"transform makes copies when called on a const rvalue"
)
{
auto
i
=
make_counted
<
counted_int
>
(
1
);
const
auto
v1
=
e_iptr
{
std
::
in_place
,
i
};
const
auto
v2
=
std
::
move
(
v1
).
transform
(
inc
);
CHECK_EQ
(
i
->
value
(),
1
);
CHECK_EQ
(
v1
,
i
);
if
(
CHECK
(
v2
))
CHECK_EQ
((
*
v2
)
->
value
(),
2
);
}
}
SUBCASE
(
"void value type"
)
{
auto
fn
=
[]
{
return
42
;
};
SUBCASE
(
"mutable lvalue"
)
{
auto
v1
=
e_void
{};
auto
v2
=
v1
.
transform
(
fn
);
CHECK_EQ
(
v2
,
42
);
}
SUBCASE
(
"const lvalue"
)
{
const
auto
v1
=
e_void
{};
const
auto
v2
=
v1
.
transform
(
fn
);
CHECK_EQ
(
v2
,
42
);
}
SUBCASE
(
"mutable rvalue"
)
{
auto
v1
=
e_void
{};
auto
v2
=
std
::
move
(
v1
).
transform
(
fn
);
CHECK_EQ
(
v2
,
42
);
}
SUBCASE
(
"const rvalue"
)
{
const
auto
v1
=
e_void
{};
const
auto
v2
=
std
::
move
(
v1
).
transform
(
fn
);
CHECK_EQ
(
v2
,
42
);
}
}
}
TEST_CASE
(
"transform does nothing when called with an error"
)
{
SUBCASE
(
"non-void value type"
)
{
auto
inc
=
[](
counted_int_ptr
ptr
)
{
return
make_counted
<
counted_int
>
(
ptr
->
value
()
+
1
);
};
auto
v1
=
e_iptr
{
sec
::
runtime_error
};
auto
v2
=
v1
.
transform
(
inc
);
// mutable lvalue
const
auto
v3
=
std
::
move
(
v2
).
transform
(
inc
);
// mutable rvalue
const
auto
v4
=
v3
.
transform
(
inc
);
// const lvalue
auto
v5
=
std
::
move
(
v4
).
transform
(
inc
);
// const rvalue
CHECK_EQ
(
v1
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v2
,
error
{});
// has been moved-from
CHECK_EQ
(
v3
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v4
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v5
,
error
{
sec
::
runtime_error
});
}
SUBCASE
(
"void value type"
)
{
auto
fn
=
[]
{};
auto
v1
=
e_void
{
sec
::
runtime_error
};
auto
v2
=
v1
.
transform
(
fn
);
// mutable lvalue
const
auto
v3
=
std
::
move
(
v2
).
transform
(
fn
);
// mutable rvalue
const
auto
v4
=
v3
.
transform
(
fn
);
// const lvalue
auto
v5
=
std
::
move
(
v4
).
transform
(
fn
);
// const rvalue
CHECK_EQ
(
v1
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v2
,
error
{});
// has been moved-from
CHECK_EQ
(
v3
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v4
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v5
,
error
{
sec
::
runtime_error
});
}
}
namespace
{
template
<
class
T
,
bool
WrapIntoExpected
>
struct
next_error_t
{
auto
operator
()(
const
error
&
err
)
const
{
assert
(
err
.
category
()
==
type_id_v
<
sec
>
);
auto
code
=
err
.
code
()
+
1
;
if
constexpr
(
WrapIntoExpected
)
return
expected
<
T
>
{
make_error
(
static_cast
<
sec
>
(
code
))};
else
return
make_error
(
static_cast
<
sec
>
(
code
));
}
auto
operator
()(
error
&&
err
)
const
{
assert
(
err
.
category
()
==
type_id_v
<
sec
>
);
auto
code
=
err
.
code
()
+
1
;
err
=
make_error
(
static_cast
<
sec
>
(
code
));
if
constexpr
(
WrapIntoExpected
)
return
expected
<
T
>
{
std
::
move
(
err
)};
else
return
std
::
move
(
err
);
}
};
}
// namespace
TEST_CASE
(
"or_else may replace the error or set a default"
)
{
SUBCASE
(
"non-void value type"
)
{
next_error_t
<
int
,
true
>
next_error
;
auto
set_fallback
=
[](
auto
&&
err
)
{
if
constexpr
(
std
::
is_same_v
<
decltype
(
err
),
error
&&>
)
{
// Just for testing that we get indeed an rvalue in the test.
err
=
error
{};
}
return
e_int
{
42
};
};
SUBCASE
(
"or_else makes copies when called on a mutable lvalue"
)
{
auto
v1
=
e_int
{
sec
::
runtime_error
};
auto
v2
=
v1
.
or_else
(
next_error
);
CHECK_EQ
(
v1
,
sec
::
runtime_error
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
auto
v3
=
v2
.
or_else
(
set_fallback
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
CHECK_EQ
(
v3
,
42
);
}
SUBCASE
(
"or_else makes copies when called on a const lvalue"
)
{
const
auto
v1
=
e_int
{
sec
::
runtime_error
};
const
auto
v2
=
v1
.
or_else
(
next_error
);
CHECK_EQ
(
v1
,
sec
::
runtime_error
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
const
auto
v3
=
v2
.
or_else
(
set_fallback
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
CHECK_EQ
(
v3
,
42
);
}
SUBCASE
(
"or_else moves when called on a mutable rvalue"
)
{
auto
v1
=
e_int
{
sec
::
runtime_error
};
auto
v2
=
std
::
move
(
v1
).
or_else
(
next_error
);
CHECK_EQ
(
v1
,
error
{});
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
auto
v3
=
std
::
move
(
v2
).
or_else
(
set_fallback
);
CHECK_EQ
(
v2
,
error
{});
CHECK_EQ
(
v3
,
42
);
}
SUBCASE
(
"or_else makes copies when called on a const rvalue"
)
{
const
auto
v1
=
e_int
{
sec
::
runtime_error
};
const
auto
v2
=
std
::
move
(
v1
).
or_else
(
next_error
);
CHECK_EQ
(
v1
,
sec
::
runtime_error
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
const
auto
v3
=
std
::
move
(
v2
).
or_else
(
set_fallback
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
CHECK_EQ
(
v3
,
42
);
}
}
SUBCASE
(
"void value type"
)
{
next_error_t
<
void
,
true
>
next_error
;
auto
set_fallback
=
[](
auto
&&
err
)
{
if
constexpr
(
std
::
is_same_v
<
decltype
(
err
),
error
&&>
)
{
// Just for testing that we get indeed an rvalue in the test.
err
=
error
{};
}
return
e_void
{};
};
SUBCASE
(
"or_else makes copies when called on a mutable lvalue"
)
{
auto
v1
=
e_void
{
sec
::
runtime_error
};
auto
v2
=
v1
.
or_else
(
next_error
);
CHECK_EQ
(
v1
,
sec
::
runtime_error
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
auto
v3
=
v2
.
or_else
(
set_fallback
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
CHECK
(
v3
);
}
SUBCASE
(
"or_else makes copies when called on a const lvalue"
)
{
const
auto
v1
=
e_void
{
sec
::
runtime_error
};
const
auto
v2
=
v1
.
or_else
(
next_error
);
CHECK_EQ
(
v1
,
sec
::
runtime_error
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
const
auto
v3
=
v2
.
or_else
(
set_fallback
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
CHECK
(
v3
);
}
SUBCASE
(
"or_else moves when called on a mutable rvalue"
)
{
auto
v1
=
e_void
{
sec
::
runtime_error
};
auto
v2
=
std
::
move
(
v1
).
or_else
(
next_error
);
CHECK_EQ
(
v1
,
error
{});
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
auto
v3
=
std
::
move
(
v2
).
or_else
(
set_fallback
);
CHECK_EQ
(
v2
,
error
{});
CHECK
(
v3
);
}
SUBCASE
(
"or_else makes copies when called on a const rvalue"
)
{
const
auto
v1
=
e_void
{
sec
::
runtime_error
};
const
auto
v2
=
std
::
move
(
v1
).
or_else
(
next_error
);
CHECK_EQ
(
v1
,
sec
::
runtime_error
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
const
auto
v3
=
std
::
move
(
v2
).
or_else
(
set_fallback
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
CHECK
(
v3
);
}
}
}
TEST_CASE
(
"or_else leaves the expected unchanged when returning void"
)
{
SUBCASE
(
"non-void value type"
)
{
auto
i
=
0
;
auto
inc
=
[
&
i
](
auto
&&
)
{
++
i
;
};
auto
v1
=
e_int
{
sec
::
runtime_error
};
auto
v2
=
v1
.
or_else
(
inc
);
// mutable lvalue
const
auto
v3
=
std
::
move
(
v2
).
or_else
(
inc
);
// mutable rvalue
const
auto
v4
=
v3
.
or_else
(
inc
);
// const lvalue
auto
v5
=
std
::
move
(
v4
).
or_else
(
inc
);
// const rvalue
CHECK_EQ
(
v1
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v2
,
error
{});
// has been moved-from
CHECK_EQ
(
v3
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v4
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v5
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
i
,
4
);
}
SUBCASE
(
"void value type"
)
{
auto
i
=
0
;
auto
inc
=
[
&
i
](
auto
&&
)
{
++
i
;
};
auto
v1
=
e_void
{
sec
::
runtime_error
};
auto
v2
=
v1
.
or_else
(
inc
);
// mutable lvalue
const
auto
v3
=
std
::
move
(
v2
).
or_else
(
inc
);
// mutable rvalue
const
auto
v4
=
v3
.
or_else
(
inc
);
// const lvalue
auto
v5
=
std
::
move
(
v4
).
or_else
(
inc
);
// const rvalue
CHECK_EQ
(
v1
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v2
,
error
{});
// has been moved-from
CHECK_EQ
(
v3
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v4
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
v5
,
error
{
sec
::
runtime_error
});
CHECK_EQ
(
i
,
4
);
}
}
TEST_CASE
(
"or_else does nothing when called with a value"
)
{
SUBCASE
(
"non-void value type"
)
{
auto
uh_oh
=
[](
auto
&&
)
{
FAIL
(
"uh-oh called!"
);
};
auto
i
=
make_counted
<
counted_int
>
(
1
);
auto
v1
=
e_iptr
{
std
::
in_place
,
i
};
auto
v2
=
v1
.
or_else
(
uh_oh
);
// mutable lvalue
const
auto
v3
=
std
::
move
(
v2
).
or_else
(
uh_oh
);
// mutable rvalue
const
auto
v4
=
v3
.
or_else
(
uh_oh
);
// const lvalue
auto
v5
=
std
::
move
(
v4
).
or_else
(
uh_oh
);
// const rvalue
CHECK_EQ
(
v1
,
i
);
CHECK_EQ
(
v2
,
nullptr
);
// has been moved-from
CHECK_EQ
(
v3
,
i
);
CHECK_EQ
(
v4
,
i
);
CHECK_EQ
(
v5
,
i
);
}
SUBCASE
(
"void value type"
)
{
auto
uh_oh
=
[](
auto
&&
)
{
FAIL
(
"uh-oh called!"
);
};
auto
v1
=
e_void
{};
auto
v2
=
v1
.
or_else
(
uh_oh
);
// mutable lvalue
const
auto
v3
=
std
::
move
(
v2
).
or_else
(
uh_oh
);
// mutable rvalue
const
auto
v4
=
v3
.
or_else
(
uh_oh
);
// const lvalue
auto
v5
=
std
::
move
(
v4
).
or_else
(
uh_oh
);
// const rvalue
CHECK
(
v1
);
CHECK
(
v2
);
CHECK
(
v3
);
CHECK
(
v4
);
CHECK
(
v5
);
}
}
TEST_CASE
(
"transform_or may replace the error or set a default"
)
{
SUBCASE
(
"non-void value type"
)
{
next_error_t
<
int
,
false
>
next_error
;
SUBCASE
(
"transform_or makes copies when called on a mutable lvalue"
)
{
auto
v1
=
e_int
{
sec
::
runtime_error
};
auto
v2
=
v1
.
transform_or
(
next_error
);
CHECK_EQ
(
v1
,
sec
::
runtime_error
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
}
SUBCASE
(
"transform_or makes copies when called on a const lvalue"
)
{
const
auto
v1
=
e_int
{
sec
::
runtime_error
};
const
auto
v2
=
v1
.
transform_or
(
next_error
);
CHECK_EQ
(
v1
,
sec
::
runtime_error
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
}
SUBCASE
(
"transform_or moves when called on a mutable rvalue"
)
{
auto
v1
=
e_int
{
sec
::
runtime_error
};
auto
v2
=
std
::
move
(
v1
).
transform_or
(
next_error
);
CHECK_EQ
(
v1
,
error
{});
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
}
SUBCASE
(
"transform_or makes copies when called on a const rvalue"
)
{
const
auto
v1
=
e_int
{
sec
::
runtime_error
};
const
auto
v2
=
std
::
move
(
v1
).
transform_or
(
next_error
);
CHECK_EQ
(
v1
,
sec
::
runtime_error
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
}
}
SUBCASE
(
"void value type"
)
{
next_error_t
<
void
,
false
>
next_error
;
SUBCASE
(
"transform_or makes copies when called on a mutable lvalue"
)
{
auto
v1
=
e_void
{
sec
::
runtime_error
};
auto
v2
=
v1
.
transform_or
(
next_error
);
CHECK_EQ
(
v1
,
sec
::
runtime_error
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
}
SUBCASE
(
"transform_or makes copies when called on a const lvalue"
)
{
const
auto
v1
=
e_void
{
sec
::
runtime_error
};
const
auto
v2
=
v1
.
transform_or
(
next_error
);
CHECK_EQ
(
v1
,
sec
::
runtime_error
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
}
SUBCASE
(
"transform_or moves when called on a mutable rvalue"
)
{
auto
v1
=
e_void
{
sec
::
runtime_error
};
auto
v2
=
std
::
move
(
v1
).
transform_or
(
next_error
);
CHECK_EQ
(
v1
,
error
{});
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
}
SUBCASE
(
"transform_or makes copies when called on a const rvalue"
)
{
const
auto
v1
=
e_void
{
sec
::
runtime_error
};
const
auto
v2
=
std
::
move
(
v1
).
transform_or
(
next_error
);
CHECK_EQ
(
v1
,
sec
::
runtime_error
);
CHECK_EQ
(
v2
,
sec
::
remote_linking_failed
);
}
}
}
TEST_CASE
(
"transform_or does nothing when called with a value"
)
{
SUBCASE
(
"non-void value type"
)
{
auto
uh_oh
=
[](
auto
&&
)
{
FAIL
(
"uh-oh called!"
);
return
error
{};
};
auto
i
=
make_counted
<
counted_int
>
(
1
);
auto
v1
=
e_iptr
{
std
::
in_place
,
i
};
auto
v2
=
v1
.
transform_or
(
uh_oh
);
// mutable lvalue
const
auto
v3
=
std
::
move
(
v2
).
transform_or
(
uh_oh
);
// mutable rvalue
const
auto
v4
=
v3
.
transform_or
(
uh_oh
);
// const lvalue
auto
v5
=
std
::
move
(
v4
).
transform_or
(
uh_oh
);
// const rvalue
CHECK_EQ
(
v1
,
i
);
CHECK_EQ
(
v2
,
nullptr
);
// has been moved-from
CHECK_EQ
(
v3
,
i
);
CHECK_EQ
(
v4
,
i
);
CHECK_EQ
(
v5
,
i
);
}
SUBCASE
(
"void value type"
)
{
auto
uh_oh
=
[](
auto
&&
)
{
FAIL
(
"uh-oh called!"
);
return
error
{};
};
auto
v1
=
e_void
{};
auto
v2
=
v1
.
transform_or
(
uh_oh
);
// mutable lvalue
const
auto
v3
=
std
::
move
(
v2
).
transform_or
(
uh_oh
);
// mutable rvalue
const
auto
v4
=
v3
.
transform_or
(
uh_oh
);
// const lvalue
auto
v5
=
std
::
move
(
v4
).
transform_or
(
uh_oh
);
// const rvalue
CHECK
(
v1
);
CHECK
(
v2
);
CHECK
(
v3
);
CHECK
(
v4
);
CHECK
(
v5
);
}
}
}
libcaf_io/src/io/network/default_multiplexer.cpp
View file @
e6f6dab9
...
@@ -788,12 +788,12 @@ expected<void> read_port(native_socket fd, SockAddrType& sa) {
...
@@ -788,12 +788,12 @@ expected<void> read_port(native_socket fd, SockAddrType& sa) {
socket_size_type
len
=
sizeof
(
SockAddrType
);
socket_size_type
len
=
sizeof
(
SockAddrType
);
CALL_CFUN
(
res
,
detail
::
cc_zero
,
"getsockname"
,
CALL_CFUN
(
res
,
detail
::
cc_zero
,
"getsockname"
,
getsockname
(
fd
,
reinterpret_cast
<
sockaddr
*>
(
&
sa
),
&
len
));
getsockname
(
fd
,
reinterpret_cast
<
sockaddr
*>
(
&
sa
),
&
len
));
return
unit
;
return
{}
;
}
}
expected
<
void
>
set_inaddr_any
(
native_socket
,
sockaddr_in
&
sa
)
{
expected
<
void
>
set_inaddr_any
(
native_socket
,
sockaddr_in
&
sa
)
{
sa
.
sin_addr
.
s_addr
=
INADDR_ANY
;
sa
.
sin_addr
.
s_addr
=
INADDR_ANY
;
return
unit
;
return
{}
;
}
}
expected
<
void
>
set_inaddr_any
(
native_socket
fd
,
sockaddr_in6
&
sa
)
{
expected
<
void
>
set_inaddr_any
(
native_socket
fd
,
sockaddr_in6
&
sa
)
{
...
@@ -804,7 +804,7 @@ expected<void> set_inaddr_any(native_socket fd, sockaddr_in6& sa) {
...
@@ -804,7 +804,7 @@ expected<void> set_inaddr_any(native_socket fd, sockaddr_in6& sa) {
setsockopt
(
fd
,
IPPROTO_IPV6
,
IPV6_V6ONLY
,
setsockopt
(
fd
,
IPPROTO_IPV6
,
IPV6_V6ONLY
,
reinterpret_cast
<
setsockopt_ptr
>
(
&
off
),
reinterpret_cast
<
setsockopt_ptr
>
(
&
off
),
static_cast
<
socket_size_type
>
(
sizeof
(
off
))));
static_cast
<
socket_size_type
>
(
sizeof
(
off
))));
return
unit
;
return
{}
;
}
}
template
<
int
Family
,
int
SockType
=
SOCK_STREAM
>
template
<
int
Family
,
int
SockType
=
SOCK_STREAM
>
...
...
libcaf_io/src/io/network/native_socket.cpp
View file @
e6f6dab9
...
@@ -128,7 +128,7 @@ expected<void> child_process_inherit(native_socket fd, bool new_value) {
...
@@ -128,7 +128,7 @@ expected<void> child_process_inherit(native_socket fd, bool new_value) {
// calculate and set new flags
// calculate and set new flags
auto
wf
=
(
!
new_value
)
?
(
rf
|
FD_CLOEXEC
)
:
(
rf
&
(
~
(
FD_CLOEXEC
)));
auto
wf
=
(
!
new_value
)
?
(
rf
|
FD_CLOEXEC
)
:
(
rf
&
(
~
(
FD_CLOEXEC
)));
CALL_CFUN
(
set_res
,
detail
::
cc_not_minus1
,
"fcntl"
,
fcntl
(
fd
,
F_SETFD
,
wf
));
CALL_CFUN
(
set_res
,
detail
::
cc_not_minus1
,
"fcntl"
,
fcntl
(
fd
,
F_SETFD
,
wf
));
return
unit
;
return
{}
;
}
}
expected
<
void
>
keepalive
(
native_socket
fd
,
bool
new_value
)
{
expected
<
void
>
keepalive
(
native_socket
fd
,
bool
new_value
)
{
...
@@ -137,7 +137,7 @@ expected<void> keepalive(native_socket fd, bool new_value) {
...
@@ -137,7 +137,7 @@ expected<void> keepalive(native_socket fd, bool new_value) {
CALL_CFUN
(
res
,
detail
::
cc_zero
,
"setsockopt"
,
CALL_CFUN
(
res
,
detail
::
cc_zero
,
"setsockopt"
,
setsockopt
(
fd
,
SOL_SOCKET
,
SO_KEEPALIVE
,
&
value
,
setsockopt
(
fd
,
SOL_SOCKET
,
SO_KEEPALIVE
,
&
value
,
static_cast
<
unsigned
>
(
sizeof
(
value
))));
static_cast
<
unsigned
>
(
sizeof
(
value
))));
return
unit
;
return
{}
;
}
}
expected
<
void
>
nonblocking
(
native_socket
fd
,
bool
new_value
)
{
expected
<
void
>
nonblocking
(
native_socket
fd
,
bool
new_value
)
{
...
@@ -147,7 +147,7 @@ expected<void> nonblocking(native_socket fd, bool new_value) {
...
@@ -147,7 +147,7 @@ expected<void> nonblocking(native_socket fd, bool new_value) {
// calculate and set new flags
// calculate and set new flags
auto
wf
=
new_value
?
(
rf
|
O_NONBLOCK
)
:
(
rf
&
(
~
(
O_NONBLOCK
)));
auto
wf
=
new_value
?
(
rf
|
O_NONBLOCK
)
:
(
rf
&
(
~
(
O_NONBLOCK
)));
CALL_CFUN
(
set_res
,
detail
::
cc_not_minus1
,
"fcntl"
,
fcntl
(
fd
,
F_SETFL
,
wf
));
CALL_CFUN
(
set_res
,
detail
::
cc_not_minus1
,
"fcntl"
,
fcntl
(
fd
,
F_SETFL
,
wf
));
return
unit
;
return
{}
;
}
}
expected
<
void
>
allow_sigpipe
(
native_socket
fd
,
bool
new_value
)
{
expected
<
void
>
allow_sigpipe
(
native_socket
fd
,
bool
new_value
)
{
...
@@ -157,12 +157,12 @@ expected<void> allow_sigpipe(native_socket fd, bool new_value) {
...
@@ -157,12 +157,12 @@ expected<void> allow_sigpipe(native_socket fd, bool new_value) {
setsockopt
(
fd
,
SOL_SOCKET
,
no_sigpipe_socket_flag
,
&
value
,
setsockopt
(
fd
,
SOL_SOCKET
,
no_sigpipe_socket_flag
,
&
value
,
static_cast
<
unsigned
>
(
sizeof
(
value
))));
static_cast
<
unsigned
>
(
sizeof
(
value
))));
}
}
return
unit
;
return
{}
;
}
}
expected
<
void
>
allow_udp_connreset
(
native_socket
,
bool
)
{
expected
<
void
>
allow_udp_connreset
(
native_socket
,
bool
)
{
// nop; SIO_UDP_CONNRESET only exists on Windows
// nop; SIO_UDP_CONNRESET only exists on Windows
return
unit
;
return
{}
;
}
}
std
::
pair
<
native_socket
,
native_socket
>
create_pipe
()
{
std
::
pair
<
native_socket
,
native_socket
>
create_pipe
()
{
...
@@ -353,7 +353,7 @@ expected<void> send_buffer_size(native_socket fd, int new_value) {
...
@@ -353,7 +353,7 @@ expected<void> send_buffer_size(native_socket fd, int new_value) {
setsockopt
(
fd
,
SOL_SOCKET
,
SO_SNDBUF
,
setsockopt
(
fd
,
SOL_SOCKET
,
SO_SNDBUF
,
reinterpret_cast
<
setsockopt_ptr
>
(
&
new_value
),
reinterpret_cast
<
setsockopt_ptr
>
(
&
new_value
),
static_cast
<
socket_size_type
>
(
sizeof
(
int
))));
static_cast
<
socket_size_type
>
(
sizeof
(
int
))));
return
unit
;
return
{}
;
}
}
expected
<
void
>
tcp_nodelay
(
native_socket
fd
,
bool
new_value
)
{
expected
<
void
>
tcp_nodelay
(
native_socket
fd
,
bool
new_value
)
{
...
@@ -363,7 +363,7 @@ expected<void> tcp_nodelay(native_socket fd, bool new_value) {
...
@@ -363,7 +363,7 @@ expected<void> tcp_nodelay(native_socket fd, bool new_value) {
setsockopt
(
fd
,
IPPROTO_TCP
,
TCP_NODELAY
,
setsockopt
(
fd
,
IPPROTO_TCP
,
TCP_NODELAY
,
reinterpret_cast
<
setsockopt_ptr
>
(
&
flag
),
reinterpret_cast
<
setsockopt_ptr
>
(
&
flag
),
static_cast
<
socket_size_type
>
(
sizeof
(
flag
))));
static_cast
<
socket_size_type
>
(
sizeof
(
flag
))));
return
unit
;
return
{}
;
}
}
bool
is_error
(
signed_size_type
res
,
bool
is_nonblock
)
{
bool
is_error
(
signed_size_type
res
,
bool
is_nonblock
)
{
...
...
libcaf_test/caf/test/bdd_dsl.hpp
View file @
e6f6dab9
...
@@ -23,6 +23,10 @@
...
@@ -23,6 +23,10 @@
} \
} \
void CAF_UNIQUE(test)::run_test_impl()
void CAF_UNIQUE(test)::run_test_impl()
#define SUBCASE(description) \
CAF_MESSAGE(description); \
if (true)
#define GIVEN(description) \
#define GIVEN(description) \
CAF_MESSAGE("GIVEN " description); \
CAF_MESSAGE("GIVEN " description); \
if (true)
if (true)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment