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
ece82dbb
Commit
ece82dbb
authored
Aug 28, 2013
by
Joseph Noir
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'unstable' of github.com:Neverlord/libcppa into unstable
parents
6aa1cd24
f580a1ef
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
498 additions
and
568 deletions
+498
-568
cppa/match.hpp
cppa/match.hpp
+113
-74
cppa/optional_variant.hpp
cppa/optional_variant.hpp
+75
-4
unit_testing/test_match.cpp
unit_testing/test_match.cpp
+310
-490
No files found.
cppa/match.hpp
View file @
ece82dbb
...
...
@@ -46,20 +46,29 @@
namespace
cppa
{
namespace
detail
{
struct
match_helper
{
class
match_helper
{
match_helper
(
const
match_helper
&
)
=
delete
;
match_helper
&
operator
=
(
const
match_helper
&
)
=
delete
;
any_tuple
tup
;
match_helper
(
any_tuple
t
)
:
tup
(
std
::
move
(
t
))
{
}
public:
match_helper
(
match_helper
&&
)
=
default
;
inline
match_helper
(
any_tuple
t
)
:
tup
(
std
::
move
(
t
))
{
}
template
<
typename
...
Ts
>
bool
operator
()(
Ts
&&
...
args
)
{
auto
operator
()(
Ts
&&
...
args
)
->
decltype
(
match_expr_collect
(
std
::
forward
<
Ts
>
(
args
)...)(
any_tuple
{}))
{
static_assert
(
sizeof
...(
Ts
)
>
0
,
"at least one argument required"
);
auto
tmp
=
match_expr_convert
(
std
::
forward
<
Ts
>
(
args
)...);
static_assert
(
std
::
is_same
<
partial_function
,
decltype
(
tmp
)
>::
value
,
"match statement contains timeout"
);
auto
tmp
=
match_expr_collect
(
std
::
forward
<
Ts
>
(
args
)...);
return
tmp
(
tup
);
}
private:
any_tuple
tup
;
};
struct
identity_fun
{
...
...
@@ -72,22 +81,25 @@ struct identity_fun {
template
<
typename
Iterator
,
typename
Projection
=
identity_fun
>
class
match_each_helper
{
match_each_helper
(
const
match_each_helper
&
)
=
delete
;
match_each_helper
&
operator
=
(
const
match_each_helper
&
)
=
delete
;
public:
match_each_helper
(
match_each_helper
&&
)
=
default
;
match_each_helper
(
const
match_each_helper
&
)
=
delete
;
match_each_helper
&
operator
=
(
const
match_each_helper
&
)
=
delete
;
match_each_helper
(
Iterator
first
,
Iterator
last
)
:
i
(
first
),
e
(
last
)
{
}
match_each_helper
(
Iterator
first
,
Iterator
last
,
Projection
proj
)
:
i
(
first
),
e
(
last
),
p
(
proj
)
{
}
match_each_helper
(
Iterator
first
,
Iterator
last
,
Projection
proj
=
Projection
{})
:
i
(
std
::
move
(
first
)),
e
(
std
::
move
(
last
)),
p
(
std
::
move
(
proj
))
{
}
template
<
typename
...
Ts
>
void
operator
()(
Ts
&&
...
args
)
{
Iterator
operator
()(
Ts
&&
...
args
)
{
static_assert
(
sizeof
...(
Ts
)
>
0
,
"at least one argument required"
);
auto
expr
=
match_expr_collect
(
std
::
forward
<
Ts
>
(
args
)...);
for
(;
i
!=
e
;
++
i
)
{
expr
(
p
(
*
i
));
auto
res
=
expr
(
p
(
*
i
));
if
(
!
res
)
return
i
;
}
return
e
;
}
private:
...
...
@@ -103,17 +115,20 @@ struct advance_once {
inline
void
operator
()(
T
&
what
)
{
++
what
;
}
};
template
<
class
Iterator
,
class
Predicate
,
template
<
class
Iterator
,
class
Predicate
,
class
Advance
=
advance_once
,
class
Projection
=
identity_fun
>
class
match_for_helper
{
match_for_helper
(
const
match_for_helper
&
)
=
delete
;
match_for_helper
&
operator
=
(
const
match_for_helper
&
)
=
delete
;
public:
match_for_helper
(
match_for_helper
&&
)
=
default
;
match_for_helper
(
const
match_for_helper
&
)
=
delete
;
match_for_helper
&
operator
=
(
const
match_for_helper
&
)
=
delete
;
match_for_helper
(
Iterator
first
,
Predicate
p
,
Advance
a
=
Advance
(),
Projection
pj
=
Projection
())
match_for_helper
(
Iterator
first
,
Predicate
p
,
Advance
a
=
Advance
{},
Projection
pj
=
Projection
{})
:
i
(
first
),
adv
(
a
),
pred
(
p
),
proj
(
pj
)
{
}
template
<
typename
...
Ts
>
...
...
@@ -142,59 +157,80 @@ size_t run_case(std::vector<T>& vec,
const
InputIterator
&
end
,
Case
&
target
);
template
<
size_t
N
,
size_t
Size
>
struct
unwind_
and_call
{
template
<
size_t
Pos
,
size_t
Max
>
struct
unwind_
pos_token
{
};
typedef
unwind_and_call
<
N
+
1
,
Size
>
next
;
template
<
size_t
Pos
,
size_t
Max
>
constexpr
unwind_pos_token
<
Pos
+
1
,
Max
>
next
(
unwind_pos_token
<
Pos
,
Max
>
)
{
return
{};
}
template
<
class
Target
,
typename
T
,
typename
...
Unwinded
>
static
inline
bool
_
(
Target
&
target
,
bool
&
skipped
,
std
::
vector
<
T
>&
vec
,
Unwinded
&&
...
args
)
{
return
next
::
_
(
target
,
skipped
,
vec
,
std
::
forward
<
Unwinded
>
(
args
)...,
vec
[
N
]
);
}
template
<
typename
T
>
static
inline
bool
eval_res
(
const
optional
<
T
>&
res
,
bool
&
)
{
return
static_cast
<
bool
>
(
res
);
}
template
<
typename
T
,
typename
InputIterator
,
class
MatchExpr
>
static
inline
bool
_
(
std
::
vector
<
T
>&
vec
,
InputIterator
&
pos
,
InputIterator
end
,
MatchExpr
&
ex
)
{
bool
skipped
=
false
;
if
(
run_case
(
vec
,
skipped
,
pos
,
end
,
get
<
N
>
(
ex
.
cases
()))
==
0
)
{
return
(
skipped
)
?
false
:
next
::
_
(
vec
,
pos
,
end
,
ex
)
;
static
inline
bool
eval_res
(
const
optional
<
match_hint
>&
res
,
bool
&
skipped
)
{
if
(
res
)
{
if
(
*
res
==
match_hint
::
skip
)
{
skipped
=
true
;
return
false
;
}
return
true
;
}
return
false
;
}
};
template
<
size_t
Size
>
struct
unwind_and_call
<
Size
,
Size
>
{
template
<
size_t
Max
,
class
Target
,
typename
T
,
typename
...
Ts
>
bool
unwind_and_call
(
unwind_pos_token
<
Max
,
Max
>
,
Target
&
target
,
bool
&
skipped
,
std
::
vector
<
T
>&
,
Ts
&&
...
args
)
{
return
eval_res
(
target
.
first
(
target
.
second
,
std
::
forward
<
Ts
>
(
args
)...),
skipped
);
}
template
<
typename
T
>
static
inline
bool
eval_res
(
const
optional
<
T
>&
res
,
bool
&
)
{
return
static_cast
<
bool
>
(
res
);
}
template
<
size_t
Max
,
typename
T
,
typename
InputIterator
,
class
MatchExpr
>
bool
unwind_and_call
(
unwind_pos_token
<
Max
,
Max
>
,
std
::
vector
<
T
>&
,
InputIterator
&
,
InputIterator
,
MatchExpr
&
)
{
return
false
;
}
static
inline
bool
eval_res
(
const
optional
<
match_hint
>&
res
,
bool
&
skipped
)
{
if
(
res
)
{
if
(
*
res
==
match_hint
::
skip
)
{
skipped
=
true
;
return
false
;
}
return
true
;
}
return
false
;
}
template
<
size_t
Pos
,
size_t
Max
,
class
Target
,
typename
T
,
typename
...
Ts
>
bool
unwind_and_call
(
unwind_pos_token
<
Pos
,
Max
>
pt
,
Target
&
target
,
bool
&
skipped
,
std
::
vector
<
T
>&
vec
,
Ts
&&
...
args
)
{
return
unwind_and_call
(
next
(
pt
),
target
,
skipped
,
vec
,
std
::
forward
<
Ts
>
(
args
)...,
vec
[
Pos
]);
}
template
<
class
Target
,
typename
T
,
typename
...
Unwinded
>
static
inline
bool
_
(
Target
&
target
,
bool
&
skipped
,
std
::
vector
<
T
>&
,
Unwinded
&&
...
args
)
{
return
eval_res
(
target
.
first
(
target
.
second
,
std
::
forward
<
Unwinded
>
(
args
)...),
skipped
);
template
<
size_t
Pos
,
size_t
Max
,
typename
T
,
typename
InputIterator
,
class
MatchExpr
>
bool
unwind_and_call
(
unwind_pos_token
<
Pos
,
Max
>
pt
,
std
::
vector
<
T
>&
vec
,
InputIterator
&
pos
,
InputIterator
end
,
MatchExpr
&
ex
)
{
bool
skipped
=
false
;
if
(
run_case
(
vec
,
skipped
,
pos
,
end
,
get
<
Pos
>
(
ex
.
cases
()))
==
0
)
{
return
(
skipped
)
?
false
:
unwind_and_call
(
next
(
pt
),
vec
,
pos
,
end
,
ex
);
}
template
<
typename
T
,
typename
...
Ts
>
static
inline
bool
_
(
std
::
vector
<
T
>&
,
Ts
&&
...)
{
return
false
;
}
};
return
true
;
}
template
<
class
Case
,
typename
T
>
inline
bool
run_case_impl
(
Case
&
target
,
std
::
vector
<
T
>&
vec
,
bool
&
skipped
)
{
return
unwind_and_call
<
0
,
util
::
tl_size
<
typename
Case
::
pattern_type
>::
value
>::
_
(
target
,
skipped
,
vec
);
unwind_pos_token
<
0
,
util
::
tl_size
<
typename
Case
::
pattern_type
>::
value
>
pt
;
return
unwind_and_call
(
pt
,
target
,
skipped
,
vec
);
}
// Case is a projection_partial_function_pair
...
...
@@ -212,7 +248,7 @@ size_t run_case(std::vector<T>& vec,
"empty match expressions are not allowed in stream matching"
);
static_assert
(
util
::
tl_forall
<
plain_args
,
util
::
tbind
<
std
::
is_same
,
T
>::
template
type
>
::
value
,
"match_stream<T>: at least one callback argument "
"
is not of type T"
);
"is not of type T"
);
while
(
vec
.
size
()
<
num_args
)
{
if
(
pos
==
end
)
{
return
0
;
...
...
@@ -244,9 +280,10 @@ class stream_matcher {
template
<
typename
...
Ts
>
bool
operator
()(
Ts
&&
...
args
)
{
auto
expr
=
match_expr_collect
(
std
::
forward
<
Ts
>
(
args
)...);
typedef
decltype
(
expr
)
expr_type
;
typedef
decltype
(
expr
)
et
;
unwind_pos_token
<
0
,
util
::
tl_size
<
typename
et
::
cases_list
>::
value
>
pt
;
while
(
m_pos
!=
m_end
)
{
if
(
!
unwind_and_call
<
0
,
util
::
tl_size
<
typename
expr_type
::
cases_list
>::
value
>::
_
(
m_cache
,
m_pos
,
m_end
,
expr
))
{
if
(
!
unwind_and_call
(
pt
,
m_cache
,
m_pos
,
m_end
,
expr
))
{
return
false
;
}
}
...
...
@@ -285,7 +322,8 @@ detail::match_helper match(T&& what) {
/**
* @brief Splits @p str using @p delim and match the resulting strings.
*/
detail
::
match_helper
match_split
(
const
std
::
string
&
str
,
char
delim
,
bool
keep_empties
=
false
);
detail
::
match_helper
match_split
(
const
std
::
string
&
str
,
char
delim
,
bool
keep_empties
=
false
);
/**
* @brief Starts a match expression that matches each element in
...
...
@@ -295,8 +333,8 @@ detail::match_helper match_split(const std::string& str, char delim, bool keep_e
* @returns A helper object providing <tt>operator(...)</tt>.
*/
template
<
typename
InputIterator
>
auto
match_each
(
InputIterator
first
,
InputIterator
last
)
->
detail
::
match_each_helper
<
InputIterator
>
{
detail
::
match_each_helper
<
InputIterator
>
match_each
(
InputIterator
first
,
InputIterator
last
)
{
return
{
first
,
last
};
}
...
...
@@ -309,39 +347,40 @@ auto match_each(InputIterator first, InputIterator last)
* @returns A helper object providing <tt>operator(...)</tt>.
*/
template
<
typename
InputIterator
,
typename
Projection
>
auto
match_each
(
InputIterator
first
,
InputIterator
last
,
Projection
proj
)
->
detail
::
match_each_helper
<
InputIterator
,
Projection
>
{
detail
::
match_each_helper
<
InputIterator
,
Projection
>
match_each
(
InputIterator
first
,
InputIterator
last
,
Projection
proj
)
{
return
{
first
,
last
,
std
::
move
(
proj
)};
}
template
<
typename
InputIterator
,
typename
Predicate
>
auto
match_for
(
InputIterator
first
,
Predicate
pred
)
->
detail
::
match_for_helper
<
InputIterator
,
Predicate
>
{
detail
::
match_for_helper
<
InputIterator
,
Predicate
>
match_for
(
InputIterator
first
,
Predicate
pred
)
{
return
{
first
,
std
::
move
(
pred
)};
}
template
<
typename
InputIterator
,
typename
Predicate
,
typename
Advance
>
auto
match_for
(
InputIterator
first
,
Predicate
pred
,
Advance
adv
)
->
detail
::
match_for_helper
<
InputIterator
,
Predicate
,
Advance
>
{
detail
::
match_for_helper
<
InputIterator
,
Predicate
,
Advance
>
match_for
(
InputIterator
first
,
Predicate
pred
,
Advance
adv
)
{
return
{
first
,
std
::
move
(
pred
),
std
::
move
(
adv
)};
}
template
<
class
InputIterator
,
class
Predicate
,
class
Advance
,
class
Projection
>
auto
match_for
(
InputIterator
first
,
Predicate
pred
,
Advance
adv
,
Projection
pj
)
->
detail
::
match_for_helper
<
InputIterator
,
Predicate
,
Advance
,
Projection
>
{
detail
::
match_for_helper
<
InputIterator
,
Predicate
,
Advance
,
Projection
>
match_for
(
InputIterator
first
,
Predicate
pred
,
Advance
adv
,
Projection
pj
)
{
return
{
first
,
std
::
move
(
pred
),
std
::
move
(
adv
),
std
::
move
(
pj
)};
}
template
<
typename
T
>
detail
::
stream_matcher
<
T
,
std
::
istream_iterator
<
T
>
>
match_stream
(
std
::
istream
&
stream
)
{
detail
::
stream_matcher
<
T
,
std
::
istream_iterator
<
T
>>
match_stream
(
std
::
istream
&
stream
)
{
std
::
istream_iterator
<
T
>
first
(
stream
);
std
::
istream_iterator
<
T
>
last
;
// 'end of stream' iterator
return
{
first
,
last
};
}
template
<
typename
T
,
typename
InputIterator
>
detail
::
stream_matcher
<
T
,
InputIterator
>
match_stream
(
InputIterator
first
,
InputIterator
last
)
{
detail
::
stream_matcher
<
T
,
InputIterator
>
match_stream
(
InputIterator
first
,
InputIterator
last
)
{
return
{
first
,
last
};
}
...
...
cppa/optional_variant.hpp
View file @
ece82dbb
...
...
@@ -31,6 +31,7 @@
#ifndef OPTIONAL_VARIANT_HPP
#define OPTIONAL_VARIANT_HPP
#include <iosfwd>
#include <stdexcept>
#include <type_traits>
...
...
@@ -196,12 +197,12 @@ class optional_variant {
}
template
<
typename
Visitor
>
auto
apply
(
const
Visitor
&
visitor
)
const
->
decltype
(
visitor
(
none_t
{}))
{
auto
apply
(
Visitor
&
visitor
)
const
->
decltype
(
visitor
(
none_t
{}))
{
return
do_apply
(
*
this
,
visitor
);
}
template
<
typename
Visitor
>
auto
apply
(
const
Visitor
&
visitor
)
->
decltype
(
visitor
(
none_t
{}))
{
auto
apply
(
Visitor
&
visitor
)
->
decltype
(
visitor
(
none_t
{}))
{
return
do_apply
(
*
this
,
visitor
);
}
...
...
@@ -241,7 +242,7 @@ class optional_variant {
}
template
<
typename
Self
,
typename
Visitor
>
static
auto
do_apply
(
Self
&
from
,
const
Visitor
&
visitor
)
->
decltype
(
visitor
(
none_t
{}))
{
static
auto
do_apply
(
Self
&
from
,
Visitor
&
visitor
)
->
decltype
(
visitor
(
none_t
{}))
{
switch
(
from
.
m_type
)
{
default:
throw
std
::
runtime_error
(
"invalid type found"
);
case
-
1
:
return
visitor
(
none_t
{});
...
...
@@ -259,7 +260,8 @@ class optional_variant {
}
inline
void
destroy_data
()
{
apply
(
detail
::
optional_variant_data_destructor
{});
detail
::
optional_variant_data_destructor
f
;
apply
(
f
);
}
template
<
typename
U
>
...
...
@@ -325,6 +327,14 @@ T& get_ref(optional_variant<Us...>& value) {
return
value
.
get
(
token
);
}
/**
* @relates optional_variant
*/
template
<
typename
Visitor
,
typename
...
Ts
>
auto
apply_visitor
(
Visitor
&
visitor
,
const
optional_variant
<
Ts
...
>&
data
)
->
decltype
(
visitor
(
none_t
{}))
{
return
data
.
apply
(
visitor
);
}
/**
* @relates optional_variant
*/
...
...
@@ -333,6 +343,14 @@ auto apply_visitor(const Visitor& visitor, const optional_variant<Ts...>& data)
return
data
.
apply
(
visitor
);
}
/**
* @relates optional_variant
*/
template
<
typename
Visitor
,
typename
...
Ts
>
auto
apply_visitor
(
Visitor
&
visitor
,
optional_variant
<
Ts
...
>&
data
)
->
decltype
(
visitor
(
none_t
{}))
{
return
data
.
apply
(
visitor
);
}
/**
* @relates optional_variant
*/
...
...
@@ -349,6 +367,59 @@ struct optional_variant_from_type_list<util::type_list<Ts...>> {
typedef
optional_variant
<
Ts
...
>
type
;
};
namespace
detail
{
template
<
typename
T
>
struct
optional_variant_cmp_helper
{
const
T
&
lhs
;
optional_variant_cmp_helper
(
const
T
&
value
)
:
lhs
{
value
}
{
}
// variant is comparable
template
<
typename
U
>
typename
std
::
enable_if
<
util
::
is_comparable
<
T
,
U
>::
value
,
bool
>::
type
operator
()(
const
U
&
rhs
)
const
{
return
lhs
==
rhs
;
}
// variant is not comparable
template
<
typename
U
>
typename
std
::
enable_if
<!
util
::
is_comparable
<
T
,
U
>::
value
,
bool
>::
type
operator
()(
const
U
&
)
const
{
return
false
;
}
// variant is void
bool
operator
()()
const
{
return
false
;
}
};
}
// namespace detail
/**
* @relates optional_variant
*/
template
<
typename
T
,
typename
...
Ts
>
bool
operator
==
(
const
T
&
lhs
,
const
optional_variant
<
Ts
...
>&
rhs
)
{
return
apply_visitor
(
detail
::
optional_variant_cmp_helper
<
T
>
{
lhs
},
rhs
);
}
/**
* @relates optional_variant
*/
template
<
typename
T
,
typename
...
Ts
>
bool
operator
==
(
const
optional_variant
<
Ts
...
>&
lhs
,
const
T
&
rhs
)
{
return
rhs
==
lhs
;
}
namespace
detail
{
struct
optional_variant_ostream_helper
{
std
::
ostream
&
lhs
;
inline
optional_variant_ostream_helper
(
std
::
ostream
&
os
)
:
lhs
(
os
)
{
}
template
<
typename
T
>
std
::
ostream
&
operator
()(
const
T
&
value
)
const
{
return
lhs
<<
value
;
}
inline
std
::
ostream
&
operator
()(
const
none_t
&
)
const
{
return
lhs
;
}
inline
std
::
ostream
&
operator
()()
const
{
return
lhs
;
}
};
}
// namespace detail
/**
* @relates optional_variant
*/
template
<
typename
T0
,
typename
...
Ts
>
std
::
ostream
&
operator
<<
(
std
::
ostream
&
lhs
,
const
optional_variant
<
T0
,
Ts
...
>&
rhs
)
{
return
apply_visitor
(
detail
::
optional_variant_ostream_helper
{
lhs
},
rhs
);
}
}
// namespace cppa
#endif // OPTIONAL_VARIANT_HPP
unit_testing/test_match.cpp
View file @
ece82dbb
...
...
@@ -11,519 +11,339 @@
using
namespace
std
;
using
namespace
cppa
;
using
namespace
std
::
placeholders
;
using
namespace
cppa
::
placeholders
;
bool
is_even
(
int
i
)
{
return
i
%
2
==
0
;
}
/*
*
* projection:
*
* on(_x.rsplit("--(.*)=(.*)")) >> [](std::vector<std::string> matched_groups)
*
*/
struct
dummy
{
inline
operator
actor_ptr
()
const
{
return
nullptr
;
}
inline
actor_ptr
as_facade
()
const
{
return
nullptr
;
}
};
inline
dummy
operator
|
(
const
dummy
&
,
const
dummy
&
)
{
return
{};
}
bool
vec_sorted
(
const
std
::
vector
<
int
>&
vec
)
{
return
std
::
is_sorted
(
vec
.
begin
(),
vec
.
end
());
}
template
<
typename
T
>
dummy
operator
|
(
const
dummy
&
lhs
,
const
T
&
)
{
return
lhs
;
vector
<
string
>
kvp_split
(
const
string
&
str
)
{
auto
pos
=
str
.
find
(
'='
);
if
(
pos
!=
string
::
npos
&&
pos
==
str
.
rfind
(
'='
))
{
return
vector
<
string
>
{
str
.
substr
(
0
,
pos
),
str
.
substr
(
pos
+
1
)};
}
return
{};
}
template
<
typename
T
>
dummy
operator
|
(
const
T
&
,
const
dummy
&
rhs
)
{
return
rhs
;
optional
<
int
>
toint
(
const
string
&
str
)
{
char
*
endptr
=
nullptr
;
int
result
=
static_cast
<
int
>
(
strtol
(
str
.
c_str
(),
&
endptr
,
10
));
if
(
endptr
!=
nullptr
&&
*
endptr
==
'\0'
)
return
result
;
return
none
;
}
dummy
slice
(
int
,
int
)
{
return
{};
}
dummy
prepend
(
atom_value
)
{
return
{};
}
dummy
consume
(
atom_value
)
{
return
{};
}
dummy
split
(
int
)
{
return
{};
}
dummy
join
(
int
)
{
return
{};
}
template
<
size_t
Pos
,
size_t
Max
>
struct
index_token
{
};
void
example
()
{
// {}: tuple
// []: list
// 'a': atom 'a' == atom("a")
// x => y: replies to x with y
template
<
size_t
Max
>
void
foobar
(
index_token
<
Max
,
Max
>
)
{
}
{
// for starters: get the internally used user-ID from a key-value store
// and get the user role, e.g., "admin", from the user database
template
<
size_t
Pos
,
size_t
Max
>
void
foobar
(
index_token
<
Pos
,
Max
>
)
{
cout
<<
"foobar<"
<<
Pos
<<
","
<<
Max
<<
">"
<<
endl
;
foobar
(
index_token
<
Pos
+
1
,
Max
>
{});
}
// {'get', key} => {user_id, [tags]}
actor_ptr
kvstore
;
// {'info', user_id} => {name, address, phone, role}
actor_ptr
userinfo
;
// {username} => {role}
auto
query
=
kvstore
|
slice
(
0
,
0
)
|
prepend
(
atom
(
"info"
))
|
userinfo
|
slice
(
3
,
3
);
// check whether Dirty Harry has admin access
sync_send
(
query
,
atom
(
"get"
),
"Dirty Harry"
).
then
(
on
(
"admin"
)
>>
[]
{
// grant access
},
others
()
>>
[]
{
// deny access (well, no one denies Dirty Harry access anyways)
}
int
main
()
{
CPPA_TEST
(
test_match
);
/* test guard evaluation */
{
// ascending values
auto
ascending
=
[](
int
a
,
int
b
,
int
c
)
->
bool
{
return
a
<
b
&&
b
<
c
;
};
auto
expr0_a
=
gcall
(
ascending
,
_x1
,
_x2
,
_x3
);
CPPA_CHECK
(
ge_invoke
(
expr0_a
,
1
,
2
,
3
));
CPPA_CHECK
(
!
ge_invoke
(
expr0_a
,
3
,
2
,
1
));
int
ival0
=
2
;
auto
expr0_b
=
gcall
(
ascending
,
_x1
,
std
::
ref
(
ival0
),
_x2
);
CPPA_CHECK
(
ge_invoke
(
expr0_b
,
1
,
3
));
++
ival0
;
CPPA_CHECK
(
!
ge_invoke
(
expr0_b
,
1
,
3
));
auto
expr0_c
=
gcall
(
ascending
,
10
,
_x1
,
30
);
CPPA_CHECK
(
!
ge_invoke
(
expr0_c
,
10
));
CPPA_CHECK
(
ge_invoke
(
expr0_c
,
11
));
// user-defined expressions using '+', '<', '%'
auto
expr1
=
_x1
+
_x2
;
auto
expr2
=
_x1
+
_x2
<
_x3
;
auto
expr3
=
_x1
%
_x2
==
0
;
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr1
,
2
,
3
)),
5
);
CPPA_CHECK
(
expr2
(
1
,
2
,
4
));
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr1
,
std
::
string
{
"1"
},
std
::
string
{
"2"
})),
"12"
);
CPPA_CHECK
(
expr3
(
100
,
2
));
// user-defined expressions using '||'
auto
expr4
=
_x1
==
"-h"
||
_x1
==
"--help"
;
CPPA_CHECK
(
ge_invoke
(
expr4
,
string
(
"-h"
)));
CPPA_CHECK
(
ge_invoke
(
expr4
,
string
(
"--help"
)));
CPPA_CHECK
(
!
ge_invoke
(
expr4
,
string
(
"-g"
)));
}
/* guard expressions on containers */
{
auto
expr5
=
_x1
.
starts_with
(
"--"
);
CPPA_CHECK
(
ge_invoke
(
expr5
,
string
(
"--help"
)));
CPPA_CHECK
(
!
ge_invoke
(
expr5
,
string
(
"-help"
)));
// container search (x in y)
vector
<
string
>
vec1
{
"hello"
,
"world"
};
auto
expr6
=
_x1
.
in
(
vec1
);
CPPA_CHECK
(
ge_invoke
(
expr6
,
string
(
"hello"
)));
CPPA_CHECK
(
ge_invoke
(
expr6
,
string
(
"world"
)));
CPPA_CHECK
(
!
ge_invoke
(
expr6
,
string
(
"hello world"
)));
auto
expr7
=
_x1
.
in
(
std
::
ref
(
vec1
));
CPPA_CHECK
(
ge_invoke
(
expr7
,
string
(
"hello"
)));
CPPA_CHECK
(
ge_invoke
(
expr7
,
string
(
"world"
)));
CPPA_CHECK
(
!
ge_invoke
(
expr7
,
string
(
"hello world"
)));
vec1
.
emplace_back
(
"hello world"
);
CPPA_CHECK
(
!
ge_invoke
(
expr6
,
string
(
"hello world"
)));
CPPA_CHECK
(
ge_invoke
(
expr7
,
string
(
"hello world"
)));
// container search (x in y) for initializer lists
auto
expr11
=
_x1
.
in
({
"one"
,
"two"
});
CPPA_CHECK
(
ge_invoke
(
expr11
,
string
(
"one"
)));
CPPA_CHECK
(
ge_invoke
(
expr11
,
string
(
"two"
)));
CPPA_CHECK
(
!
ge_invoke
(
expr11
,
string
(
"three"
)));
// container search (x not in y)
auto
expr12
=
_x1
.
not_in
({
"hello"
,
"world"
});
CPPA_CHECK
(
ge_invoke
(
expr12
,
string
(
"foo"
)));
CPPA_CHECK
(
!
ge_invoke
(
expr12
,
string
(
"hello"
)));
// user-defined function to evaluate whether container is sorted
std
::
vector
<
int
>
expr21_vec_a
{
1
,
2
,
3
};
std
::
vector
<
int
>
expr21_vec_b
{
1
,
0
,
2
};
auto
expr21
=
gcall
(
vec_sorted
,
_x1
);
CPPA_CHECK
(
ge_invoke
(
expr21
,
expr21_vec_a
));
CPPA_CHECK
(
!
ge_invoke
(
expr21
,
expr21_vec_b
));
auto
expr22
=
_x1
.
empty
()
&&
_x2
.
not_empty
();
CPPA_CHECK
(
ge_invoke
(
expr22
,
std
::
string
(
""
),
std
::
string
(
"abc"
)));
}
/* user-defined expressions */
{
int
ival
=
5
;
auto
expr8
=
_x1
==
ival
;
auto
expr9
=
_x1
==
std
::
ref
(
ival
);
CPPA_CHECK
(
ge_invoke
(
expr8
,
5
));
CPPA_CHECK
(
ge_invoke
(
expr9
,
5
));
ival
=
10
;
CPPA_CHECK
(
!
ge_invoke
(
expr9
,
5
));
CPPA_CHECK
(
ge_invoke
(
expr9
,
10
));
// user-defined expressions w/ wide range of operators
auto
expr13
=
_x1
*
_x2
<
_x3
-
_x4
;
CPPA_CHECK
(
ge_invoke
(
expr13
,
1
,
1
,
4
,
2
));
auto
expr14
=
_x1
+
_x2
;
static_assert
(
std
::
is_same
<
decltype
(
ge_invoke
(
expr14
,
1
,
2
)),
int
>::
value
,
"wrong return type"
);
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr14
,
2
,
3
)),
5
);
auto
expr15
=
_x1
+
_x2
+
_x3
;
static_assert
(
std
::
is_same
<
decltype
(
ge_invoke
(
expr15
,
1
,
2
,
3
)),
int
>::
value
,
"wrong return type"
);
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr15
,
7
,
10
,
25
)),
42
);
// user-defined operations on containers such as 'size' and 'front'
std
::
string
expr16_str
;
// = "expr16";
auto
expr16_a
=
_x1
.
size
();
auto
expr16_b
=
_x1
.
front
()
==
'e'
;
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr16_b
,
expr16_str
)),
false
);
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr16_a
,
expr16_str
)),
0
);
expr16_str
=
"expr16"
;
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr16_b
,
expr16_str
)),
true
);
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr16_a
,
expr16_str
)),
expr16_str
.
size
());
expr16_str
.
front
()
=
'_'
;
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr16_b
,
expr16_str
)),
false
);
}
/* user-defined expressions using 'gref' */
{
int
expr17_value
=
42
;
auto
expr17
=
gref
(
expr17_value
)
==
42
;
CPPA_CHECK_EQUAL
(
ge_invoke
(
expr17
),
true
);
expr17_value
=
0
;
CPPA_CHECK_EQUAL
(
ge_invoke
(
expr17
),
false
);
int
expr18_value
=
42
;
auto
expr18_a
=
gref
(
expr18_value
)
==
42
;
CPPA_CHECK_EQUAL
(
ge_invoke
(
expr18_a
),
true
);
expr18_value
=
0
;
CPPA_CHECK_EQUAL
(
ge_invoke
(
expr18_a
),
false
);
auto
expr18_b
=
gref
(
expr18_value
)
==
_x1
;
auto
expr18_c
=
std
::
ref
(
expr18_value
)
==
_x1
;
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr18_b
,
0
)),
true
);
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr18_c
,
0
)),
true
);
bool
enable_case1
=
true
;
auto
expr19
=
(
on
<
anything
>
().
when
(
gref
(
enable_case1
)
==
false
)
>>
[]
{
return
1
;
},
on
<
anything
>
()
>>
[]
{
return
2
;
}
);
// creates a new actor providing the interface {username} => {role}
actor_ptr
roles
=
query
.
as_facade
();
any_tuple
expr19_tup
=
make_cow_tuple
(
"hello guard!"
);
CPPA_CHECK_EQUAL
(
expr19
(
expr19_tup
),
2
);
partial_function
expr20
=
expr19
;
enable_case1
=
false
;
CPPA_CHECK_EQUAL
(
expr20
(
expr19_tup
),
1
);
}
{
// we have an actor representing a database for orders and we want
// to have the net price of all orders from Dirty Harry
// {'orders', user_id} => {[order_id]}
// {'price', order_id} => {net_price}
actor_ptr
orders
;
// {'prices', user_id} => {[net_price]}
auto
query
=
consume
(
atom
(
"prices"
))
|
prepend
(
atom
(
"orders"
))
|
orders
|
prepend
(
atom
(
"price"
))
|
split
(
1
)
|
orders
|
join
(
0
);
sync_send
(
query
,
atom
(
"prices"
),
"Dirty Harry"
).
then
(
[](
const
vector
<
float
>&
prices
)
{
cout
<<
"Dirty Harry has ordered products "
<<
"with a total net price of $"
<<
accumulate
(
prices
.
begin
(),
prices
.
end
(),
0
)
<<
endl
;
/* test 'match' function */
{
auto
res0
=
match
(
5
)
(
on_arg_match
.
when
(
_x1
<
6
)
>>
[
&
](
int
i
)
{
CPPA_CHECK_EQUAL
(
i
,
5
);
}
);
CPPA_CHECK
(
res0
);
auto
res1
=
match
(
"value=42"
)
(
on
(
kvp_split
).
when
(
_x1
.
not_empty
())
>>
[
&
](
const
vector
<
string
>&
vec
)
{
CPPA_CHECK_EQUAL
(
"value"
,
vec
[
0
]);
CPPA_CHECK_EQUAL
(
"42"
,
vec
[
1
]);
}
);
CPPA_CHECK
(
res1
);
auto
res2
=
match
(
"42"
)
(
on
(
toint
)
>>
[
&
](
int
i
)
{
CPPA_CHECK_EQUAL
(
42
,
i
);
}
);
CPPA_CHECK
(
res2
);
auto
res3
=
match
(
"abc"
)
(
on
<
string
>
().
when
(
_x1
==
"abc"
)
>>
[
&
]
{
}
);
CPPA_CHECK
(
res3
);
CPPA_CHECK
(
res3
.
is
<
void
>
());
// match vectors
auto
res4
=
match
(
std
::
vector
<
int
>
{
1
,
2
,
3
})
(
on
<
int
,
int
,
int
>
().
when
(
_x1
+
_x2
+
_x3
==
6
&&
_x2
(
is_even
)
&&
_x3
%
2
==
1
)
>>
[
&
]
{
}
);
CPPA_CHECK
(
res4
);
vector
<
string
>
vec
{
"a"
,
"b"
,
"c"
};
auto
res5
=
match
(
vec
)
(
on
(
"a"
,
"b"
,
val
<
string
>
)
>>
[](
string
&
)
->
string
{
return
"C"
;
}
);
CPPA_CHECK_EQUAL
(
res5
,
"C"
);
}
}
template
<
typename
T
>
struct
type_token
{
typedef
T
type
;
};
template
<
typename
...
Ts
>
struct
variant
;
template
<
typename
T
>
struct
variant
<
T
>
{
T
&
get
(
type_token
<
T
>
)
{
return
m_value
;
}
T
m_value
;
};
template
<
typename
T0
,
typename
T1
>
struct
variant
<
T0
,
T1
>
{
public:
T0
&
get
(
type_token
<
T0
>
)
{
return
m_v0
;
}
T1
&
get
(
type_token
<
T1
>
)
{
return
m_v1
;
}
variant
()
:
m_type
{
0
},
m_v0
{}
{
}
~
variant
()
{
switch
(
m_type
)
{
case
0
:
m_v0
.
~
T0
();
break
;
case
1
:
m_v1
.
~
T1
();
break
;
}
}
private:
size_t
m_type
;
union
{
T0
m_v0
;
T1
m_v1
;
};
};
template
<
typename
T
,
typename
...
Ts
>
T
&
get
(
variant
<
Ts
...
>&
v
)
{
return
v
.
get
(
type_token
<
T
>
{});
}
int
main
()
{
CPPA_TEST
(
test_match
);
using
namespace
std
::
placeholders
;
using
namespace
cppa
::
placeholders
;
variant
<
int
,
double
>
rofl
;
get
<
int
>
(
rofl
)
=
42
;
cout
<<
"rofl = "
<<
get
<
int
>
(
rofl
)
<<
endl
;
auto
ascending
=
[](
int
a
,
int
b
,
int
c
)
->
bool
{
return
a
<
b
&&
b
<
c
;
};
auto
expr0_a
=
gcall
(
ascending
,
_x1
,
_x2
,
_x3
);
CPPA_CHECK
(
ge_invoke
(
expr0_a
,
1
,
2
,
3
));
CPPA_CHECK
(
!
ge_invoke
(
expr0_a
,
3
,
2
,
1
));
int
ival0
=
2
;
auto
expr0_b
=
gcall
(
ascending
,
_x1
,
std
::
ref
(
ival0
),
_x2
);
CPPA_CHECK
(
ge_invoke
(
expr0_b
,
1
,
3
));
++
ival0
;
CPPA_CHECK
(
!
ge_invoke
(
expr0_b
,
1
,
3
));
auto
expr0_c
=
gcall
(
ascending
,
10
,
_x1
,
30
);
CPPA_CHECK
(
!
ge_invoke
(
expr0_c
,
10
));
CPPA_CHECK
(
ge_invoke
(
expr0_c
,
11
));
auto
expr1
=
_x1
+
_x2
;
auto
expr2
=
_x1
+
_x2
<
_x3
;
auto
expr3
=
_x1
%
_x2
==
0
;
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr1
,
2
,
3
)),
5
);
//CPPA_CHECK(ge_invoke(expr2, 1, 2, 4));
CPPA_CHECK
(
expr2
(
1
,
2
,
4
));
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr1
,
std
::
string
{
"1"
},
std
::
string
{
"2"
})),
"12"
);
CPPA_CHECK
(
expr3
(
100
,
2
));
auto
expr4
=
_x1
==
"-h"
||
_x1
==
"--help"
;
CPPA_CHECK
(
ge_invoke
(
expr4
,
string
(
"-h"
)));
CPPA_CHECK
(
ge_invoke
(
expr4
,
string
(
"--help"
)));
CPPA_CHECK
(
!
ge_invoke
(
expr4
,
string
(
"-g"
)));
auto
expr5
=
_x1
.
starts_with
(
"--"
);
CPPA_CHECK
(
ge_invoke
(
expr5
,
string
(
"--help"
)));
CPPA_CHECK
(
!
ge_invoke
(
expr5
,
string
(
"-help"
)));
vector
<
string
>
vec1
{
"hello"
,
"world"
};
auto
expr6
=
_x1
.
in
(
vec1
);
CPPA_CHECK
(
ge_invoke
(
expr6
,
string
(
"hello"
)));
CPPA_CHECK
(
ge_invoke
(
expr6
,
string
(
"world"
)));
CPPA_CHECK
(
!
ge_invoke
(
expr6
,
string
(
"hello world"
)));
auto
expr7
=
_x1
.
in
(
std
::
ref
(
vec1
));
CPPA_CHECK
(
ge_invoke
(
expr7
,
string
(
"hello"
)));
CPPA_CHECK
(
ge_invoke
(
expr7
,
string
(
"world"
)));
CPPA_CHECK
(
!
ge_invoke
(
expr7
,
string
(
"hello world"
)));
vec1
.
emplace_back
(
"hello world"
);
CPPA_CHECK
(
!
ge_invoke
(
expr6
,
string
(
"hello world"
)));
CPPA_CHECK
(
ge_invoke
(
expr7
,
string
(
"hello world"
)));
int
ival
=
5
;
auto
expr8
=
_x1
==
ival
;
auto
expr9
=
_x1
==
std
::
ref
(
ival
);
CPPA_CHECK
(
ge_invoke
(
expr8
,
5
));
CPPA_CHECK
(
ge_invoke
(
expr9
,
5
));
ival
=
10
;
CPPA_CHECK
(
!
ge_invoke
(
expr9
,
5
));
CPPA_CHECK
(
ge_invoke
(
expr9
,
10
));
auto
expr11
=
_x1
.
in
({
"one"
,
"two"
});
CPPA_CHECK
(
ge_invoke
(
expr11
,
string
(
"one"
)));
CPPA_CHECK
(
ge_invoke
(
expr11
,
string
(
"two"
)));
CPPA_CHECK
(
!
ge_invoke
(
expr11
,
string
(
"three"
)));
auto
expr12
=
_x1
*
_x2
<
_x3
-
_x4
;
CPPA_CHECK
(
ge_invoke
(
expr12
,
1
,
1
,
4
,
2
));
auto
expr13
=
_x1
.
not_in
({
"hello"
,
"world"
});
CPPA_CHECK
(
ge_invoke
(
expr13
,
string
(
"foo"
)));
CPPA_CHECK
(
!
ge_invoke
(
expr13
,
string
(
"hello"
)));
auto
expr14
=
_x1
+
_x2
;
static_assert
(
std
::
is_same
<
decltype
(
ge_invoke
(
expr14
,
1
,
2
)),
int
>::
value
,
"wrong return type"
);
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr14
,
2
,
3
)),
5
);
auto
expr15
=
_x1
+
_x2
+
_x3
;
static_assert
(
std
::
is_same
<
decltype
(
ge_invoke
(
expr15
,
1
,
2
,
3
)),
int
>::
value
,
"wrong return type"
);
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr15
,
7
,
10
,
25
)),
42
);
std
::
string
expr16_str
;
// = "expr16";
auto
expr16_a
=
_x1
.
size
();
auto
expr16_b
=
_x1
.
front
()
==
'e'
;
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr16_b
,
expr16_str
)),
false
);
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr16_a
,
expr16_str
)),
0
);
expr16_str
=
"expr16"
;
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr16_b
,
expr16_str
)),
true
);
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr16_a
,
expr16_str
)),
expr16_str
.
size
());
expr16_str
.
front
()
=
'_'
;
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr16_b
,
expr16_str
)),
false
);
int
expr17_value
=
42
;
auto
expr17
=
gref
(
expr17_value
)
==
42
;
CPPA_CHECK_EQUAL
(
ge_invoke
(
expr17
),
true
);
expr17_value
=
0
;
CPPA_CHECK_EQUAL
(
ge_invoke
(
expr17
),
false
);
int
expr18_value
=
42
;
auto
expr18_a
=
gref
(
expr18_value
)
==
42
;
CPPA_CHECK_EQUAL
(
ge_invoke
(
expr18_a
),
true
);
expr18_value
=
0
;
CPPA_CHECK_EQUAL
(
ge_invoke
(
expr18_a
),
false
);
auto
expr18_b
=
gref
(
expr18_value
)
==
_x1
;
auto
expr18_c
=
std
::
ref
(
expr18_value
)
==
_x1
;
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr18_b
,
0
)),
true
);
CPPA_CHECK_EQUAL
((
ge_invoke
(
expr18_c
,
0
)),
true
);
bool
invoked
=
false
;
auto
kvp_split1
=
[](
const
string
&
str
)
->
vector
<
string
>
{
auto
pos
=
str
.
find
(
'='
);
if
(
pos
!=
string
::
npos
&&
pos
==
str
.
rfind
(
'='
))
{
return
vector
<
string
>
{
str
.
substr
(
0
,
pos
),
str
.
substr
(
pos
+
1
)};
}
return
{};
};
match
(
"value=42"
)
(
on
(
kvp_split1
).
when
(
_x1
.
not_empty
())
>>
[
&
](
const
vector
<
string
>&
vec
)
{
CPPA_CHECK_EQUAL
(
"value"
,
vec
[
0
]);
CPPA_CHECK_EQUAL
(
"42"
,
vec
[
1
]);
invoked
=
true
;
}
);
CPPA_CHECK
(
invoked
);
invoked
=
false
;
auto
toint
=
[](
const
string
&
str
)
->
optional
<
int
>
{
char
*
endptr
=
nullptr
;
int
result
=
static_cast
<
int
>
(
strtol
(
str
.
c_str
(),
&
endptr
,
10
));
if
(
endptr
!=
nullptr
&&
*
endptr
==
'\0'
)
{
return
result
;
}
return
none
;
};
match
(
"42"
)
(
on
(
toint
)
>>
[
&
](
int
i
)
{
CPPA_CHECK_EQUAL
(
42
,
i
);
invoked
=
true
;
}
);
CPPA_CHECK
(
invoked
);
invoked
=
false
;
match
(
"abc"
)
(
on
<
string
>
().
when
(
_x1
==
"abc"
)
>>
[
&
]()
{
invoked
=
true
;
}
);
if
(
!
invoked
)
{
CPPA_FAILURE
(
"match(
\"
abc
\"
) failed"
);
}
invoked
=
false
;
bool
disable_case1
=
true
;
bool
case1_invoked
=
false
;
bool
case2_invoked
=
false
;
auto
expr19
=
(
on
<
anything
>
().
when
(
gref
(
disable_case1
)
==
false
)
>>
[
&
]()
{
case1_invoked
=
true
;
},
on
<
anything
>
()
>>
[
&
]()
{
case2_invoked
=
true
;
}
);
any_tuple
expr19_tup
=
make_cow_tuple
(
"hello guard!"
);
expr19
(
expr19_tup
);
CPPA_CHECK
(
!
case1_invoked
);
CPPA_CHECK
(
case2_invoked
);
partial_function
expr20
=
expr19
;
case1_invoked
=
false
;
case2_invoked
=
false
;
disable_case1
=
false
;
expr20
(
expr19_tup
);
CPPA_CHECK
(
case1_invoked
);
CPPA_CHECK
(
!
case2_invoked
);
std
::
vector
<
int
>
expr21_vec_a
{
1
,
2
,
3
};
std
::
vector
<
int
>
expr21_vec_b
{
1
,
0
,
2
};
auto
vec_sorted
=
[](
const
std
::
vector
<
int
>&
vec
)
{
return
std
::
is_sorted
(
vec
.
begin
(),
vec
.
end
());
};
auto
expr21
=
gcall
(
vec_sorted
,
_x1
);
CPPA_CHECK
(
ge_invoke
(
expr21
,
expr21_vec_a
));
CPPA_CHECK
(
!
ge_invoke
(
expr21
,
expr21_vec_b
));
auto
expr22
=
_x1
.
empty
()
&&
_x2
.
not_empty
();
CPPA_CHECK
(
ge_invoke
(
expr22
,
std
::
string
(
""
),
std
::
string
(
"abc"
)));
match
(
std
::
vector
<
int
>
{
1
,
2
,
3
})
(
on
<
int
,
int
,
int
>
().
when
(
_x1
+
_x2
+
_x3
==
6
&&
_x2
(
is_even
)
&&
_x3
%
2
==
1
)
>>
[
&
]()
{
invoked
=
true
;
}
);
if
(
!
invoked
)
{
CPPA_FAILURE
(
"match({1, 2, 3}) failed"
);
}
invoked
=
false
;
string
sum
;
vector
<
string
>
sum_args
=
{
"-h"
,
"--version"
,
"-wtf"
};
match_each
(
begin
(
sum_args
),
end
(
sum_args
))
(
on
<
string
>
().
when
(
_x1
.
in
({
"-h"
,
"--help"
}))
>>
[
&
](
string
s
)
{
sum
+=
s
;
},
on
<
string
>
().
when
(
_x1
==
"-v"
||
_x1
==
"--version"
)
>>
[
&
](
string
s
)
{
sum
+=
s
;
},
on
<
string
>
().
when
(
_x1
.
starts_with
(
"-"
))
>>
[
&
](
const
string
&
str
)
{
match_each
(
str
.
begin
()
+
1
,
str
.
end
())
(
on
<
char
>
().
when
(
_x1
.
in
({
'w'
,
't'
,
'f'
}))
>>
[
&
](
char
c
)
{
sum
+=
c
;
},
on
<
char
>
()
>>
CPPA_FAILURE_CB
(
"guard didn't match"
),
others
()
>>
CPPA_FAILURE_CB
(
"unexpected match"
)
);
},
others
()
>>
CPPA_FAILURE_CB
(
"unexpected match"
)
);
CPPA_CHECK_EQUAL
(
sum
,
"-h--versionwtf"
);
match
(
5
)
(
on
<
int
>
().
when
(
_x1
<
6
)
>>
[
&
](
int
i
)
{
CPPA_CHECK_EQUAL
(
i
,
5
);
invoked
=
true
;
}
);
CPPA_CHECK
(
invoked
);
invoked
=
false
;
vector
<
string
>
vec
{
"a"
,
"b"
,
"c"
};
match
(
vec
)
(
on
(
"a"
,
"b"
,
val
<
string
>
)
>>
[
&
](
string
&
str
)
{
invoked
=
true
;
str
=
"C"
;
}
);
if
(
!
invoked
)
{
CPPA_FAILURE
(
"match({
\"
a
\"
,
\"
b
\"
,
\"
c
\"
}) failed"
);
}
CPPA_CHECK_EQUAL
(
vec
.
back
(),
"C"
);
invoked
=
false
;
match_each
(
begin
(
vec
),
end
(
vec
))
(
on
(
"a"
)
>>
[
&
](
string
&
str
)
{
invoked
=
true
;
str
=
"A"
;
}
);
if
(
!
invoked
)
{
CPPA_FAILURE
(
"match_each({
\"
a
\"
,
\"
b
\"
,
\"
C
\"
}) failed"
);
}
CPPA_CHECK_EQUAL
(
vec
.
front
(),
"A"
);
invoked
=
false
;
vector
<
string
>
vec2
{
"a=0"
,
"b=1"
,
"c=2"
};
auto
c2
=
split
(
vec2
.
back
(),
'='
);
match
(
c2
)
(
on
(
"c"
,
"2"
)
>>
[
&
]()
{
invoked
=
true
;
}
);
CPPA_CHECK_EQUAL
(
invoked
,
true
);
invoked
=
false
;
// let's get the awesomeness started
bool
success
=
false
;
istringstream
iss
(
"hello world"
);
success
=
match_stream
<
string
>
(
iss
)
(
on
(
"hello"
,
"world"
)
>>
CPPA_CHECKPOINT_CB
()
);
CPPA_CHECK_EQUAL
(
success
,
true
);
auto
extract_name
=
[](
const
string
&
kvp
)
->
optional
<
string
>
{
auto
vec
=
split
(
kvp
,
'='
);
if
(
vec
.
size
()
==
2
)
{
if
(
vec
.
front
()
==
"--name"
)
{
return
vec
.
back
();
/* test 'match_each' */
{
string
sum
;
vector
<
string
>
sum_args
=
{
"-h"
,
"--version"
,
"-wtf"
};
auto
iter1
=
match_each
(
begin
(
sum_args
),
end
(
sum_args
))
(
on
<
string
>
().
when
(
_x1
.
in
({
"-h"
,
"--help"
}))
>>
[
&
](
const
string
&
s
)
{
sum
+=
s
;
},
on
<
string
>
().
when
(
_x1
==
"-v"
||
_x1
==
"--version"
)
>>
[
&
](
const
string
&
s
)
{
sum
+=
s
;
},
on
<
string
>
().
when
(
_x1
.
starts_with
(
"-"
))
>>
[
&
](
const
string
&
str
)
{
match_each
(
str
.
begin
()
+
1
,
str
.
end
())
(
on
<
char
>
().
when
(
_x1
.
in
({
'w'
,
't'
,
'f'
}))
>>
[
&
](
char
c
)
{
sum
+=
c
;
},
on
<
char
>
()
>>
CPPA_FAILURE_CB
(
"guard didn't match"
),
others
()
>>
CPPA_FAILURE_CB
(
"unexpected match"
)
);
}
}
return
none
;
};
const
char
*
svec
[]
=
{
"-n"
,
"foo"
,
"--name=bar"
,
"-p"
,
"2"
};
success
=
match_stream
<
string
>
(
begin
(
svec
),
end
(
svec
))
(
(
on
(
"-n"
,
arg_match
)
||
on
(
extract_name
))
>>
[](
const
string
&
name
)
->
bool
{
CPPA_CHECK
(
name
==
"foo"
||
name
==
"bar"
);
return
name
==
"foo"
||
name
==
"bar"
;
},
on
(
"-p"
,
arg_match
)
>>
[
&
](
const
string
&
port
)
->
match_hint
{
auto
i
=
toint
(
port
);
if
(
i
)
{
CPPA_CHECK_EQUAL
(
*
i
,
2
);
return
match_hint
::
handle
;
);
CPPA_CHECK
(
iter1
==
end
(
sum_args
));
CPPA_CHECK_EQUAL
(
sum
,
"-h--versionwtf"
);
auto
iter2
=
match_each
(
begin
(
sum_args
),
end
(
sum_args
))
(
on
(
"-h"
)
>>
[]
{
}
);
CPPA_CHECK
(
iter2
==
(
begin
(
sum_args
)
+
1
));
}
/* test match_stream */
{
bool
success
=
false
;
istringstream
iss
(
"hello world"
);
success
=
match_stream
<
string
>
(
iss
)
(
on
(
"hello"
,
"world"
)
>>
CPPA_CHECKPOINT_CB
()
);
CPPA_CHECK_EQUAL
(
success
,
true
);
auto
extract_name
=
[](
const
string
&
kvp
)
->
optional
<
string
>
{
auto
vec
=
split
(
kvp
,
'='
);
if
(
vec
.
size
()
==
2
&&
vec
.
front
()
==
"--name"
)
return
vec
.
back
();
return
none
;
};
const
char
*
svec
[]
=
{
"-n"
,
"foo"
,
"--name=bar"
,
"-p"
,
"2"
};
success
=
match_stream
<
string
>
(
begin
(
svec
),
end
(
svec
))
(
(
on
(
"-n"
,
arg_match
)
||
on
(
extract_name
))
>>
[](
const
string
&
name
)
->
bool
{
CPPA_CHECK
(
name
==
"foo"
||
name
==
"bar"
);
return
name
==
"foo"
||
name
==
"bar"
;
},
on
(
"-p"
,
arg_match
)
>>
[
&
](
const
string
&
port
)
->
match_hint
{
auto
i
=
toint
(
port
);
if
(
i
)
{
CPPA_CHECK_EQUAL
(
*
i
,
2
);
return
match_hint
::
handle
;
}
else
return
match_hint
::
skip
;
},
on_arg_match
>>
[](
const
string
&
arg
)
->
match_hint
{
CPPA_FAILURE
(
"unexpected string: "
<<
arg
);
return
match_hint
::
skip
;
}
else
return
match_hint
::
skip
;
},
on_arg_match
>>
[](
const
string
&
arg
)
->
match_hint
{
CPPA_FAILURE
(
"unexpected string: "
<<
arg
);
return
match_hint
::
skip
;
}
);
CPPA_CHECK_EQUAL
(
success
,
true
);
CPPA_PRINT
(
"check combined partial function matching"
);
std
::
string
last_invoked_fun
;
# define check(pf, tup, str) { \
last_invoked_fun = ""; \
pf(tup); \
CPPA_CHECK_EQUAL(last_invoked_fun, str); \
);
CPPA_CHECK_EQUAL
(
success
,
true
);
}
partial_function
pf0
=
(
on
<
int
,
int
>
()
>>
[
&
]
{
last_invoked_fun
=
"<int, int>@1"
;
},
on
<
float
>
()
>>
[
&
]
{
last_invoked_fun
=
"<float>@2"
;
}
);
auto
pf1
=
pf0
.
or_else
(
on
<
int
,
int
>
()
>>
[
&
]
{
last_invoked_fun
=
"<int, int>@3"
;
},
on
<
string
>
()
>>
[
&
]
{
last_invoked_fun
=
"<string>@4"
;
}
);
check
(
pf0
,
make_any_tuple
(
1
,
2
),
"<int, int>@1"
);
check
(
pf1
,
make_any_tuple
(
1
,
2
),
"<int, int>@1"
);
check
(
pf0
,
make_any_tuple
(
"hi"
),
""
);
check
(
pf1
,
make_any_tuple
(
"hi"
),
"<string>@4"
);
CPPA_PRINT
(
"check match expressions with boolean return value"
);
// utility macro to identify invoked functors
std
::
string
last_invoked_fun
;
# define bhvr_check(pf, tup, expected_result, str) { \
last_invoked_fun = ""; \
CPPA_CHECK_EQUAL(pf(tup), expected_result); \
CPPA_CHECK_EQUAL(last_invoked_fun, str); \
}
behavior
bhvr1
=
(
on
<
int
>
()
>>
[
&
](
int
i
)
->
match_hint
{
last_invoked_fun
=
"<int>@1"
;
return
(
i
==
42
)
?
match_hint
::
skip
:
match_hint
::
handle
;
},
on
<
float
>
()
>>
[
&
]
{
last_invoked_fun
=
"<float>@2"
;
},
on
<
int
>
()
>>
[
&
]
{
last_invoked_fun
=
"<int>@3"
;
},
others
()
>>
[
&
]
{
last_invoked_fun
=
"<*>@4"
;
}
);
bhvr_check
(
bhvr1
,
make_any_tuple
(
42
),
false
,
"<int>@1"
);
bhvr_check
(
bhvr1
,
make_any_tuple
(
24
),
true
,
"<int>@1"
);
bhvr_check
(
bhvr1
,
make_any_tuple
(
2.
f
),
true
,
"<float>@2"
);
bhvr_check
(
bhvr1
,
make_any_tuple
(
""
),
true
,
"<*>@4"
);
partial_function
pf11
{
on_arg_match
>>
[
&
](
int
)
{
last_invoked_fun
=
"<int>@1"
;
}
};
partial_function
pf12
{
on_arg_match
>>
[
&
](
int
)
{
last_invoked_fun
=
"<int>@2"
;
},
on_arg_match
>>
[
&
](
float
)
{
last_invoked_fun
=
"<float>@2"
;
}
};
auto
pf13
=
pf11
.
or_else
(
pf12
);
bhvr_check
(
pf13
,
make_any_tuple
(
42
),
true
,
"<int>@1"
);
bhvr_check
(
pf13
,
make_any_tuple
(
42.24
f
),
true
,
"<float>@2"
);
/* test if match hints are evaluated properly */
{
behavior
bhvr1
{
on
<
int
>
()
>>
[
&
](
int
i
)
->
match_hint
{
last_invoked_fun
=
"<int>@1"
;
return
(
i
==
42
)
?
match_hint
::
skip
:
match_hint
::
handle
;
},
on
<
float
>
()
>>
[
&
]
{
last_invoked_fun
=
"<float>@2"
;
},
on
<
int
>
()
>>
[
&
]
{
last_invoked_fun
=
"<int>@3"
;
},
others
()
>>
[
&
]
{
last_invoked_fun
=
"<*>@4"
;
}
};
bhvr_check
(
bhvr1
,
make_any_tuple
(
42
),
false
,
"<int>@1"
);
bhvr_check
(
bhvr1
,
make_any_tuple
(
24
),
true
,
"<int>@1"
);
bhvr_check
(
bhvr1
,
make_any_tuple
(
2.
f
),
true
,
"<float>@2"
);
bhvr_check
(
bhvr1
,
make_any_tuple
(
""
),
true
,
"<*>@4"
);
}
/* test or_else concatenation */
{
partial_function
pf0
{
on
<
int
,
int
>
()
>>
[
&
]
{
last_invoked_fun
=
"<int, int>@1"
;
},
on
<
float
>
()
>>
[
&
]
{
last_invoked_fun
=
"<float>@2"
;
}
};
auto
pf1
=
pf0
.
or_else
(
on
<
int
,
int
>
()
>>
[
&
]
{
last_invoked_fun
=
"<int, int>@3"
;
},
on
<
string
>
()
>>
[
&
]
{
last_invoked_fun
=
"<string>@4"
;
}
);
bhvr_check
(
pf0
,
make_any_tuple
(
1
,
2
),
true
,
"<int, int>@1"
);
bhvr_check
(
pf1
,
make_any_tuple
(
1
,
2
),
true
,
"<int, int>@1"
);
bhvr_check
(
pf0
,
make_any_tuple
(
"hi"
),
false
,
""
);
bhvr_check
(
pf1
,
make_any_tuple
(
"hi"
),
true
,
"<string>@4"
);
partial_function
pf11
{
on_arg_match
>>
[
&
](
int
)
{
last_invoked_fun
=
"<int>@1"
;
}
};
partial_function
pf12
{
on_arg_match
>>
[
&
](
int
)
{
last_invoked_fun
=
"<int>@2"
;
},
on_arg_match
>>
[
&
](
float
)
{
last_invoked_fun
=
"<float>@2"
;
}
};
auto
pf13
=
pf11
.
or_else
(
pf12
);
bhvr_check
(
pf13
,
make_any_tuple
(
42
),
true
,
"<int>@1"
);
bhvr_check
(
pf13
,
make_any_tuple
(
42.24
f
),
true
,
"<float>@2"
);
}
/* check result of pattern matching */
{
auto
res
=
match
(
make_any_tuple
(
42
,
4.2
f
))
(
on
(
42
,
arg_match
)
>>
[](
double
d
)
{
return
d
;
},
on
(
42
,
arg_match
)
>>
[](
float
f
)
{
return
f
;
}
);
CPPA_CHECK
(
res
&&
res
.
is
<
float
>
()
&&
get
<
float
>
(
res
)
==
4.2
f
);
auto
res2
=
match
(
make_any_tuple
(
23
,
4.2
f
))
(
on
(
42
,
arg_match
)
>>
[](
double
d
)
{
return
d
;
},
on
(
42
,
arg_match
)
>>
[](
float
f
)
{
return
f
;
}
);
CPPA_CHECK
(
!
res2
);
}
return
CPPA_TEST_RESULT
();
}
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