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
e5c42e3f
Commit
e5c42e3f
authored
Jun 21, 2016
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add new expected<T> type
parent
5e7b99b9
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
516 additions
and
35 deletions
+516
-35
libcaf_core/caf/error.hpp
libcaf_core/caf/error.hpp
+30
-35
libcaf_core/caf/expected.hpp
libcaf_core/caf/expected.hpp
+372
-0
libcaf_core/test/expected.cpp
libcaf_core/test/expected.cpp
+114
-0
No files found.
libcaf_core/caf/error.hpp
View file @
e5c42e3f
...
@@ -30,6 +30,31 @@
...
@@ -30,6 +30,31 @@
namespace
caf
{
namespace
caf
{
class
error
;
/// Evaluates to true if `T` is an enum with a free function
/// `make_error` for converting it to an `error`.
template
<
class
T
>
struct
has_make_error
{
private:
template
<
class
U
>
static
auto
test_make_error
(
U
*
x
)
->
decltype
(
make_error
(
*
x
));
template
<
class
U
>
static
auto
test_make_error
(...)
->
void
;
using
type
=
decltype
(
test_make_error
<
T
>
(
nullptr
));
public:
static
constexpr
bool
value
=
std
::
is_enum
<
T
>::
value
&&
std
::
is_same
<
error
,
type
>::
value
;
};
/// Convenience alias for `std::enable_if<has_make_error<T>::value, U>::type`.
template
<
class
T
,
class
U
=
void
>
using
enable_if_has_make_error_t
=
typename
std
::
enable_if
<
has_make_error
<
T
>::
value
,
U
>::
type
;
/// A serializable type for storing error codes with category and optional,
/// A serializable type for storing error codes with category and optional,
/// human-readable context information. Unlike error handling classes from
/// human-readable context information. Unlike error handling classes from
/// the C++ standard library, this type is serializable. It consists of an
/// the C++ standard library, this type is serializable. It consists of an
...
@@ -71,13 +96,7 @@ public:
...
@@ -71,13 +96,7 @@ public:
error
(
uint8_t
code
,
atom_value
category
)
noexcept
;
error
(
uint8_t
code
,
atom_value
category
)
noexcept
;
error
(
uint8_t
code
,
atom_value
category
,
message
msg
)
noexcept
;
error
(
uint8_t
code
,
atom_value
category
,
message
msg
)
noexcept
;
template
<
class
E
,
template
<
class
E
,
class
=
enable_if_has_make_error_t
<
E
>
>
class
=
typename
std
::
enable_if
<
std
::
is_same
<
decltype
(
make_error
(
std
::
declval
<
const
E
&
>())),
error
>::
value
>::
type
>
error
(
E
error_value
)
:
error
(
make_error
(
error_value
))
{
error
(
E
error_value
)
:
error
(
make_error
(
error_value
))
{
// nop
// nop
}
}
...
@@ -133,49 +152,25 @@ private:
...
@@ -133,49 +152,25 @@ private:
};
};
/// @relates error
/// @relates error
template
<
class
E
,
template
<
class
E
,
class
=
enable_if_has_make_error_t
<
E
>
>
class
=
typename
std
::
enable_if
<
std
::
is_same
<
decltype
(
make_error
(
std
::
declval
<
const
E
&
>())),
error
>::
value
>::
type
>
bool
operator
==
(
const
error
&
x
,
E
y
)
{
bool
operator
==
(
const
error
&
x
,
E
y
)
{
return
x
==
make_error
(
y
);
return
x
==
make_error
(
y
);
}
}
/// @relates error
/// @relates error
template
<
class
E
,
template
<
class
E
,
class
=
enable_if_has_make_error_t
<
E
>
>
class
=
typename
std
::
enable_if
<
std
::
is_same
<
decltype
(
make_error
(
std
::
declval
<
const
E
&
>())),
error
>::
value
>::
type
>
bool
operator
==
(
E
x
,
const
error
&
y
)
{
bool
operator
==
(
E
x
,
const
error
&
y
)
{
return
make_error
(
x
)
==
y
;
return
make_error
(
x
)
==
y
;
}
}
/// @relates error
/// @relates error
template
<
class
E
,
template
<
class
E
,
class
=
enable_if_has_make_error_t
<
E
>
>
class
=
typename
std
::
enable_if
<
std
::
is_same
<
decltype
(
make_error
(
std
::
declval
<
const
E
&
>())),
error
>::
value
>::
type
>
bool
operator
!=
(
const
error
&
x
,
E
y
)
{
bool
operator
!=
(
const
error
&
x
,
E
y
)
{
return
!
(
x
==
y
);
return
!
(
x
==
y
);
}
}
/// @relates error
/// @relates error
template
<
class
E
,
template
<
class
E
,
class
=
enable_if_has_make_error_t
<
E
>
>
class
=
typename
std
::
enable_if
<
std
::
is_same
<
decltype
(
make_error
(
std
::
declval
<
const
E
&
>())),
error
>::
value
>::
type
>
bool
operator
!=
(
E
x
,
const
error
&
y
)
{
bool
operator
!=
(
E
x
,
const
error
&
y
)
{
return
!
(
x
==
y
);
return
!
(
x
==
y
);
}
}
...
...
libcaf_core/caf/expected.hpp
0 → 100644
View file @
e5c42e3f
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_EXPECTED_HPP
#define CAF_EXPECTED_HPP
#include "caf/config.hpp"
#include <new>
#include <memory>
#include <type_traits>
#include "caf/unit.hpp"
#include "caf/error.hpp"
namespace
caf
{
/// Represents the result of a computation which can either complete
/// successfully with an instance of type `T` or fail with an `error`.
/// @tparam The type of the result.
template
<
typename
T
>
class
expected
{
public:
// -- static member variables ------------------------------------------------
/// Stores whether move construct and move assign never throw.
static
constexpr
bool
nothrow_move
=
std
::
is_nothrow_move_constructible
<
T
>::
value
&&
std
::
is_nothrow_move_assignable
<
T
>::
value
;
/// Stores whether copy construct and copy assign never throw.
static
constexpr
bool
nothrow_copy
=
std
::
is_nothrow_copy_constructible
<
T
>::
value
&&
std
::
is_nothrow_copy_assignable
<
T
>::
value
;
// -- constructors, destructors, and assignment operators --------------------
expected
(
T
&&
x
)
noexcept
(
nothrow_move
)
:
engaged_
(
true
)
{
new
(
&
value_
)
T
(
std
::
move
(
x
));
}
expected
(
const
T
&
x
)
noexcept
(
nothrow_copy
)
:
engaged_
(
true
)
{
new
(
&
value_
)
T
(
x
);
}
expected
(
caf
::
error
e
)
noexcept
:
engaged_
(
false
)
{
new
(
&
error_
)
caf
::
error
{
std
::
move
(
e
)};
}
expected
(
const
expected
&
other
)
noexcept
(
nothrow_copy
)
{
construct
(
other
);
}
expected
(
expected
&&
other
)
noexcept
(
nothrow_move
)
{
construct
(
std
::
move
(
other
));
}
~
expected
()
{
destroy
();
}
expected
&
operator
=
(
const
expected
&
other
)
noexcept
(
nothrow_copy
)
{
if
(
engaged_
&&
other
.
engaged_
)
value_
=
other
.
value_
;
else
if
(
!
engaged_
&&
!
other
.
engaged_
)
error_
=
other
.
error_
;
else
{
destroy
();
construct
(
other
);
}
return
*
this
;
}
expected
&
operator
=
(
expected
&&
other
)
noexcept
(
nothrow_move
)
{
if
(
engaged_
&&
other
.
engaged_
)
value_
=
std
::
move
(
other
.
value_
);
else
if
(
!
engaged_
&&
!
other
.
engaged_
)
error_
=
std
::
move
(
other
.
error_
);
else
{
destroy
();
construct
(
std
::
move
(
other
));
}
return
*
this
;
}
expected
&
operator
=
(
const
T
&
x
)
noexcept
(
nothrow_copy
)
{
if
(
engaged_
)
{
value_
=
x
;
}
else
{
destroy
();
engaged_
=
true
;
new
(
&
value_
)
T
(
x
);
}
return
*
this
;
}
expected
&
operator
=
(
T
&&
x
)
noexcept
(
nothrow_move
)
{
if
(
engaged_
)
{
value_
=
std
::
move
(
x
);
}
else
{
destroy
();
engaged_
=
true
;
new
(
&
value_
)
T
(
std
::
move
(
x
));
}
return
*
this
;
}
expected
&
operator
=
(
caf
::
error
e
)
noexcept
{
if
(
!
engaged_
)
error_
=
std
::
move
(
e
);
else
{
destroy
();
engaged_
=
false
;
new
(
&
value_
)
caf
::
error
(
std
::
move
(
e
));
}
return
*
this
;
}
// -- modifiers --------------------------------------------------------------
/// @copydoc cvalue
T
&
value
()
noexcept
{
CAF_ASSERT
(
engaged_
);
return
value_
;
}
/// @copydoc cvalue
T
&
operator
*
()
noexcept
{
return
value
();
}
/// @copydoc cvalue
T
*
operator
->
()
noexcept
{
return
&
value
();
}
/// @copydoc cerror
caf
::
error
&
error
()
noexcept
{
CAF_ASSERT
(
!
engaged_
);
return
error_
;
}
// -- observers --------------------------------------------------------------
/// Returns the contained value.
/// @pre `engaged() == true`.
const
T
&
cvalue
()
const
noexcept
{
CAF_ASSERT
(
engaged_
);
return
value_
;
}
/// @copydoc cvalue
const
T
&
value
()
const
noexcept
{
CAF_ASSERT
(
engaged_
);
return
value_
;
}
/// @copydoc cvalue
const
T
&
operator
*
()
const
noexcept
{
return
value
();
}
/// @copydoc cvalue
const
T
*
operator
->
()
const
noexcept
{
return
&
value
();
}
/// @copydoc engaged
explicit
operator
bool
()
const
noexcept
{
return
engaged
();
}
/// Returns `true` if the object holds a value (is engaged).
bool
engaged
()
const
noexcept
{
return
engaged_
;
}
/// Returns the contained error.
/// @pre `engaged() == false`.
const
caf
::
error
&
cerror
()
const
noexcept
{
CAF_ASSERT
(
!
engaged_
);
return
error_
;
}
/// @copydoc cerror
const
caf
::
error
&
error
()
const
noexcept
{
CAF_ASSERT
(
!
engaged_
);
return
error_
;
}
private:
void
construct
(
expected
&&
other
)
noexcept
(
nothrow_move
)
{
if
(
other
.
engaged_
)
new
(
&
value_
)
T
(
std
::
move
(
other
.
value_
));
else
new
(
&
error_
)
caf
::
error
(
std
::
move
(
other
.
error_
));
engaged_
=
other
.
engaged_
;
}
void
construct
(
const
expected
&
other
)
noexcept
(
nothrow_copy
)
{
if
(
other
.
engaged_
)
new
(
&
value_
)
T
(
other
.
value_
);
else
new
(
&
error_
)
caf
::
error
(
other
.
error_
);
engaged_
=
other
.
engaged_
;
}
void
destroy
()
{
if
(
engaged_
)
value_
.
~
T
();
else
error_
.
~
error
();
}
bool
engaged_
;
union
{
T
value_
;
caf
::
error
error_
;
};
};
/// @relates expected
template
<
class
T
>
auto
operator
==
(
const
expected
<
T
>&
x
,
const
expected
<
T
>&
y
)
->
decltype
(
*
x
==
*
y
)
{
return
x
&&
y
?
*
x
==
*
y
:
(
!
x
&&
!
y
?
x
.
error
()
==
y
.
error
()
:
false
);
}
/// @relates expected
template
<
class
T
,
class
U
>
auto
operator
==
(
const
expected
<
T
>&
x
,
const
U
&
y
)
->
decltype
(
*
x
==
y
)
{
return
x
?
*
x
==
y
:
false
;
}
/// @relates expected
template
<
class
T
,
class
U
>
auto
operator
==
(
const
T
&
x
,
const
expected
<
U
>&
y
)
->
decltype
(
x
==
*
y
)
{
return
y
==
x
;
}
/// @relates expected
template
<
class
T
>
bool
operator
==
(
const
expected
<
T
>&
x
,
const
error
&
y
)
{
return
x
?
false
:
x
.
error
()
==
y
;
}
/// @relates expected
template
<
class
T
>
bool
operator
==
(
const
error
&
x
,
const
expected
<
T
>&
y
)
{
return
y
==
x
;
}
/// @relates expected
template
<
class
T
,
class
E
>
enable_if_has_make_error_t
<
E
,
bool
>
operator
==
(
const
expected
<
T
>&
x
,
E
y
)
{
return
x
==
make_error
(
y
);
}
/// @relates expected
template
<
class
T
,
class
E
>
enable_if_has_make_error_t
<
E
,
bool
>
operator
==
(
E
x
,
const
expected
<
T
>&
y
)
{
return
y
==
make_error
(
x
);
}
/// @relates expected
template
<
class
T
>
auto
operator
!=
(
const
expected
<
T
>&
x
,
const
expected
<
T
>&
y
)
->
decltype
(
*
x
==
*
y
)
{
return
!
(
x
==
y
);
}
/// @relates expected
template
<
class
T
,
class
U
>
auto
operator
!=
(
const
expected
<
T
>&
x
,
const
U
&
y
)
->
decltype
(
*
x
==
y
)
{
return
!
(
x
==
y
);
}
/// @relates expected
template
<
class
T
,
class
U
>
auto
operator
!=
(
const
T
&
x
,
const
expected
<
U
>&
y
)
->
decltype
(
x
==
*
y
)
{
return
!
(
x
==
y
);
}
/// @relates expected
template
<
class
T
>
bool
operator
!=
(
const
expected
<
T
>&
x
,
const
error
&
y
)
{
return
!
(
x
==
y
);
}
/// @relates expected
template
<
class
T
>
bool
operator
!=
(
const
error
&
x
,
const
expected
<
T
>&
y
)
{
return
!
(
x
==
y
);
}
/// @relates expected
template
<
class
T
,
class
E
>
enable_if_has_make_error_t
<
E
,
bool
>
operator
!=
(
const
expected
<
T
>&
x
,
E
y
)
{
return
!
(
x
==
y
);
}
/// @relates expected
template
<
class
T
,
class
E
>
enable_if_has_make_error_t
<
E
,
bool
>
operator
!=
(
E
x
,
const
expected
<
T
>&
y
)
{
return
!
(
x
==
y
);
}
/// The pattern `expected<void>` shall be used for functions that may generate
/// an error but would otherwise return `bool`.
template
<
>
class
expected
<
void
>
{
public:
expected
()
=
default
;
expected
(
unit_t
)
noexcept
{
// nop
}
expected
(
caf
::
error
e
)
noexcept
:
error_
(
std
::
move
(
e
))
{
// nop
}
expected
(
const
expected
&
other
)
noexcept
:
error_
(
other
.
error_
)
{
// nop
}
expected
(
expected
&&
other
)
noexcept
:
error_
(
std
::
move
(
other
.
error_
))
{
// nop
}
expected
&
operator
=
(
const
expected
&
other
)
noexcept
{
error_
=
other
.
error_
;
return
*
this
;
}
expected
&
operator
=
(
expected
&&
other
)
noexcept
{
error_
=
std
::
move
(
other
.
error_
);
return
*
this
;
}
explicit
operator
bool
()
const
{
return
!
error_
;
}
const
caf
::
error
&
error
()
const
{
return
error_
;
}
private:
caf
::
error
error_
;
};
}
// namespace caf
#endif
libcaf_core/test/expected.cpp
0 → 100644
View file @
e5c42e3f
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE expected
#include "caf/test/unit_test.hpp"
#include "caf/sec.hpp"
#include "caf/expected.hpp"
using
namespace
std
;
using
namespace
caf
;
#define CHECK(x) CAF_CHECK(x);
#define CHECK_EQ(x, y) \
CAF_CHECK(x == y); \
CAF_CHECK(y == x);
#define CHECK_NEQ(x, y) \
CAF_CHECK(x != y); \
CAF_CHECK(y != x);
namespace
{
using
e_int
=
expected
<
int
>
;
using
e_str
=
expected
<
std
::
string
>
;
}
// namespace <anonymous>
CAF_TEST
(
both_engaged_equal
)
{
e_int
x
{
42
};
e_int
y
{
42
};
CHECK
(
x
);
CHECK
(
y
);
CHECK_EQ
(
x
,
y
);
CHECK_EQ
(
x
,
42
);
CHECK_EQ
(
y
,
42
);
}
CAF_TEST
(
both_engaged_not_equal
)
{
e_int
x
{
42
};
e_int
y
{
24
};
CHECK
(
x
);
CHECK
(
y
);
CHECK_NEQ
(
x
,
y
);
CHECK_NEQ
(
x
,
sec
::
unexpected_message
);
CHECK_NEQ
(
y
,
sec
::
unexpected_message
);
CHECK_EQ
(
x
,
42
);
CHECK_EQ
(
y
,
24
);
}
CAF_TEST
(
engaged_plus_not_engaged
)
{
e_int
x
{
42
};
e_int
y
{
sec
::
unexpected_message
};
CHECK
(
x
);
CHECK
(
!
y
);
CHECK_EQ
(
x
,
42
);
CHECK_EQ
(
y
,
sec
::
unexpected_message
);
CHECK_NEQ
(
x
,
sec
::
unexpected_message
);
CHECK_NEQ
(
x
,
y
);
CHECK_NEQ
(
y
,
42
);
CHECK_NEQ
(
y
,
sec
::
unsupported_sys_key
);
}
CAF_TEST
(
both_not_engaged
)
{
e_int
x
{
sec
::
unexpected_message
};
e_int
y
{
sec
::
unexpected_message
};
CHECK
(
!
x
);
CHECK
(
!
y
);
CHECK_EQ
(
x
,
y
);
CHECK_EQ
(
x
,
sec
::
unexpected_message
);
CHECK_EQ
(
y
,
sec
::
unexpected_message
);
CHECK_EQ
(
x
.
error
(),
y
.
error
());
CHECK_NEQ
(
x
,
sec
::
unsupported_sys_key
);
CHECK_NEQ
(
y
,
sec
::
unsupported_sys_key
);
}
CAF_TEST
(
move_and_copy
)
{
e_str
x
{
sec
::
unexpected_message
};
e_str
y
{
"hello"
};
x
=
"hello"
;
CHECK_NEQ
(
x
,
sec
::
unexpected_message
);
CHECK_EQ
(
x
,
"hello"
);
CHECK_EQ
(
x
,
y
);
y
=
"world"
;
x
=
std
::
move
(
y
);
CHECK_EQ
(
x
,
"world"
);
e_str
z
{
std
::
move
(
x
)};
CHECK_EQ
(
z
,
"world"
);
e_str
z_cpy
{
z
};
CHECK_EQ
(
z_cpy
,
"world"
);
CHECK_EQ
(
z
,
z_cpy
);
z
=
e_str
{
sec
::
unsupported_sys_key
};
CHECK_NEQ
(
z
,
z_cpy
);
CHECK_EQ
(
z
,
sec
::
unsupported_sys_key
);
}
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