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
406f2f1e
Commit
406f2f1e
authored
Apr 22, 2016
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Base pattern matching on type-erased tuples
parent
fa5ad15f
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
38 additions
and
112 deletions
+38
-112
libcaf_core/caf/detail/try_match.hpp
libcaf_core/caf/detail/try_match.hpp
+6
-4
libcaf_core/caf/match_case.hpp
libcaf_core/caf/match_case.hpp
+10
-19
libcaf_core/caf/type_erased_tuple.hpp
libcaf_core/caf/type_erased_tuple.hpp
+0
-1
libcaf_core/src/behavior_impl.cpp
libcaf_core/src/behavior_impl.cpp
+1
-1
libcaf_core/src/try_match.cpp
libcaf_core/src/try_match.cpp
+17
-86
libcaf_core/src/type_erased_tuple.cpp
libcaf_core/src/type_erased_tuple.cpp
+2
-0
libcaf_core/test/message_lifetime.cpp
libcaf_core/test/message_lifetime.cpp
+2
-1
No files found.
libcaf_core/caf/detail/try_match.hpp
View file @
406f2f1e
...
@@ -38,12 +38,14 @@ struct meta_element {
...
@@ -38,12 +38,14 @@ struct meta_element {
atom_value
v
;
atom_value
v
;
uint16_t
typenr
;
uint16_t
typenr
;
const
std
::
type_info
*
type
;
const
std
::
type_info
*
type
;
bool
(
*
fun
)(
const
meta_element
&
,
const
message
&
,
size_t
,
void
**
);
bool
(
*
fun
)(
const
meta_element
&
,
const
type_erased_tuple
*
,
size_t
,
void
**
);
};
};
bool
match_element
(
const
meta_element
&
,
const
message
&
,
size_t
,
void
**
);
bool
match_element
(
const
meta_element
&
,
const
type_erased_tuple
*
,
size_t
,
void
**
);
bool
match_atom_constant
(
const
meta_element
&
,
const
message
&
,
size_t
,
void
**
);
bool
match_atom_constant
(
const
meta_element
&
,
const
type_erased_tuple
*
,
size_t
,
void
**
);
template
<
class
T
,
uint16_t
TN
=
detail
::
type_nr
<
T
>
::
value
>
template
<
class
T
,
uint16_t
TN
=
detail
::
type_nr
<
T
>
::
value
>
struct
meta_element_factory
{
struct
meta_element_factory
{
...
@@ -78,7 +80,7 @@ struct meta_elements<type_list<Ts...>> {
...
@@ -78,7 +80,7 @@ struct meta_elements<type_list<Ts...>> {
}
}
};
};
bool
try_match
(
const
message
&
msg
,
const
meta_element
*
pattern_begin
,
bool
try_match
(
const
type_erased_tuple
*
xs
,
const
meta_element
*
pattern_begin
,
size_t
pattern_size
,
void
**
out
);
size_t
pattern_size
,
void
**
out
);
}
// namespace detail
}
// namespace detail
...
...
libcaf_core/caf/match_case.hpp
View file @
406f2f1e
...
@@ -55,7 +55,7 @@ public:
...
@@ -55,7 +55,7 @@ public:
virtual
~
match_case
();
virtual
~
match_case
();
virtual
result
invoke
(
detail
::
invoke_result_visitor
&
,
message
&
)
=
0
;
virtual
result
invoke
(
detail
::
invoke_result_visitor
&
,
type_erased_tuple
*
)
=
0
;
inline
uint32_t
type_token
()
const
{
inline
uint32_t
type_token
()
const
{
return
token_
;
return
token_
;
...
@@ -65,18 +65,6 @@ private:
...
@@ -65,18 +65,6 @@ private:
uint32_t
token_
;
uint32_t
token_
;
};
};
struct
match_case_zipper
{
template
<
class
F
,
typename
T
>
auto
operator
()(
const
F
&
fun
,
T
&
arg
)
->
decltype
(
fun
(
arg
))
const
{
return
fun
(
arg
);
}
// forward everything as reference if no guard/transformation is set
template
<
class
T
>
auto
operator
()(
const
unit_t
&
,
T
&
arg
)
const
->
decltype
(
std
::
ref
(
arg
))
{
return
std
::
ref
(
arg
);
}
};
template
<
class
T
>
template
<
class
T
>
T
&&
unopt
(
T
&&
v
,
T
&&
unopt
(
T
&&
v
,
typename
std
::
enable_if
<
std
::
is_rvalue_reference
<
T
&&>::
value
>::
type
*
=
0
)
{
typename
std
::
enable_if
<
std
::
is_rvalue_reference
<
T
&&>::
value
>::
type
*
=
0
)
{
...
@@ -188,21 +176,24 @@ public:
...
@@ -188,21 +176,24 @@ public:
// nop
// nop
}
}
match_case
::
result
invoke
(
detail
::
invoke_result_visitor
&
f
,
message
&
msg
)
override
{
match_case
::
result
invoke
(
detail
::
invoke_result_visitor
&
f
,
intermediate_tuple
it
{
msg
.
shared
()};
type_erased_tuple
*
xs
)
override
{
intermediate_tuple
it
{
xs
?
xs
->
shared
()
:
false
};
detail
::
meta_elements
<
pattern
>
ms
;
detail
::
meta_elements
<
pattern
>
ms
;
message
tmp
;
// check if try_match() reports success
// check if try_match() reports success
if
(
!
detail
::
try_match
(
msg
,
ms
.
arr
.
data
(),
ms
.
arr
.
size
(),
it
.
data
))
if
(
!
detail
::
try_match
(
xs
,
ms
.
arr
.
data
(),
ms
.
arr
.
size
(),
it
.
data
))
return
match_case
::
no_match
;
return
match_case
::
no_match
;
// detach msg before invoking fun_ if needed
// detach msg before invoking fun_ if needed
if
(
is_manipulator
&&
it
.
shared_access
)
{
if
(
is_manipulator
&&
it
.
shared_access
)
{
msg
.
force_unshare
();
tmp
=
message
::
from
(
xs
);
tmp
.
force_unshare
();
it
.
shared_access
=
false
;
it
.
shared_access
=
false
;
// update pointers in our intermediate tuple
// update pointers in our intermediate tuple
for
(
size_t
i
=
0
;
i
<
msg
.
size
();
++
i
)
{
for
(
size_t
i
=
0
;
i
<
tmp
.
size
();
++
i
)
{
// msg is guaranteed to be detached, hence we don't need to
// msg is guaranteed to be detached, hence we don't need to
// check this condition over and over again via get_mutable
// check this condition over and over again via get_mutable
it
[
i
]
=
const_cast
<
void
*>
(
msg
.
at
(
i
));
it
[
i
]
=
const_cast
<
void
*>
(
tmp
.
at
(
i
));
}
}
}
}
lfinvoker
<
std
::
is_same
<
result_type
,
void
>::
value
,
F
>
fun
{
fun_
};
lfinvoker
<
std
::
is_same
<
result_type
,
void
>::
value
,
F
>
fun
{
fun_
};
...
...
libcaf_core/caf/type_erased_tuple.hpp
View file @
406f2f1e
...
@@ -108,7 +108,6 @@ public:
...
@@ -108,7 +108,6 @@ public:
}
}
};
};
/// @relates type_erased_tuple
/// @relates type_erased_tuple
template
<
class
Processor
>
template
<
class
Processor
>
typename
std
::
enable_if
<
Processor
::
is_saving
::
value
>::
type
typename
std
::
enable_if
<
Processor
::
is_saving
::
value
>::
type
...
...
libcaf_core/src/behavior_impl.cpp
View file @
406f2f1e
...
@@ -94,7 +94,7 @@ match_case::result behavior_impl::invoke(detail::invoke_result_visitor& f,
...
@@ -94,7 +94,7 @@ match_case::result behavior_impl::invoke(detail::invoke_result_visitor& f,
auto
msg_token
=
msg
.
type_token
();
auto
msg_token
=
msg
.
type_token
();
for
(
auto
i
=
begin_
;
i
!=
end_
;
++
i
)
for
(
auto
i
=
begin_
;
i
!=
end_
;
++
i
)
if
(
i
->
type_token
==
msg_token
)
if
(
i
->
type_token
==
msg_token
)
switch
(
i
->
ptr
->
invoke
(
f
,
msg
))
{
switch
(
i
->
ptr
->
invoke
(
f
,
msg
.
cvals
().
get
()
))
{
case
match_case
:
:
no_match
:
case
match_case
:
:
no_match
:
break
;
break
;
case
match_case
:
:
match
:
case
match_case
:
:
match
:
...
...
libcaf_core/src/try_match.cpp
View file @
406f2f1e
...
@@ -24,30 +24,23 @@ namespace detail {
...
@@ -24,30 +24,23 @@ namespace detail {
using
pattern_iterator
=
const
meta_element
*
;
using
pattern_iterator
=
const
meta_element
*
;
bool
is_wildcard
(
const
meta_element
&
me
)
{
bool
match_element
(
const
meta_element
&
me
,
const
type_erased_tuple
*
xs
,
return
me
.
typenr
==
0
&&
me
.
type
==
nullptr
;
}
bool
match_element
(
const
meta_element
&
me
,
const
message
&
msg
,
size_t
pos
,
void
**
storage
)
{
size_t
pos
,
void
**
storage
)
{
CAF_ASSERT
(
me
.
typenr
!=
0
||
me
.
type
!=
nullptr
);
CAF_ASSERT
(
me
.
typenr
!=
0
||
me
.
type
!=
nullptr
);
if
(
!
msg
.
match_element
(
pos
,
me
.
typenr
,
me
.
type
))
{
if
(
!
xs
->
matches
(
pos
,
me
.
typenr
,
me
.
type
))
return
false
;
return
false
;
}
*
storage
=
const_cast
<
void
*>
(
xs
->
get
(
pos
));
*
storage
=
const_cast
<
void
*>
(
msg
.
at
(
pos
));
return
true
;
return
true
;
}
}
bool
match_atom_constant
(
const
meta_element
&
me
,
const
message
&
msg
,
bool
match_atom_constant
(
const
meta_element
&
me
,
const
type_erased_tuple
*
xs
,
size_t
pos
,
void
**
storage
)
{
size_t
pos
,
void
**
storage
)
{
CAF_ASSERT
(
me
.
typenr
==
detail
::
type_nr
<
atom_value
>::
value
);
CAF_ASSERT
(
me
.
typenr
==
detail
::
type_nr
<
atom_value
>::
value
);
if
(
!
msg
.
match_element
(
pos
,
detail
::
type_nr
<
atom_value
>::
value
,
nullptr
))
{
if
(
!
xs
->
matches
(
pos
,
detail
::
type_nr
<
atom_value
>::
value
,
nullptr
))
return
false
;
return
false
;
}
auto
ptr
=
xs
->
get
(
pos
);
auto
ptr
=
msg
.
at
(
pos
);
if
(
me
.
v
!=
*
reinterpret_cast
<
const
atom_value
*>
(
ptr
))
if
(
me
.
v
!=
*
reinterpret_cast
<
const
atom_value
*>
(
ptr
))
{
return
false
;
return
false
;
}
// This assignment casts `atom_value` to `atom_constant<V>*`.
// This assignment casts `atom_value` to `atom_constant<V>*`.
// This type violation could theoretically cause undefined behavior.
// This type violation could theoretically cause undefined behavior.
// However, `uti` does have an address that is guaranteed to be valid
// However, `uti` does have an address that is guaranteed to be valid
...
@@ -58,81 +51,19 @@ bool match_atom_constant(const meta_element& me, const message& msg,
...
@@ -58,81 +51,19 @@ bool match_atom_constant(const meta_element& me, const message& msg,
return
true
;
return
true
;
}
}
class
set_commit_rollback
{
bool
try_match
(
const
type_erased_tuple
*
xs
,
public:
pattern_iterator
iter
,
size_t
ps
,
void
**
out
)
{
using
pointer
=
void
**
;
CAF_ASSERT
(
out
!=
nullptr
);
set_commit_rollback
(
const
set_commit_rollback
&
)
=
delete
;
if
(
!
xs
)
set_commit_rollback
&
operator
=
(
const
set_commit_rollback
&
)
=
delete
;
return
ps
==
0
;
explicit
set_commit_rollback
(
pointer
ptr
)
if
(
xs
->
size
()
!=
ps
)
:
data_
(
ptr
),
return
false
;
pos_
(
0
),
for
(
size_t
i
=
0
;
i
<
ps
;
++
i
,
++
iter
,
++
out
)
fallback_pos_
(
0
)
{
// nop
}
inline
void
inc
()
{
++
pos_
;
}
inline
pointer
current
()
const
{
return
&
data_
[
pos_
];
}
inline
void
commit
()
{
fallback_pos_
=
pos_
;
}
inline
void
rollback
()
{
pos_
=
fallback_pos_
;
}
private:
pointer
data_
;
size_t
pos_
;
size_t
fallback_pos_
;
};
bool
try_match
(
const
message
&
msg
,
size_t
msg_pos
,
size_t
msg_size
,
pattern_iterator
pbegin
,
pattern_iterator
pend
,
set_commit_rollback
&
storage
)
{
while
(
msg_pos
<
msg_size
)
{
if
(
pbegin
==
pend
)
{
return
false
;
}
if
(
is_wildcard
(
*
pbegin
))
{
// perform submatching
++
pbegin
;
// always true at the end of the pattern
if
(
pbegin
==
pend
)
{
return
true
;
}
// safe current mapping as fallback
storage
.
commit
();
// iterate over remaining values until we found a match
for
(;
msg_pos
<
msg_size
;
++
msg_pos
)
{
if
(
try_match
(
msg
,
msg_pos
,
msg_size
,
pbegin
,
pend
,
storage
))
{
return
true
;
}
// restore mapping to fallback (delete invalid mappings)
storage
.
rollback
();
}
return
false
;
// no submatch found
}
// inspect current element
// inspect current element
if
(
!
pbegin
->
fun
(
*
pbegin
,
msg
,
msg_pos
,
storage
.
current
()))
{
if
(
!
iter
->
fun
(
*
iter
,
xs
,
i
,
out
))
// type mismatch
// type mismatch
return
false
;
return
false
;
}
return
true
;
// next iteration
storage
.
inc
();
++
msg_pos
;
++
pbegin
;
}
// we found a match if we've inspected each element and consumed
// the whole pattern (or the remainder consists of wildcards only)
return
std
::
all_of
(
pbegin
,
pend
,
is_wildcard
);
}
bool
try_match
(
const
message
&
msg
,
pattern_iterator
pb
,
size_t
ps
,
void
**
out
)
{
CAF_ASSERT
(
out
!=
nullptr
);
CAF_ASSERT
(
msg
.
empty
()
||
msg
.
vals
()
->
get_reference_count
()
>
0
);
set_commit_rollback
scr
{
out
};
return
try_match
(
msg
,
0
,
msg
.
size
(),
pb
,
pb
+
ps
,
scr
);
}
}
}
// namespace detail
}
// namespace detail
...
...
libcaf_core/src/type_erased_tuple.cpp
View file @
406f2f1e
...
@@ -21,6 +21,8 @@
...
@@ -21,6 +21,8 @@
#include "caf/config.hpp"
#include "caf/config.hpp"
#include "caf/detail/dynamic_message_data.hpp"
namespace
caf
{
namespace
caf
{
type_erased_tuple
::~
type_erased_tuple
()
{
type_erased_tuple
::~
type_erased_tuple
()
{
...
...
libcaf_core/test/message_lifetime.cpp
View file @
406f2f1e
...
@@ -115,7 +115,8 @@ CAF_TEST(message_lifetime_in_scoped_actor) {
...
@@ -115,7 +115,8 @@ CAF_TEST(message_lifetime_in_scoped_actor) {
self
->
send
(
self
,
msg
);
self
->
send
(
self
,
msg
);
self
->
receive
(
self
->
receive
(
[
&
](
int
&
value
)
{
[
&
](
int
&
value
)
{
CAF_CHECK_EQUAL
(
msg
.
cvals
()
->
get_reference_count
(),
1u
);
CAF_CHECK_EQUAL
(
msg
.
cvals
()
->
get_reference_count
(),
2u
);
CAF_CHECK_NOT_EQUAL
(
&
value
,
msg
.
at
(
0
));
value
=
10
;
value
=
10
;
}
}
);
);
...
...
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