Commit 64892301 authored by Dominik Charousset's avatar Dominik Charousset

re-implemented companions + fixed Qt examples

parent e513f0ee
......@@ -140,6 +140,7 @@ set(LIBCPPA_SRC
src/abstract_tuple.cpp
src/actor.cpp
src/actor_addr.cpp
src/actor_companion.cpp
src/actor_namespace.cpp
src/actor_proxy.cpp
src/actor_registry.cpp
......
......@@ -3,6 +3,7 @@ cppa/abstract_channel.hpp
cppa/abstract_group.hpp
cppa/actor.hpp
cppa/actor_addr.hpp
cppa/actor_companion.hpp
cppa/actor_namespace.hpp
cppa/actor_ostream.hpp
cppa/actor_proxy.hpp
......@@ -33,11 +34,13 @@ cppa/detail/behavior_impl.hpp
cppa/detail/behavior_stack.hpp
cppa/detail/boxed.hpp
cppa/detail/container_tuple_view.hpp
cppa/detail/cs_thread.hpp
cppa/detail/decorated_tuple.hpp
cppa/detail/default_uniform_type_info.hpp
cppa/detail/demangle.hpp
cppa/detail/disablable_delete.hpp
cppa/detail/empty_tuple.hpp
cppa/detail/execinfo_windows.hpp
cppa/detail/fd_util.hpp
cppa/detail/functor_based_actor.hpp
cppa/detail/functor_based_blocking_actor.hpp
......@@ -113,7 +116,7 @@ cppa/mailbox_based.hpp
cppa/mailbox_element.hpp
cppa/match.hpp
cppa/match_expr.hpp
cppa/skip_message.hpp
cppa/may_have_timeout.hpp
cppa/memory_cached.hpp
cppa/memory_managed.hpp
cppa/message_header.hpp
......@@ -165,6 +168,7 @@ cppa/scoped_actor.hpp
cppa/serializer.hpp
cppa/single_timeout.hpp
cppa/singletons.hpp
cppa/skip_message.hpp
cppa/spawn.hpp
cppa/spawn_fwd.hpp
cppa/spawn_options.hpp
......@@ -191,7 +195,6 @@ cppa/util/comparable.hpp
cppa/util/compare_tuples.hpp
cppa/util/dptr.hpp
cppa/util/duration.hpp
cppa/detail/cs_thread.hpp
cppa/util/get_mac_addresses.hpp
cppa/util/get_root_uuid.hpp
cppa/util/guard.hpp
......@@ -216,11 +219,13 @@ cppa/util/wrapped.hpp
cppa/weak_intrusive_ptr.hpp
cppa/weak_ptr_anchor.hpp
cppa/wildcard_position.hpp
examples/aout.cpp
examples/curl/curl_fuse.cpp
examples/hello_world.cpp
examples/message_passing/calculator.cpp
examples/message_passing/dancing_kirby.cpp
examples/message_passing/dining_philosophers.cpp
examples/message_passing/typed_calculator.cpp
examples/opencl/proper_matrix.cpp
examples/opencl/simple_matrix.cpp
examples/qtsupport/chatwidget.cpp
......@@ -241,6 +246,7 @@ src/abstract_group.cpp
src/abstract_tuple.cpp
src/actor.cpp
src/actor_addr.cpp
src/actor_companion.cpp
src/actor_namespace.cpp
src/actor_ostream.cpp
src/actor_proxy.cpp
......@@ -260,6 +266,7 @@ src/channel.cpp
src/context_switching_resume.cpp
src/continuable.cpp
src/continue_helper.cpp
src/cs_thread.cpp
src/decorated_tuple.cpp
src/demangle.cpp
src/deserializer.cpp
......@@ -267,10 +274,10 @@ src/duration.cpp
src/empty_tuple.cpp
src/event_based_actor.cpp
src/exception.cpp
src/execinfo_windows.cpp
src/exit_reason.cpp
src/factory.cpp
src/fd_util.cpp
src/cs_thread.cpp
src/functor_based_actor.cpp
src/functor_based_blocking_actor.cpp
src/get_mac_addresses.cpp
......@@ -348,8 +355,3 @@ unit_testing/test_typed_remote_actor.cpp
unit_testing/test_typed_spawn.cpp
unit_testing/test_uniform_type.cpp
unit_testing/test_yield_interface.cpp
cppa/may_have_timeout.hpp
examples/message_passing/typed_calculator.cpp
examples/aout.cpp
cppa/detail/execinfo_windows.hpp
src/execinfo_windows.cpp
......@@ -48,6 +48,7 @@ class actor_addr;
class actor_proxy;
class local_actor;
class blocking_actor;
class actor_companion;
class event_based_actor;
struct invalid_actor_addr_t;
......@@ -78,6 +79,7 @@ struct is_convertible_to_actor {
static constexpr bool value = std::is_base_of<io::broker, T>::value
|| std::is_base_of<actor_proxy, T>::value
|| std::is_base_of<blocking_actor, T>::value
|| std::is_base_of<actor_companion, T>::value
|| std::is_base_of<event_based_actor, T>::value;
};
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_ACTOR_COMPANION_HPP
#define CPPA_ACTOR_COMPANION_HPP
#include <memory>
#include <functional>
#include "cppa/local_actor.hpp"
#include "cppa/sync_sender.hpp"
#include "cppa/mailbox_based.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/behavior_stack_based.hpp"
#include "cppa/detail/memory.hpp"
#include "cppa/util/shared_spinlock.hpp"
#include "cppa/util/shared_lock_guard.hpp"
namespace cppa {
/**
* @brief An co-existing forwarding all messages through a user-defined
* callback to another object, thus serving as gateway to
* allow any object to interact with other actors.
*/
class actor_companion : public extend<local_actor, actor_companion>::
with<behavior_stack_based<behavior>::impl,
sync_sender<nonblocking_response_handle_tag>::impl> {
typedef util::shared_spinlock lock_type;
public:
typedef std::unique_ptr<mailbox_element, detail::disposer> message_pointer;
typedef std::function<void (message_pointer)> enqueue_handler;
/**
* @brief Removes the handler for incoming messages and terminates
* the companion for exit reason @ rsn.
*/
void disconnect(std::uint32_t rsn = exit_reason::normal);
/**
* @brief Sets the handler for incoming messages.
* @warning @p handler needs to be thread-safe
*/
void on_enqueue(enqueue_handler handler);
void enqueue(const message_header& hdr, any_tuple msg) override;
private:
// set by parent to define custom enqueue action
enqueue_handler m_on_enqueue;
// guards access to m_handler
lock_type m_lock;
};
/**
* @brief A pointer to a co-existing (actor) object.
* @relates actor_companion
*/
typedef intrusive_ptr<actor_companion> actor_companion_ptr;
} // namespace cppa
#endif // CPPA_ACTOR_COMPANION_HPP
......@@ -34,48 +34,65 @@
#include <QEvent>
#include <QApplication>
#include "cppa/actor_companion_mixin.hpp"
#include "cppa/actor_companion.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/policy/sequential_invoke.hpp"
namespace cppa {
template<typename Base, int EventId = static_cast<int>(QEvent::User + 31337)>
class actor_widget_mixin : public actor_companion_mixin<Base> {
typedef actor_companion_mixin<Base> super;
typedef typename super::message_pointer message_pointer;
class actor_widget_mixin : public Base {
public:
template<typename... Ts>
actor_widget_mixin(Ts&&... args) : super(std::forward<Ts>(args)...) { }
typedef typename actor_companion::message_pointer message_pointer;
struct event_type : public QEvent {
message_pointer msg;
message_pointer mptr;
event_type(message_pointer mptr)
: QEvent(static_cast<QEvent::Type>(EventId)), msg(std::move(mptr)) { }
: QEvent(static_cast<QEvent::Type>(EventId)), mptr(std::move(mptr)) { }
};
template<typename... Ts>
actor_widget_mixin(Ts&&... args) : Base(std::forward<Ts>(args)...) {
m_companion.reset(detail::memory::create<actor_companion>());
m_companion->on_enqueue([=](message_pointer ptr) {
qApp->postEvent(this, new event_type(std::move(ptr)));
});
}
template<typename T>
void set_message_handler(T pfun) {
m_companion->become(pfun(m_companion.get()));
}
virtual bool event(QEvent* event) {
if (event->type() == static_cast<QEvent::Type>(EventId)) {
auto ptr = dynamic_cast<event_type*>(event);
if (ptr) {
this->handle_message(ptr->msg);
m_invoke.handle_message(m_companion.get(),
ptr->mptr.release(),
m_companion->bhvr_stack().back(),
m_companion->bhvr_stack().back_id());
return true;
}
}
return super::event(event);
return Base::event(event);
}
protected:
virtual void new_message(message_pointer ptr) {
qApp->postEvent(this, new event_type(std::move(ptr)));
actor as_actor() const {
return m_companion;
}
private:
policy::sequential_invoke m_invoke;
actor_companion_ptr m_companion;
};
} // namespace cppa
......
......@@ -14,33 +14,39 @@ using namespace cppa;
ChatWidget::ChatWidget(QWidget* parent, Qt::WindowFlags f)
: super(parent, f), m_input(nullptr), m_output(nullptr) {
set_message_handler (
on(atom("join"), arg_match) >> [=](const group& what) {
if (m_chatroom) {
send(m_chatroom, m_name + " has left the chatroom");
self->leave(m_chatroom);
}
self->join(what);
print(("*** joined " + to_string(what)).c_str());
m_chatroom = what;
send(what, m_name + " has entered the chatroom");
},
on(atom("setName"), arg_match) >> [=](string& name) {
send(m_chatroom, m_name + " is now known as " + name);
m_name = std::move(name);
print("*** changed name to "
+ QString::fromUtf8(m_name.c_str()));
},
on(atom("quit")) >> [=] {
close(); // close widget
},
on<string>() >> [=](const string& txt) {
// don't print own messages
if (self != self->last_sender()) {
print(QString::fromUtf8(txt.c_str()));
set_message_handler ([=](local_actor* self) -> partial_function {
return {
on(atom("join"), arg_match) >> [=](const group& what) {
if (m_chatroom) {
self->send(m_chatroom, m_name + " has left the chatroom");
self->leave(m_chatroom);
}
self->join(what);
print(("*** joined " + to_string(what)).c_str());
m_chatroom = what;
self->send(what, m_name + " has entered the chatroom");
},
on(atom("setName"), arg_match) >> [=](string& name) {
self->send(m_chatroom, m_name + " is now known as " + name);
m_name = std::move(name);
print("*** changed name to "
+ QString::fromUtf8(m_name.c_str()));
},
on(atom("quit")) >> [=] {
close(); // close widget
},
[=](const string& txt) {
// don't print own messages
if (self != self->last_sender()) {
print(QString::fromUtf8(txt.c_str()));
}
},
[=](const group_down_msg& gdm) {
print("*** chatroom offline: "
+ QString::fromUtf8(to_string(gdm.source).c_str()));
}
}
);
};
});
}
void ChatWidget::sendChatMessage() {
......@@ -52,11 +58,11 @@ void ChatWidget::sendChatMessage() {
match_split(line.midRef(1).toUtf8().constData(), ' ') (
on("join", arg_match) >> [=](const string& mod, const string& g) {
group gptr;
try { gptr = abstract_group::get(mod, g); }
try { gptr = group::get(mod, g); }
catch (exception& e) {
print("*** exception: " + QString::fromUtf8((e.what())));
}
if (gptr != nullptr) {
if (gptr) {
send_as(as_actor(), as_actor(), atom("join"), gptr);
}
},
......@@ -75,7 +81,7 @@ void ChatWidget::sendChatMessage() {
print("*** please set a name before sending messages");
return;
}
if (m_chatroom == nullptr) {
if (!m_chatroom) {
print("*** no one is listening... please join a group");
return;
}
......@@ -110,7 +116,7 @@ void ChatWidget::joinGroup() {
string gid = gname.midRef(pos+1).toUtf8().constData();
group gptr;
try {
auto gptr = abstract_group::get(mod, gid);
auto gptr = group::get(mod, gid);
send_as(as_actor(), as_actor(), atom("join"), gptr);
}
catch (exception& e) {
......
......@@ -4,7 +4,7 @@
#include <QLineEdit>
#include <QTextEdit>
#include "cppa/abstract_group.hpp"
#include "cppa/group.hpp"
#include "cppa/qtsupport/actor_widget_mixin.hpp"
class ChatWidget : public cppa::actor_widget_mixin<QWidget> {
......
......@@ -70,7 +70,7 @@ int main(int argc, char** argv) {
}
else {
try {
gptr = abstract_group::get(group_id.substr(0, p),
gptr = group::get(group_id.substr(0, p),
group_id.substr(p + 1));
}
catch (exception& e) {
......@@ -93,7 +93,7 @@ int main(int argc, char** argv) {
if (!name.empty()) {
send_as(client, client, atom("setName"), move(name));
}
if (gptr != nullptr) {
if (gptr) {
send_as(client, client, atom("join"), gptr);
}
mw.show();
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#include "cppa/actor_companion.hpp"
namespace cppa {
void actor_companion::disconnect(std::uint32_t rsn) {
enqueue_handler tmp;
{ // lifetime scope of guard
std::lock_guard<lock_type> guard(m_lock);
m_on_enqueue.swap(tmp);
}
cleanup(rsn);
}
void actor_companion::on_enqueue(enqueue_handler handler) {
std::lock_guard<lock_type> guard(m_lock);
m_on_enqueue = std::move(handler);
}
void actor_companion::enqueue(const message_header& hdr, any_tuple msg) {
message_pointer ptr;
ptr.reset(detail::memory::create<mailbox_element>(hdr, std::move(msg)));
util::shared_lock_guard<lock_type> guard(m_lock);
if (!m_on_enqueue) return;
m_on_enqueue(std::move(ptr));
}
} // namespace cppa
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment