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
50543c98
Commit
50543c98
authored
May 17, 2011
by
neverlord
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
exit_signal and serialization of group_ptr + channel_ptr
parent
904adf60
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
881 additions
and
166 deletions
+881
-166
cppa.files
cppa.files
+3
-0
cppa/channel.hpp
cppa/channel.hpp
+10
-1
cppa/detail/converted_thread_context.hpp
cppa/detail/converted_thread_context.hpp
+5
-3
cppa/detail/default_uniform_type_info_impl.hpp
cppa/detail/default_uniform_type_info_impl.hpp
+41
-3
cppa/exit_signal.hpp
cppa/exit_signal.hpp
+91
-0
cppa/group.hpp
cppa/group.hpp
+16
-0
cppa/intrusive_ptr.hpp
cppa/intrusive_ptr.hpp
+9
-2
cppa/message_queue.hpp
cppa/message_queue.hpp
+8
-8
cppa/uniform_type_info.hpp
cppa/uniform_type_info.hpp
+4
-6
cppa/util/shared_lock_guard.hpp
cppa/util/shared_lock_guard.hpp
+15
-4
cppa/util/shared_spinlock.hpp
cppa/util/shared_spinlock.hpp
+6
-0
cppa/util/upgrade_lock_guard.hpp
cppa/util/upgrade_lock_guard.hpp
+38
-0
libcppa.Makefile
libcppa.Makefile
+3
-0
src/converted_thread_context.cpp
src/converted_thread_context.cpp
+27
-6
src/exit_signal.cpp
src/exit_signal.cpp
+32
-0
src/group.cpp
src/group.cpp
+150
-9
src/shared_spinlock.cpp
src/shared_spinlock.cpp
+22
-0
src/uniform_type_info.cpp
src/uniform_type_info.cpp
+209
-9
unit_testing/test__local_group.cpp
unit_testing/test__local_group.cpp
+1
-86
unit_testing/test__serialization.cpp
unit_testing/test__serialization.cpp
+187
-28
unit_testing/test__uniform_type.cpp
unit_testing/test__uniform_type.cpp
+4
-1
No files found.
cppa.files
View file @
50543c98
...
...
@@ -148,3 +148,6 @@ src/object_array.cpp
cppa/any_tuple.hpp
src/any_tuple.cpp
cppa/util/abstract_uniform_type_info.hpp
cppa/util/upgrade_lock_guard.hpp
cppa/exit_signal.hpp
src/exit_signal.cpp
cppa/channel.hpp
View file @
50543c98
...
...
@@ -6,12 +6,21 @@
namespace
cppa
{
// forward declaration
// forward declarations
class
actor
;
class
group
;
class
message
;
class
channel
:
public
ref_counted
{
friend
class
actor
;
friend
class
group
;
// channel is a sealed class and the only
// allowed subclasses are actor and group.
channel
()
=
default
;
public:
virtual
~
channel
();
...
...
cppa/detail/converted_thread_context.hpp
View file @
50543c98
...
...
@@ -15,15 +15,15 @@ namespace cppa { namespace detail {
class
converted_thread_context
:
public
context
{
// true if the associated thread has finished execution
bool
m_exited
;
// mailbox implementation
detail
::
blocking_message_queue
m_mailbox
;
// guards access to m_exited, m_subscriptions and m_links
std
::
mutex
m_mtx
;
// true if the associated thread has finished execution
bool
m_exited
;
// manages group subscriptions
std
::
map
<
group_ptr
,
group
::
subscription
>
m_subscriptions
;
...
...
@@ -32,6 +32,8 @@ class converted_thread_context : public context
public:
converted_thread_context
();
message_queue
&
mailbox
/*[[override]]*/
();
void
join
/*[[override]]*/
(
group_ptr
&
what
);
...
...
cppa/detail/default_uniform_type_info_impl.hpp
View file @
50543c98
...
...
@@ -2,8 +2,10 @@
#define DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP
#include "cppa/any_type.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/util/conjunction.hpp"
#include "cppa/util/disjunction.hpp"
#include "cppa/util/is_iterable.hpp"
#include "cppa/util/is_primitive.hpp"
...
...
@@ -98,11 +100,11 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
std
::
function
<
void
(
const
uniform_type_info
*
,
const
void
*
,
serializer
*
)
>
m_serialize
;
serializer
*
)
>
m_serialize
;
std
::
function
<
void
(
const
uniform_type_info
*
,
void
*
,
deserializer
*
)
>
m_deserialize
;
deserializer
*
)
>
m_deserialize
;
member
(
const
member
&
)
=
delete
;
member
&
operator
=
(
const
member
&
)
=
delete
;
...
...
@@ -141,6 +143,32 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
};
}
template
<
typename
GRes
,
typename
SRes
,
typename
SArg
,
class
C
>
member
(
uniform_type_info
*
mtptr
,
GRes
(
C
::*
getter
)()
const
,
SRes
(
C
::*
setter
)(
SArg
))
:
m_meta
(
mtptr
)
{
typedef
typename
util
::
rm_ref
<
GRes
>::
type
getter_result
;
typedef
typename
util
::
rm_ref
<
SArg
>::
type
setter_arg
;
static_assert
(
std
::
is_same
<
getter_result
,
setter_arg
>::
value
,
"getter result doesn't match setter argument"
);
m_serialize
=
[
getter
]
(
const
uniform_type_info
*
mt
,
const
void
*
obj
,
serializer
*
s
)
{
GRes
v
=
(
*
reinterpret_cast
<
const
C
*>
(
obj
).
*
getter
)();
mt
->
serialize
(
&
v
,
s
);
};
m_deserialize
=
[
setter
]
(
const
uniform_type_info
*
mt
,
void
*
obj
,
deserializer
*
d
)
{
setter_arg
value
;
mt
->
deserialize
(
&
value
,
d
);
(
*
reinterpret_cast
<
C
*>
(
obj
).
*
setter
)(
value
);
};
}
member
(
member
&&
other
)
:
m_meta
(
nullptr
)
{
swap
(
other
);
...
...
@@ -201,6 +229,16 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
push_back
(
args
...);
}
// pr.first = getter member function pointer
// pr.second = setter member function pointer
template
<
typename
GRes
,
typename
SRes
,
typename
SArg
,
class
C
>
typename
util
::
enable_if
<
util
::
is_primitive
<
typename
util
::
rm_ref
<
GRes
>::
type
>
>::
type
push_back
(
std
::
pair
<
GRes
(
C
::*
)()
const
,
SRes
(
C
::*
)(
SArg
)
>
pr
)
{
typedef
typename
util
::
rm_ref
<
GRes
>::
type
memtype
;
m_members
.
push_back
({
new
primitive_member
<
memtype
>
(),
pr
.
first
,
pr
.
second
});
}
template
<
typename
R
,
class
C
,
typename
...
Args
>
typename
util
::
enable_if
<
util
::
is_primitive
<
R
>
>::
type
push_back
(
R
C
::*
mem_ptr
,
const
Args
&
...
args
)
...
...
cppa/exit_signal.hpp
0 → 100644
View file @
50543c98
#ifndef EXIT_SIGNAL_HPP
#define EXIT_SIGNAL_HPP
#include <cstdint>
namespace
cppa
{
enum
class
exit_reason
:
std
::
uint32_t
{
/**
* @brief Indicates that an actor finished execution.
*/
normal
=
0x00
,
/**
* @brief Indicates that an actor finished execution
* because of an unhandled exception.
*/
unhandled_exception
=
0x01
,
/**
* @brief Any user defined exit reason should have a
* value greater or equal to prevent collisions
* with default defined exit reasons.
*/
user_defined
=
0x10000
};
/**
* @brief Converts {@link exit_reason} to @c std::uint32_t.
*/
constexpr
std
::
uint32_t
to_uint
(
exit_reason
r
)
{
return
static_cast
<
std
::
uint32_t
>
(
r
);
}
class
exit_signal
{
std
::
uint32_t
m_reason
;
public:
/**
* @brief Creates an exit signal with
* <tt>reason() == exit_reason::normal</tt>.
*/
exit_signal
();
/**
* @brief Creates an exit signal with
* <tt>reason() == @p r</tt>.
* @pre {@code r != exit_reason::user_defined}.
*/
exit_signal
(
exit_reason
r
);
/**
* @brief Creates an exit signal with
* <tt>reason() == @p r</tt>.
* @pre {@code r >= exit_reason::user_defined}.
*/
exit_signal
(
std
::
uint32_t
r
);
/**
* @brief Reads the exit reason.
*/
inline
std
::
uint32_t
reason
()
const
{
return
m_reason
;
}
// an unambiguous member function
void
set_uint_reason
(
std
::
uint32_t
value
);
/**
* @brief Sets the exit reason to @p value.
*/
void
set_reason
(
std
::
uint32_t
value
);
/**
* @brief Sets the exit reason to @p value.
*/
void
set_reason
(
exit_reason
value
);
};
}
// namespace cppa
#endif // EXIT_SIGNAL_HPP
cppa/group.hpp
View file @
50543c98
...
...
@@ -11,8 +11,15 @@ namespace cppa {
class
group
:
public
channel
{
std
::
string
m_identifier
;
std
::
string
m_module_name
;
protected:
group
(
std
::
string
&&
id
,
std
::
string
&&
mod_name
);
group
(
const
std
::
string
&
id
,
const
std
::
string
&
mod_name
);
virtual
void
unsubscribe
(
const
channel_ptr
&
who
)
=
0
;
public:
...
...
@@ -33,6 +40,11 @@ class group : public channel
public:
inline
explicit
operator
bool
()
{
return
m_self
!=
nullptr
&&
m_group
!=
nullptr
;
}
subscription
(
const
channel_ptr
&
s
,
const
intrusive_ptr
<
group
>&
g
);
subscription
(
subscription
&&
other
);
~
subscription
();
...
...
@@ -49,6 +61,10 @@ class group : public channel
};
const
std
::
string
&
identifier
()
const
;
const
std
::
string
&
module_name
()
const
;
virtual
subscription
subscribe
(
const
channel_ptr
&
who
)
=
0
;
static
intrusive_ptr
<
group
>
get
(
const
std
::
string
&
module_name
,
...
...
cppa/intrusive_ptr.hpp
View file @
50543c98
...
...
@@ -65,6 +65,13 @@ class intrusive_ptr : util::comparable<intrusive_ptr<T>, T*>,
const
T
*
get
()
const
{
return
m_ptr
;
}
T
*
take
()
{
auto
result
=
m_ptr
;
m_ptr
=
nullptr
;
return
result
;
}
void
swap
(
intrusive_ptr
&
other
)
{
std
::
swap
(
m_ptr
,
other
.
m_ptr
);
...
...
@@ -111,8 +118,8 @@ class intrusive_ptr : util::comparable<intrusive_ptr<T>, T*>,
{
static_assert
(
std
::
is_convertible
<
Y
*
,
T
*>::
value
,
"Y* is not assignable to T*"
);
m_ptr
=
other
.
m_ptr
;
other
.
m_ptr
=
nullptr
;
reset
()
;
m_ptr
=
other
.
take
()
;
return
*
this
;
}
...
...
cppa/message_queue.hpp
View file @
50543c98
#ifndef MESSAGE_QUEUE_HPP
#define MESSAGE_QUEUE_HPP
#include "cppa/
channel
.hpp"
#include "cppa/
ref_counted
.hpp"
namespace
cppa
{
// forward declaration
class
invoke_rules
;
class
message_queue
:
public
channel
class
message_queue
:
public
ref_counted
{
public:
virtual
void
enqueue
(
const
message
&
)
=
0
;
virtual
const
message
&
dequeue
()
=
0
;
virtual
void
dequeue
(
invoke_rules
&
)
=
0
;
virtual
bool
try_dequeue
(
message
&
)
=
0
;
virtual
bool
try_dequeue
(
invoke_rules
&
)
=
0
;
virtual
const
message
&
last_dequeued
()
=
0
;
virtual
void
enqueue
(
const
message
&
)
=
0
;
virtual
const
message
&
dequeue
()
=
0
;
virtual
void
dequeue
(
invoke_rules
&
)
=
0
;
virtual
bool
try_dequeue
(
message
&
)
=
0
;
virtual
bool
try_dequeue
(
invoke_rules
&
)
=
0
;
virtual
const
message
&
last_dequeued
()
=
0
;
};
...
...
cppa/uniform_type_info.hpp
View file @
50543c98
...
...
@@ -29,18 +29,16 @@ const uniform_type_info* uniform_typeid(const std::type_info&);
* @brief Provides a platform independent type name and a (very primitive)
* kind of reflection in combination with {@link cppa::object object}.
*
* The platform dependent type name (from GCC or Microsofts VC++ Compiler) is
* translated to a (usually) shorter and platform independent name.
*
* This name is equal to the "in-sourcecode-name" but with a few exceptions:
* The platform independent name is equal to the "in-sourcecode-name"
* with a few exceptions:
* - @c std::string is named @c \@str
* - @c std::u16string is named @c \@u16str
* - @c std::u32string is named @c \@u32str
* - @c integers are named <tt>\@(i|u)$size</tt>\n
* e.g.: @c \@i32 is a 32 bit signed integer; @c \@u16
* is a 16 bit unsigned integer
* - the <em>anonymous namespace</em> is named @c \@_\n
* e.g.:
@code namespace { class foo { }; } @endcode
is mapped to
* - the <em>anonymous namespace</em> is named @c \@_
\n
* e.g.:
<tt>namespace { class foo { }; }</tt>
is mapped to
* @c \@_::foo
* - {@link cppa::util::void_type} is named @c \@0
*/
...
...
cppa/util/shared_lock_guard.hpp
View file @
50543c98
...
...
@@ -7,20 +7,31 @@ template<typename SharedLockable>
class
shared_lock_guard
{
SharedLockable
&
m_lockable
;
SharedLockable
*
m_lockable
;
public:
shared_lock_guard
(
SharedLockable
&
lockable
)
:
m_lockable
(
lockable
)
explicit
shared_lock_guard
(
SharedLockable
&
lockable
)
:
m_lockable
(
&
lockable
)
{
m_lockable
.
lock_shared
();
m_lockable
->
lock_shared
();
}
~
shared_lock_guard
()
{
m_lockable
.
unlock_shared
();
if
(
m_lockable
)
m_lockable
->
unlock_shared
();
}
bool
owns_lock
()
const
{
return
m_lockable
!=
nullptr
;
}
SharedLockable
*
release
()
{
auto
result
=
m_lockable
;
m_lockable
=
nullptr
;
return
result
;
}
};
}
}
// namespace cppa::util
...
...
cppa/util/shared_spinlock.hpp
View file @
50543c98
...
...
@@ -23,6 +23,12 @@ class shared_spinlock
void
unlock_shared
();
bool
try_lock_shared
();
/**
* @brief Upgrades a shared lock to an exclusive lock (must be released
* through a call to {@link lock()} afterwards).
*/
void
lock_upgrade
();
};
}
}
// namespace cppa::util
...
...
cppa/util/upgrade_lock_guard.hpp
0 → 100644
View file @
50543c98
#ifndef UPGRADE_LOCK_GUARD_HPP
#define UPGRADE_LOCK_GUARD_HPP
namespace
cppa
{
namespace
util
{
/**
* @brief Upgrades shared ownership to exclusive ownership.
*/
template
<
typename
UpgradeLockable
>
class
upgrade_lock_guard
{
UpgradeLockable
*
m_lockable
;
public:
template
<
template
<
typename
>
class
LockType
>
upgrade_lock_guard
(
LockType
<
UpgradeLockable
>&
other
)
{
m_lockable
=
other
.
release
();
if
(
m_lockable
)
m_lockable
->
lock_upgrade
();
}
~
upgrade_lock_guard
()
{
if
(
m_lockable
)
m_lockable
->
unlock
();
}
bool
owns_lock
()
const
{
return
m_lockable
!=
nullptr
;
}
};
}
}
// namespace cppa::util
#endif // UPGRADE_LOCK_GUARD_HPP
libcppa.Makefile
View file @
50543c98
...
...
@@ -15,6 +15,7 @@ HEADERS = \
cppa/cow_ptr.hpp \
cppa/cppa.hpp \
cppa/deserializer.hpp \
cppa/exit_signal.hpp \
cppa/get.hpp \
cppa/get_view.hpp \
cppa/group.hpp \
...
...
@@ -102,6 +103,7 @@ HEADERS = \
cppa/util/type_list.hpp \
cppa/util/type_list_apply.hpp \
cppa/util/type_list_pop_back.hpp \
cppa/util/upgrade_lock_guard.hpp \
cppa/util/void_type.hpp \
cppa/util/wrapped_type.hpp
...
...
@@ -118,6 +120,7 @@ SOURCES = \
src/converted_thread_context.cpp \
src/demangle.cpp \
src/deserializer.cpp \
src/exit_signal.cpp \
src/group.cpp \
src/message.cpp \
src/mock_scheduler.cpp \
...
...
src/converted_thread_context.cpp
View file @
50543c98
...
...
@@ -2,6 +2,10 @@
namespace
cppa
{
namespace
detail
{
converted_thread_context
::
converted_thread_context
()
:
m_exited
(
false
)
{
}
void
converted_thread_context
::
link
(
intrusive_ptr
<
actor
>&
other
)
{
std
::
lock_guard
<
std
::
mutex
>
guard
(
m_mtx
);
...
...
@@ -21,15 +25,30 @@ bool converted_thread_context::remove_backlink(const intrusive_ptr<actor>& other
return
false
;
}
bool
converted_thread_context
::
establish_backlink
(
const
intrusive_ptr
<
actor
>&
other
)
{
bool
send_exit_message
=
false
;
bool
result
=
false
;
if
(
other
&&
other
!=
this
)
{
std
::
lock_guard
<
std
::
mutex
>
guard
(
m_mtx
);
return
m_links
.
insert
(
other
).
second
;
// lifetime scope of guard
{
std
::
lock_guard
<
std
::
mutex
>
guard
(
m_mtx
);
if
(
!
m_exited
)
{
result
=
m_links
.
insert
(
other
).
second
;
}
else
{
send_exit_message
=
true
;
}
}
}
return
false
;
if
(
send_exit_message
)
{
}
return
result
;
}
void
converted_thread_context
::
unlink
(
intrusive_ptr
<
actor
>&
other
)
...
...
@@ -46,8 +65,10 @@ void converted_thread_context::join(group_ptr& what)
std
::
lock_guard
<
std
::
mutex
>
guard
(
m_mtx
);
if
(
!
m_exited
&&
m_subscriptions
.
count
(
what
)
==
0
)
{
m_subscriptions
.
insert
(
std
::
make_pair
(
what
,
what
->
subscribe
(
this
)));
//m_subscriptions[what] = what->subscribe(this);
auto
s
=
what
->
subscribe
(
this
);
// insert only valid subscriptions
// (a subscription is invalid if this actor already joined the group)
if
(
s
)
m_subscriptions
.
insert
(
std
::
make_pair
(
what
,
std
::
move
(
s
)));
}
}
...
...
src/exit_signal.cpp
0 → 100644
View file @
50543c98
#include "cppa/exit_signal.hpp"
namespace
cppa
{
exit_signal
::
exit_signal
()
:
m_reason
(
to_uint
(
exit_reason
::
normal
))
{
}
exit_signal
::
exit_signal
(
exit_reason
r
)
:
m_reason
(
to_uint
(
r
))
{
}
exit_signal
::
exit_signal
(
std
::
uint32_t
r
)
:
m_reason
(
r
)
{
}
void
exit_signal
::
set_reason
(
std
::
uint32_t
value
)
{
m_reason
=
value
;
}
void
exit_signal
::
set_reason
(
exit_reason
value
)
{
m_reason
=
to_uint
(
value
);
}
void
exit_signal
::
set_uint_reason
(
std
::
uint32_t
value
)
{
set_reason
(
value
);
}
}
// namespace cppa
src/group.cpp
View file @
50543c98
#include "cppa/config.hpp"
#include <map>
#include <set>
#include <list>
#include <mutex>
#include <memory>
#include <stdexcept>
#include "cppa/group.hpp"
#include "cppa/util/shared_spinlock.hpp"
#include "cppa/util/shared_lock_guard.hpp"
#include "cppa/util/upgrade_lock_guard.hpp"
namespace
cppa
{
...
...
@@ -13,19 +18,133 @@ namespace {
typedef
std
::
map
<
std
::
string
,
std
::
unique_ptr
<
group
::
module
>
>
modules_map
;
typedef
std
::
lock_guard
<
util
::
shared_spinlock
>
exclusive_guard
;
typedef
util
::
shared_lock_guard
<
util
::
shared_spinlock
>
shared_guard
;
typedef
util
::
upgrade_lock_guard
<
util
::
shared_spinlock
>
upgrade_guard
;
std
::
mutex
s_mtx
;
modules_map
s_mmap
;
class
local_group
:
public
group
{
friend
class
local_group_module
;
util
::
shared_spinlock
m_mtx
;
std
::
set
<
channel_ptr
>
m_subscribers
;
// allow access to local_group_module only
local_group
(
std
::
string
&&
gname
)
:
group
(
std
::
move
(
gname
),
"local"
)
{
}
public:
virtual
void
enqueue
(
const
message
&
msg
)
{
shared_guard
guard
(
m_mtx
);
for
(
auto
i
=
m_subscribers
.
begin
();
i
!=
m_subscribers
.
end
();
++
i
)
{
const_cast
<
channel_ptr
&>
(
*
i
)
->
enqueue
(
msg
);
}
}
virtual
group
::
subscription
subscribe
(
const
channel_ptr
&
who
)
{
exclusive_guard
guard
(
m_mtx
);
if
(
m_subscribers
.
insert
(
who
).
second
)
{
return
{
who
,
this
};
}
else
{
return
{
nullptr
,
nullptr
};
}
}
virtual
void
unsubscribe
(
const
channel_ptr
&
who
)
{
exclusive_guard
guard
(
m_mtx
);
m_subscribers
.
erase
(
who
);
}
};
class
local_group_module
:
public
group
::
module
{
std
::
string
m_name
;
util
::
shared_spinlock
m_mtx
;
std
::
map
<
std
::
string
,
group_ptr
>
m_instances
;
public:
local_group_module
()
:
m_name
(
"local"
)
{
}
const
std
::
string
&
name
()
{
return
m_name
;
}
group_ptr
get
(
const
std
::
string
&
group_name
)
{
shared_guard
guard
(
m_mtx
);
auto
i
=
m_instances
.
find
(
group_name
);
if
(
i
!=
m_instances
.
end
())
{
return
i
->
second
;
}
else
{
group_ptr
tmp
(
new
local_group
(
std
::
string
(
group_name
)));
// lifetime scope of uguard
{
upgrade_guard
uguard
(
guard
);
auto
p
=
m_instances
.
insert
(
std
::
make_pair
(
group_name
,
tmp
));
if
(
p
.
second
==
false
)
{
// someone preempt us
return
p
.
first
->
second
;
}
else
{
// ok, inserted tmp
return
tmp
;
}
}
}
}
};
modules_map
&
mmap
()
{
if
(
s_mmap
.
empty
())
{
// lazy initialization
s_mmap
.
insert
(
std
::
make_pair
(
std
::
string
(
"local"
),
new
local_group_module
));
}
return
s_mmap
;
}
}
// namespace <anonymous>
intrusive_ptr
<
group
>
group
::
get
(
const
std
::
string
&
module_name
,
const
std
::
string
&
group_name
)
{
std
::
lock_guard
<
std
::
mutex
>
guard
(
s_mtx
);
auto
i
=
s_mmap
.
find
(
module_name
);
if
(
i
!=
s_mmap
.
end
())
// lifetime scope of guard
{
return
(
i
->
second
)
->
get
(
group_name
);
std
::
lock_guard
<
std
::
mutex
>
guard
(
s_mtx
);
auto
&
mmref
=
mmap
();
auto
i
=
mmref
.
find
(
module_name
);
if
(
i
!=
mmref
.
end
())
{
return
(
i
->
second
)
->
get
(
group_name
);
}
}
std
::
string
error_msg
=
"no module named
\"
"
;
error_msg
+=
module_name
;
...
...
@@ -40,14 +159,16 @@ void group::add_module(group::module* ptr)
// lifetime scope of guard
{
std
::
lock_guard
<
std
::
mutex
>
guard
(
s_mtx
);
if
(
!
s_mmap
.
insert
(
std
::
make_pair
(
mname
,
std
::
move
(
mptr
))).
second
)
if
(
mmap
()
.
insert
(
std
::
make_pair
(
mname
,
std
::
move
(
mptr
))).
second
)
{
std
::
string
error_msg
=
"module name
\"
"
;
error_msg
+=
mname
;
error_msg
+=
"
\"
already defined"
;
throw
std
::
logic_error
(
error_msg
);
return
;
// success; don't throw exception
}
}
std
::
string
error_msg
=
"module name
\"
"
;
error_msg
+=
mname
;
error_msg
+=
"
\"
already defined"
;
throw
std
::
logic_error
(
error_msg
);
}
group
::
subscription
::
subscription
(
const
channel_ptr
&
s
,
...
...
@@ -66,4 +187,24 @@ group::subscription::~subscription()
if
(
m_group
)
m_group
->
unsubscribe
(
m_self
);
}
group
::
group
(
std
::
string
&&
id
,
std
::
string
&&
mod_name
)
:
m_identifier
(
std
::
move
(
id
)),
m_module_name
(
std
::
move
(
mod_name
))
{
}
group
::
group
(
const
std
::
string
&
id
,
const
std
::
string
&
mod_name
)
:
m_identifier
(
id
),
m_module_name
(
mod_name
)
{
}
const
std
::
string
&
group
::
identifier
()
const
{
return
m_identifier
;
}
const
std
::
string
&
group
::
module_name
()
const
{
return
m_module_name
;
}
}
// namespace cppa
src/shared_spinlock.cpp
View file @
50543c98
...
...
@@ -35,6 +35,28 @@ void shared_spinlock::lock()
}
}
void
shared_spinlock
::
lock_upgrade
()
{
unlock_shared
();
lock
();
/*
long v = m_flag.load();
for (;;)
{
if (v != 1)
{
//std::this_thread::yield();
v = m_flag.load();
}
else if (m_flag.compare_exchange_weak(v, min_long))
{
return;
}
// else: next iteration
}
*/
}
void
shared_spinlock
::
unlock
()
{
m_flag
.
store
(
0
);
...
...
src/uniform_type_info.cpp
View file @
50543c98
...
...
@@ -15,6 +15,7 @@
#include "cppa/announce.hpp"
#include "cppa/any_type.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/exit_signal.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/uniform_type_info.hpp"
...
...
@@ -96,20 +97,184 @@ void push(std::map<int, std::pair<string_set, string_set>>& ints)
namespace
cppa
{
namespace
detail
{
namespace
{
class
actor_ptr_type_info
:
public
util
::
abstract_uniform_type_info
<
actor_ptr
>
const
std
::
string
nullptr_type_name
=
"@0"
;
void
serialize_nullptr
(
serializer
*
sink
)
{
sink
->
begin_object
(
nullptr_type_name
);
sink
->
end_object
();
}
void
deserialize_nullptr
(
deserializer
*
source
)
{
source
->
begin_object
(
nullptr_type_name
);
source
->
end_object
();
}
class
actor_ptr_tinfo
:
public
util
::
abstract_uniform_type_info
<
actor_ptr
>
{
public:
static
void
s_serialize
(
const
actor
*
ptr
,
serializer
*
sink
,
const
std
::
string
name
)
{
if
(
!
ptr
)
{
serialize_nullptr
(
sink
);
}
else
{
sink
->
begin_object
(
name
);
sink
->
write_value
(
ptr
->
id
());
sink
->
end_object
();
}
}
static
void
s_deserialize
(
actor_ptr
&
ptrref
,
deserializer
*
source
,
const
std
::
string
name
)
{
std
::
string
cname
=
source
->
seek_object
();
if
(
cname
!=
name
)
{
if
(
cname
==
nullptr_type_name
)
{
deserialize_nullptr
(
source
);
ptrref
.
reset
();
}
else
{
throw
std
::
logic_error
(
"wrong type name found"
);
}
}
else
{
source
->
begin_object
(
cname
);
auto
id
=
get
<
std
::
uint32_t
>
(
source
->
read_value
(
pt_uint32
));
ptrref
=
actor
::
by_id
(
id
);
source
->
end_object
();
}
}
protected:
void
serialize
(
const
void
*
ptr
,
serializer
*
sink
)
const
{
s_serialize
(
reinterpret_cast
<
const
actor_ptr
*>
(
ptr
)
->
get
(),
sink
,
name
());
}
void
deserialize
(
void
*
ptr
,
deserializer
*
source
)
const
{
s_deserialize
(
*
reinterpret_cast
<
actor_ptr
*>
(
ptr
),
source
,
name
());
}
};
class
group_ptr_tinfo
:
public
util
::
abstract_uniform_type_info
<
group_ptr
>
{
public:
static
void
s_serialize
(
const
group
*
ptr
,
serializer
*
sink
,
const
std
::
string
name
)
{
if
(
!
ptr
)
{
serialize_nullptr
(
sink
);
}
else
{
sink
->
begin_object
(
name
);
sink
->
write_value
(
ptr
->
module_name
());
sink
->
write_value
(
ptr
->
identifier
());
sink
->
end_object
();
}
}
static
void
s_deserialize
(
group_ptr
&
ptrref
,
deserializer
*
source
,
const
std
::
string
name
)
{
std
::
string
cname
=
source
->
seek_object
();
if
(
cname
!=
name
)
{
if
(
cname
==
nullptr_type_name
)
{
deserialize_nullptr
(
source
);
ptrref
.
reset
();
}
else
{
throw
std
::
logic_error
(
"wrong type name found"
);
}
}
else
{
source
->
begin_object
(
name
);
auto
modname
=
source
->
read_value
(
pt_u8string
);
auto
groupid
=
source
->
read_value
(
pt_u8string
);
ptrref
=
group
::
get
(
get
<
std
::
string
>
(
modname
),
get
<
std
::
string
>
(
groupid
));
source
->
end_object
();
}
}
protected:
void
serialize
(
const
void
*
ptr
,
serializer
*
sink
)
const
{
s_serialize
(
reinterpret_cast
<
const
group_ptr
*>
(
ptr
)
->
get
(),
sink
,
name
());
}
void
deserialize
(
void
*
ptr
,
deserializer
*
source
)
const
{
s_deserialize
(
*
reinterpret_cast
<
group_ptr
*>
(
ptr
),
source
,
name
());
}
};
class
channel_ptr_tinfo
:
public
util
::
abstract_uniform_type_info
<
channel_ptr
>
{
std
::
string
group_ptr_name
;
std
::
string
actor_ptr_name
;
protected:
void
serialize
(
const
void
*
instance
,
serializer
*
sink
)
const
{
sink
->
begin_object
(
name
());
auto
id
=
(
*
reinterpret_cast
<
const
actor_ptr
*>
(
ptr
))
->
id
();
sink
->
write_value
(
id
);
auto
ptr
=
reinterpret_cast
<
const
channel_ptr
*>
(
instance
)
->
get
();
if
(
!
ptr
)
{
serialize_nullptr
(
sink
);
}
else
{
const
group
*
gptr
;
auto
aptr
=
dynamic_cast
<
const
actor
*>
(
ptr
);
if
(
aptr
)
{
actor_ptr_tinfo
::
s_serialize
(
aptr
,
sink
,
actor_ptr_name
);
}
else
if
((
gptr
=
dynamic_cast
<
const
group
*>
(
ptr
))
!=
nullptr
)
{
group_ptr_tinfo
::
s_serialize
(
gptr
,
sink
,
group_ptr_name
);
}
else
{
throw
std
::
logic_error
(
"channel is neither "
"an actor nor a group"
);
}
}
sink
->
end_object
();
}
void
deserialize
(
void
*
ptr
,
deserializer
*
source
)
const
void
deserialize
(
void
*
instance
,
deserializer
*
source
)
const
{
std
::
string
cname
=
source
->
seek_object
();
if
(
cname
!=
name
())
...
...
@@ -117,14 +282,43 @@ class actor_ptr_type_info : public util::abstract_uniform_type_info<actor_ptr>
throw
std
::
logic_error
(
"wrong type name found"
);
}
source
->
begin_object
(
cname
);
auto
id
=
get
<
std
::
uint32_t
>
(
source
->
read_value
(
pt_uint32
));
*
reinterpret_cast
<
actor_ptr
*>
(
ptr
)
=
actor
::
by_id
(
id
);
std
::
string
subobj
=
source
->
peek_object
();
if
(
subobj
==
actor_ptr_name
)
{
actor_ptr
tmp
;
actor_ptr_tinfo
::
s_deserialize
(
tmp
,
source
,
actor_ptr_name
);
*
reinterpret_cast
<
channel_ptr
*>
(
instance
)
=
tmp
;
}
else
if
(
subobj
==
group_ptr_name
)
{
group_ptr
tmp
;
group_ptr_tinfo
::
s_deserialize
(
tmp
,
source
,
group_ptr_name
);
*
reinterpret_cast
<
channel_ptr
*>
(
instance
)
=
tmp
;
}
else
if
(
subobj
==
nullptr_type_name
)
{
(
void
)
source
->
seek_object
();
deserialize_nullptr
(
source
);
reinterpret_cast
<
channel_ptr
*>
(
instance
)
->
reset
();
}
else
{
throw
std
::
logic_error
(
"unexpected type name: "
+
subobj
);
}
source
->
end_object
();
}
public:
channel_ptr_tinfo
()
:
group_ptr_name
(
to_uniform_name
(
typeid
(
group_ptr
)))
,
actor_ptr_name
(
to_uniform_name
(
typeid
(
actor_ptr
)))
{
}
};
class
any_tuple_t
ype_
info
:
public
util
::
abstract_uniform_type_info
<
any_tuple
>
class
any_tuple_tinfo
:
public
util
::
abstract_uniform_type_info
<
any_tuple
>
{
protected:
...
...
@@ -205,8 +399,14 @@ class uniform_type_info_map
insert
<
std
::
string
>
();
insert
<
std
::
u16string
>
();
insert
<
std
::
u32string
>
();
insert
(
new
actor_ptr_type_info
,
{
raw_name
<
actor_ptr
>
()
});
insert
(
new
any_tuple_type_info
,
{
raw_name
<
any_tuple
>
()
});
insert
(
new
default_uniform_type_info_impl
<
exit_reason
>
(
std
::
make_pair
(
&
exit_signal
::
reason
,
&
exit_signal
::
set_uint_reason
)),
{
raw_name
<
exit_signal
>
()
});
insert
(
new
any_tuple_tinfo
,
{
raw_name
<
any_tuple
>
()
});
insert
(
new
actor_ptr_tinfo
,
{
raw_name
<
actor_ptr
>
()
});
insert
(
new
group_ptr_tinfo
,
{
raw_name
<
actor_ptr
>
()
});
insert
(
new
channel_ptr_tinfo
,
{
raw_name
<
channel_ptr
>
()
});
insert
<
float
>
();
insert
<
cppa
::
util
::
void_type
>
();
if
(
sizeof
(
double
)
==
sizeof
(
long
double
))
...
...
unit_testing/test__local_group.cpp
View file @
50543c98
...
...
@@ -21,90 +21,6 @@ using std::endl;
using
namespace
cppa
;
class
local_group
:
public
group
{
friend
class
local_group_module
;
std
::
mutex
m_mtx
;
std
::
list
<
channel_ptr
>
m_subscribers
;
inline
std
::
list
<
channel_ptr
>::
iterator
find
(
const
channel_ptr
&
what
)
{
return
std
::
find
(
m_subscribers
.
begin
(),
m_subscribers
.
end
(),
what
);
}
local_group
()
=
default
;
public:
virtual
void
enqueue
(
const
message
&
msg
)
{
std
::
lock_guard
<
std
::
mutex
>
guard
(
m_mtx
);
for
(
auto
i
=
m_subscribers
.
begin
();
i
!=
m_subscribers
.
end
();
++
i
)
{
(
*
i
)
->
enqueue
(
msg
);
}
}
virtual
group
::
subscription
subscribe
(
const
channel_ptr
&
who
)
{
std
::
lock_guard
<
std
::
mutex
>
guard
(
m_mtx
);
auto
i
=
find
(
who
);
if
(
i
==
m_subscribers
.
end
())
{
m_subscribers
.
push_back
(
who
);
return
{
who
,
this
};
}
return
{
nullptr
,
nullptr
};
}
virtual
void
unsubscribe
(
const
channel_ptr
&
who
)
{
std
::
lock_guard
<
std
::
mutex
>
guard
(
m_mtx
);
auto
i
=
find
(
who
);
if
(
i
!=
m_subscribers
.
end
())
{
m_subscribers
.
erase
(
i
);
}
}
};
class
local_group_module
:
public
group
::
module
{
std
::
string
m_name
;
std
::
mutex
m_mtx
;
std
::
map
<
std
::
string
,
group_ptr
>
m_instances
;
public:
local_group_module
()
:
m_name
(
"local"
)
{
}
const
std
::
string
&
name
()
{
return
m_name
;
}
group_ptr
get
(
const
std
::
string
&
group_name
)
{
std
::
lock_guard
<
std
::
mutex
>
guard
(
m_mtx
);
auto
i
=
m_instances
.
find
(
group_name
);
if
(
i
==
m_instances
.
end
())
{
group_ptr
result
(
new
local_group
);
m_instances
.
insert
(
std
::
make_pair
(
group_name
,
result
));
return
result
;
}
else
return
i
->
second
;
}
};
void
worker
()
{
receive
(
on
<
int
>
()
>>
[](
int
value
)
{
...
...
@@ -115,11 +31,10 @@ void worker()
size_t
test__local_group
()
{
CPPA_TEST
(
test__local_group
);
group
::
add_module
(
new
local_group_module
);
auto
foo_group
=
group
::
get
(
"local"
,
"foo"
);
for
(
int
i
=
0
;
i
<
5
;
++
i
)
{
// spawn workers
in group local:
foo
// spawn workers
and let them join local/
foo
spawn
(
worker
)
->
join
(
foo_group
);
}
send
(
foo_group
,
2
);
...
...
unit_testing/test__serialization.cpp
View file @
50543c98
#include <new>
#include <set>
#include <list>
#include <stack>
#include <locale>
#include <memory>
#include <string>
...
...
@@ -129,7 +130,13 @@ class string_serializer : public serializer
void
operator
()(
const
std
::
string
&
str
)
{
out
<<
"
\"
"
<<
str
<<
"
\"
"
;
out
<<
"
\"
"
;
// << str << "\"";
for
(
char
c
:
str
)
{
if
(
c
==
'"'
)
out
<<
"
\\\"
"
;
else
out
<<
c
;
}
out
<<
'"'
;
}
void
operator
()(
const
std
::
u16string
&
)
{
}
...
...
@@ -140,6 +147,7 @@ class string_serializer : public serializer
int
m_open_objects
;
bool
m_after_value
;
bool
m_obj_just_opened
;
inline
void
clear
()
{
...
...
@@ -148,22 +156,39 @@ class string_serializer : public serializer
out
<<
", "
;
m_after_value
=
false
;
}
else
if
(
m_obj_just_opened
)
{
out
<<
" ( "
;
m_obj_just_opened
=
false
;
}
}
public:
string_serializer
(
std
::
ostream
&
mout
)
:
out
(
mout
),
m_open_objects
(
0
),
m_after_value
(
false
)
{
}
:
out
(
mout
),
m_open_objects
(
0
)
,
m_after_value
(
false
),
m_obj_just_opened
(
false
)
{
}
void
begin_object
(
const
std
::
string
&
type_name
)
{
clear
();
++
m_open_objects
;
out
<<
type_name
<<
" ( "
;
out
<<
type_name
;
// << " ( ";
m_obj_just_opened
=
true
;
}
void
end_object
()
{
out
<<
" )"
;
if
(
m_obj_just_opened
)
{
m_obj_just_opened
=
false
;
}
else
{
out
<<
(
m_after_value
?
" )"
:
")"
);
}
m_after_value
=
true
;
}
void
begin_sequence
(
size_t
)
...
...
@@ -204,6 +229,7 @@ class string_deserializer : public deserializer
std
::
string
m_str
;
std
::
string
::
iterator
m_pos
;
size_t
m_obj_count
;
std
::
stack
<
bool
>
m_obj_had_left_parenthesis
;
void
skip_space_and_comma
()
{
...
...
@@ -231,6 +257,17 @@ class string_deserializer : public deserializer
++
m_pos
;
}
bool
try_consume
(
char
c
)
{
skip_space_and_comma
();
if
(
*
m_pos
==
c
)
{
++
m_pos
;
return
true
;
}
return
false
;
}
inline
std
::
string
::
iterator
next_delimiter
()
{
return
std
::
find_if
(
m_pos
,
m_str
.
end
(),
[]
(
char
c
)
->
bool
{
...
...
@@ -247,6 +284,19 @@ class string_deserializer : public deserializer
});
}
void
integrity_check
()
{
if
(
m_obj_had_left_parenthesis
.
empty
())
{
throw_malformed
(
"missing begin_object()"
);
}
else
if
(
m_obj_had_left_parenthesis
.
top
()
==
false
)
{
throw_malformed
(
"expected left parenthesis after "
"begin_object call or void value"
);
}
}
public:
string_deserializer
(
const
std
::
string
&
str
)
:
m_str
(
str
)
...
...
@@ -265,15 +315,14 @@ class string_deserializer : public deserializer
{
skip_space_and_comma
();
auto
substr_end
=
next_delimiter
();
// next delimiter must eiter be '(' or "\w+\("
if
(
substr_end
==
m_str
.
end
()
||
*
substr_end
!=
'('
)
if
(
m_pos
==
substr_end
)
{
auto
peeker
=
substr_end
;
while
(
peeker
!=
m_str
.
end
()
&&
*
peeker
==
' '
)
++
peeker
;
if
(
peeker
==
m_str
.
end
()
||
*
peeker
!=
'('
)
if
(
m_pos
!=
m_str
.
end
())
{
throw_malformed
(
"type name not followed by '('"
);
std
::
string
remain
(
m_pos
,
m_str
.
end
());
cout
<<
remain
<<
endl
;
}
throw_malformed
(
"wtf?"
);
}
std
::
string
result
(
m_pos
,
substr_end
);
m_pos
=
substr_end
;
...
...
@@ -292,12 +341,24 @@ class string_deserializer : public deserializer
{
++
m_obj_count
;
skip_space_and_comma
();
consume
(
'('
);
m_obj_had_left_parenthesis
.
push
(
try_consume
(
'('
));
//consume('(');
}
void
end_object
()
{
consume
(
')'
);
if
(
m_obj_had_left_parenthesis
.
empty
())
{
throw_malformed
(
"missing begin_object()"
);
}
else
{
if
(
m_obj_had_left_parenthesis
.
top
()
==
true
)
{
consume
(
')'
);
}
m_obj_had_left_parenthesis
.
pop
();
}
if
(
--
m_obj_count
==
0
)
{
skip_space_and_comma
();
...
...
@@ -310,6 +371,7 @@ class string_deserializer : public deserializer
size_t
begin_sequence
()
{
integrity_check
();
consume
(
'{'
);
auto
list_end
=
std
::
find
(
m_pos
,
m_str
.
end
(),
'}'
);
return
std
::
count
(
m_pos
,
list_end
,
','
)
+
1
;
...
...
@@ -340,8 +402,11 @@ class string_deserializer : public deserializer
primitive_variant
read_value
(
primitive_type
ptype
)
{
integrity_check
();
skip_space_and_comma
();
auto
substr_end
=
std
::
find_if
(
m_pos
,
m_str
.
end
(),
[]
(
char
c
)
->
bool
{
std
::
string
::
iterator
substr_end
;
auto
find_if_cond
=
[]
(
char
c
)
->
bool
{
switch
(
c
)
{
case
')'
:
...
...
@@ -350,11 +415,87 @@ class string_deserializer : public deserializer
case
','
:
return
true
;
default
:
return
false
;
}
});
};
if
(
ptype
==
pt_u8string
)
{
if
(
*
m_pos
==
'"'
)
{
// skip leading "
++
m_pos
;
char
last_char
=
'"'
;
auto
find_if_str_cond
=
[
&
last_char
]
(
char
c
)
->
bool
{
if
(
c
==
'"'
&&
last_char
!=
'\\'
)
{
return
true
;
}
last_char
=
c
;
return
false
;
};
substr_end
=
std
::
find_if
(
m_pos
,
m_str
.
end
(),
find_if_str_cond
);
}
else
{
substr_end
=
std
::
find_if
(
m_pos
,
m_str
.
end
(),
find_if_cond
);
}
}
else
{
substr_end
=
std
::
find_if
(
m_pos
,
m_str
.
end
(),
find_if_cond
);
}
if
(
substr_end
==
m_str
.
end
())
{
throw
std
::
logic_error
(
"malformed string (unterminated value)"
);
}
std
::
string
substr
(
m_pos
,
substr_end
);
m_pos
+=
substr
.
size
();
if
(
ptype
==
pt_u8string
)
{
// skip trailing "
if
(
*
m_pos
!=
'"'
)
{
std
::
string
error_msg
;
error_msg
=
"malformed string, expected '
\"
' found '"
;
error_msg
+=
*
m_pos
;
error_msg
+=
"'"
;
throw
std
::
logic_error
(
error_msg
);
}
++
m_pos
;
// replace '\"' by '"'
char
last_char
=
' '
;
auto
cond
=
[
&
last_char
]
(
char
c
)
->
bool
{
if
(
c
==
'"'
&&
last_char
==
'\\'
)
{
return
true
;
}
last_char
=
c
;
return
false
;
};
std
::
string
tmp
;
auto
sbegin
=
substr
.
begin
();
auto
send
=
substr
.
end
();
for
(
auto
i
=
std
::
find_if
(
sbegin
,
send
,
cond
);
i
!=
send
;
i
=
std
::
find_if
(
i
,
send
,
cond
))
{
--
i
;
tmp
.
append
(
sbegin
,
i
);
tmp
+=
'"'
;
i
+=
2
;
sbegin
=
i
;
}
if
(
sbegin
!=
substr
.
begin
())
{
tmp
.
append
(
sbegin
,
send
);
}
if
(
!
tmp
.
empty
())
{
substr
=
std
::
move
(
tmp
);
}
}
primitive_variant
result
(
ptype
);
result
.
apply
(
from_string
(
substr
));
m_pos
+=
substr
.
size
();
return
result
;
}
...
...
@@ -362,6 +503,7 @@ class string_deserializer : public deserializer
void
read_tuple
(
size_t
size
,
const
primitive_type
*
begin
,
primitive_variant
*
storage
)
{
integrity_check
();
consume
(
'{'
);
const
primitive_type
*
end
=
begin
+
size
;
for
(
;
begin
!=
end
;
++
begin
)
...
...
@@ -374,7 +516,7 @@ class string_deserializer : public deserializer
};
class
message_
uti
:
public
util
::
abstract_uniform_type_info
<
message
>
class
message_
tinfo
:
public
util
::
abstract_uniform_type_info
<
message
>
{
public:
...
...
@@ -384,6 +526,8 @@ class message_uti : public util::abstract_uniform_type_info<message>
const
message
&
msg
=
*
reinterpret_cast
<
const
message
*>
(
instance
);
const
any_tuple
&
data
=
msg
.
content
();
sink
->
begin_object
(
name
());
uniform_typeid
<
actor_ptr
>
()
->
serialize
(
&
(
msg
.
sender
()),
sink
);
uniform_typeid
<
channel_ptr
>
()
->
serialize
(
&
(
msg
.
receiver
()),
sink
);
uniform_typeid
<
any_tuple
>
()
->
serialize
(
&
data
,
sink
);
sink
->
end_object
();
}
...
...
@@ -393,10 +537,16 @@ class message_uti : public util::abstract_uniform_type_info<message>
auto
tname
=
source
->
seek_object
();
if
(
tname
!=
name
())
throw
42
;
source
->
begin_object
(
tname
);
actor_ptr
sender
;
channel_ptr
receiver
;
any_tuple
content
;
uniform_typeid
<
actor_ptr
>
()
->
deserialize
(
&
sender
,
source
);
uniform_typeid
<
channel_ptr
>
()
->
deserialize
(
&
receiver
,
source
);
uniform_typeid
<
any_tuple
>
()
->
deserialize
(
&
content
,
source
);
source
->
end_object
();
*
reinterpret_cast
<
message
*>
(
instance
)
=
message
(
0
,
0
,
content
);
*
reinterpret_cast
<
message
*>
(
instance
)
=
message
(
sender
,
receiver
,
content
);
}
};
...
...
@@ -419,7 +569,7 @@ std::string to_string(const T& what)
size_t
test__serialization
()
{
CPPA_TEST
(
test__serialization
);
announce
(
typeid
(
message
),
new
message_
uti
);
announce
(
typeid
(
message
),
new
message_
tinfo
);
auto
oarr
=
new
detail
::
object_array
;
...
...
@@ -461,20 +611,29 @@ size_t test__serialization()
}
{
message
msg1
(
0
,
0
,
42
,
std
::
string
(
"Hello
World
!"
));
//
cout << "msg = " << to_string(msg1) << endl;
message
msg1
(
0
,
0
,
42
,
std
::
string
(
"Hello
\"
World
\"
!"
));
cout
<<
"msg = "
<<
to_string
(
msg1
)
<<
endl
;
binary_serializer
bs
;
bs
<<
msg1
;
binary_deserializer
bd
(
bs
.
data
(),
bs
.
size
());
object
obj
;
bd
>>
obj
;
if
(
obj
.
type
()
==
typeid
(
message
))
string_deserializer
sd
(
to_string
(
msg1
));
object
obj1
;
bd
>>
obj1
;
object
obj2
;
sd
>>
obj2
;
CPPA_CHECK_EQUAL
(
obj1
,
obj2
);
if
(
obj1
.
type
()
==
typeid
(
message
)
&&
obj2
.
type
()
==
obj1
.
type
())
{
auto
&
content
=
get
<
message
>
(
obj
).
content
();
auto
cview
=
get_view
<
decltype
(
42
),
std
::
string
>
(
content
);
CPPA_CHECK_EQUAL
(
cview
.
size
(),
2
);
CPPA_CHECK_EQUAL
(
get
<
0
>
(
cview
),
42
);
CPPA_CHECK_EQUAL
(
get
<
1
>
(
cview
),
"Hello World!"
);
auto
&
content1
=
get
<
message
>
(
obj1
).
content
();
auto
&
content2
=
get
<
message
>
(
obj2
).
content
();
auto
cview1
=
get_view
<
decltype
(
42
),
std
::
string
>
(
content1
);
auto
cview2
=
get_view
<
decltype
(
42
),
std
::
string
>
(
content2
);
CPPA_CHECK_EQUAL
(
cview1
.
size
(),
2
);
CPPA_CHECK_EQUAL
(
cview2
.
size
(),
2
);
CPPA_CHECK_EQUAL
(
get
<
0
>
(
cview1
),
42
);
CPPA_CHECK_EQUAL
(
get
<
0
>
(
cview2
),
42
);
CPPA_CHECK_EQUAL
(
get
<
1
>
(
cview1
),
"Hello
\"
World
\"
!"
);
CPPA_CHECK_EQUAL
(
get
<
1
>
(
cview2
),
"Hello
\"
World
\"
!"
);
}
else
{
...
...
unit_testing/test__uniform_type.cpp
View file @
50543c98
...
...
@@ -89,7 +89,10 @@ size_t test__uniform_type()
// default announced cppa types
"cppa::any_type"
,
"cppa::any_tuple"
,
"cppa::intrusive_ptr<cppa::actor>"
"cppa::exit_reason"
,
"cppa::intrusive_ptr<cppa::actor>"
,
"cppa::intrusive_ptr<cppa::group>"
,
"cppa::intrusive_ptr<cppa::channel>"
};
if
(
sizeof
(
double
)
!=
sizeof
(
long
double
))
{
...
...
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