Commit eb29971e authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'develop' of github.com:actor-framework/actor-framework into develop

parents 6a8fd3e5 5c0525b7
...@@ -108,7 +108,7 @@ else() ...@@ -108,7 +108,7 @@ else()
message(STATUS "NOTE: Automatically added -stdlib=libc++ flag, " message(STATUS "NOTE: Automatically added -stdlib=libc++ flag, "
"you can override this by defining CMAKE_CXX_FLAGS " "you can override this by defining CMAKE_CXX_FLAGS "
"(see 'configure --help')") "(see 'configure --help')")
set(CMAKE_CXX_FLAGS "-std=c++11 -stdlib=libc++") set(CMAKE_CXX_FLAGS "-std=c++11 -stdlib=libc++ -fPIC")
if(MORE_CLANG_WARNINGS) if(MORE_CLANG_WARNINGS)
set(CMAKE_CXX_FLAGS "-pedantic -Weverything -Wno-c++98-compat " set(CMAKE_CXX_FLAGS "-pedantic -Weverything -Wno-c++98-compat "
"-Wno-padded -Wno-documentation-unknown-command " "-Wno-padded -Wno-documentation-unknown-command "
...@@ -118,7 +118,7 @@ else() ...@@ -118,7 +118,7 @@ else()
"-Wno-unused-const-variable") "-Wno-unused-const-variable")
endif() endif()
else() else()
set(CMAKE_CXX_FLAGS "-std=c++11 -Wextra -Wall -pedantic") set(CMAKE_CXX_FLAGS "-std=c++11 -Wextra -Wall -pedantic -fPIC")
endif() endif()
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os")
...@@ -204,9 +204,9 @@ set(LIBCAF_INCLUDE_DIRS ...@@ -204,9 +204,9 @@ set(LIBCAF_INCLUDE_DIRS
${CMAKE_SOURCE_DIR}/libcaf_core ${CMAKE_SOURCE_DIR}/libcaf_core
${CMAKE_SOURCE_DIR}/libcaf_io) ${CMAKE_SOURCE_DIR}/libcaf_io)
# path to caf opencl headers # path to caf opencl headers
if(EXISTS ${CMAKE_SOURCE_DOR}/libcaf_opencl/caf) if(EXISTS ${CMAKE_SOURCE_DIR}/libcaf_opencl/caf)
set(LIBCAF_INCLUDE_DIRS ${LIBCAF_INCLUDE_DIRS} set(LIBCAF_INCLUDE_DIRS
${CMAKE_SOURCE_DIR}/libcaf_opencl) ${CMAKE_SOURCE_DIR}/libcaf_opencl/ ${LIBCAF_INCLUDE_DIRS})
endif() endif()
# path to probe-event headers (if submodule is loaded) # path to probe-event headers (if submodule is loaded)
...@@ -239,7 +239,9 @@ set(LIBCAF_IO_LIBRARY libcaf_io) ...@@ -239,7 +239,9 @@ set(LIBCAF_IO_LIBRARY libcaf_io)
# set opencl lib for sub directories if not told otherwise # set opencl lib for sub directories if not told otherwise
if(NOT CAF_NO_OPENCL AND EXISTS "${CMAKE_SOURCE_DIR}/libcaf_opencl/caf") if(NOT CAF_NO_OPENCL AND EXISTS "${CMAKE_SOURCE_DIR}/libcaf_opencl/caf")
message(STATUS "Enter subdirectory libcaf_opencl") message(STATUS "Enter subdirectory libcaf_opencl")
find_package(OPENCL REQUIRED)
add_subdirectory(libcaf_opencl) add_subdirectory(libcaf_opencl)
set(LIBCAF_OPENCL_LIBRARY libcaf_opencl)
endif() endif()
# tell CMake caf_io depends on caf_core # tell CMake caf_io depends on caf_core
if(CAF_BUILD_STATIC_ONLY OR CAF_BUILD_STATIC) if(CAF_BUILD_STATIC_ONLY OR CAF_BUILD_STATIC)
...@@ -249,13 +251,16 @@ if(NOT CAF_BUILD_STATIC_ONLY) ...@@ -249,13 +251,16 @@ if(NOT CAF_BUILD_STATIC_ONLY)
add_dependencies(libcaf_io libcaf_core) add_dependencies(libcaf_io libcaf_core)
endif() endif()
# set LIBCAF_LIBRARIES for other subprojects # set LIBCAF_LIBRARIES for other subprojects
set(LIBCAF_LIBRARIES ${LIBCAF_CORE_LIBRARY} ${LIBCAF_IO_LIBRARY}) set(LIBCAF_LIBRARIES ${LIBCAF_CORE_LIBRARY} ${LIBCAF_IO_LIBRARY} ${LIBCAF_OPENCL_LIBRARY})
# add unit tests if not being told otherwise # add unit tests if not being told otherwise
if(NOT CAF_NO_UNIT_TESTS) if(NOT CAF_NO_UNIT_TESTS)
enable_testing() enable_testing()
message(STATUS "Enter subdirectory unit_testing") message(STATUS "Enter subdirectory unit_testing")
add_subdirectory(unit_testing) add_subdirectory(unit_testing)
add_dependencies(all_unit_tests libcaf_io) add_dependencies(all_unit_tests libcaf_io)
if(NOT CAF_NO_OPENCL AND EXISTS "${CMAKE_SOURCE_DIR}/libcaf_opencl/caf")
add_subdirectory(libcaf_opencl/unit_testing)
endif()
endif() endif()
# build examples if not being told otherwise # build examples if not being told otherwise
if(NOT CAF_NO_EXAMPLES) if(NOT CAF_NO_EXAMPLES)
...@@ -310,6 +315,13 @@ if(NOT CAF_NO_PROBE AND EXISTS "${CMAKE_SOURCE_DIR}/probe/caf/") ...@@ -310,6 +315,13 @@ if(NOT CAF_NO_PROBE AND EXISTS "${CMAKE_SOURCE_DIR}/probe/caf/")
set(CAF_NO_PROBE no) set(CAF_NO_PROBE no)
endif() endif()
endif() endif()
# add probe-event if not told otherwise
if(NOT CAF_NO_PROBE_EVENT AND EXISTS "${CMAKE_SOURCE_DIR}/probe-event/caf/")
message(STATUS "Enter subdirectory probe-event")
add_subdirectory(probe-event)
set(CAF_NO_PROBE_EVENT no)
endif()
# build benchmarks if not being told otherwise # build benchmarks if not being told otherwise
if(NOT CAF_NO_BENCHMARKS AND EXISTS "${CMAKE_SOURCE_DIR}/benchmarks/caf/") if(NOT CAF_NO_BENCHMARKS AND EXISTS "${CMAKE_SOURCE_DIR}/benchmarks/caf/")
message(STATUS "Enter subdirectory benchmarks") message(STATUS "Enter subdirectory benchmarks")
......
# - Try to find OpenCL
# Once done this will define
#
# OPENCL_FOUND - system has OpenCL
# OPENCL_INCLUDE_DIR - the OpenCL include directory
# OPENCL_LIBRARIES - link these to use OpenCL
#
# WIN32 should work, but is untested
IF (WIN32)
FIND_PATH(OPENCL_INCLUDE_DIR CL/cl.h )
# TODO this is only a hack assuming the 64 bit library will
# not be found on 32 bit system
FIND_LIBRARY(OPENCL_LIBRARIES opencl ) #used to say opencl64
IF( OPENCL_LIBRARIES )
FIND_LIBRARY(OPENCL_LIBRARIES opencl ) #used to say opencl32
ENDIF( OPENCL_LIBRARIES )
ELSE (WIN32)
# Unix style platforms
# We also search for OpenCL in the NVIDIA GPU SDK default location
#SET(OPENCL_INCLUDE_DIR "$ENV{OPENCL_HOME}/common/inc"
# CACHE PATH "path to Opencl Include files")
#message(***** OPENCL_INCLUDE_DIR: "${OPENCL_INCLUDE_DIR}" ********)
# does not work. WHY?
#SET(inc $ENV{CUDA_LOCAL}/../OpenCL/common/inc /usr/include)
#FIND_PATH(OPENCL_INCLUDE_DIR CL/cl.h PATHS ${inc} /usr/include )
message("lib path: $ENV{LD_LIBRARY_PATH}")
#FIND_LIBRARY(OPENCL_LIBRARIES OpenCL $ENV{LD_LIBRARY_PATH})
FIND_LIBRARY(OPENCL_LIBRARIES OpenCL ENV LD_LIBRARY_PATH)
message("==============")
message("opencl_libraries: ${OPENCL_LIBRARIES}")
#message(***** OPENCL ENV: "$ENV{GPU_SDK}" ********)
#~/NVIDIA_GPU_Computing_SDK/OpenCL/common/inc/
ENDIF (WIN32)
SET( OPENCL_FOUND "NO" )
IF(OPENCL_LIBRARIES )
SET( OPENCL_FOUND "YES" )
ENDIF(OPENCL_LIBRARIES)
MARK_AS_ADVANCED(
OPENCL_INCLUDE_DIR
)
...@@ -5,11 +5,11 @@ add_custom_target(all_examples) ...@@ -5,11 +5,11 @@ add_custom_target(all_examples)
include_directories(${LIBCAF_INCLUDE_DIRS}) include_directories(${LIBCAF_INCLUDE_DIRS})
if (${CMAKE_SYSTEM_NAME} MATCHES "Window") if(${CMAKE_SYSTEM_NAME} MATCHES "Window")
set(WSLIB -lws2_32) set(WSLIB -lws2_32)
else () else ()
set(WSLIB) set(WSLIB)
endif () endif()
macro(add name folder) macro(add name folder)
add_executable(${name} ${folder}/${name}.cpp ${ARGN}) add_executable(${name} ${folder}/${name}.cpp ${ARGN})
...@@ -37,9 +37,9 @@ add(group_server remote_actors) ...@@ -37,9 +37,9 @@ add(group_server remote_actors)
add(group_chat remote_actors) add(group_chat remote_actors)
add(simple_broker remote_actors) add(simple_broker remote_actors)
if (NOT "${CAF_NO_PROTOBUF_EXAMPLES}" STREQUAL "yes") if(NOT CAF_NO_PROTOBUF_EXAMPLES)
find_package(Protobuf) find_package(Protobuf)
if (PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE) if(PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE)
PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders "${CMAKE_CURRENT_SOURCE_DIR}/remote_actors/pingpong.proto") PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders "${CMAKE_CURRENT_SOURCE_DIR}/remote_actors/pingpong.proto")
include_directories(${PROTOBUF_INCLUDE_DIR}) include_directories(${PROTOBUF_INCLUDE_DIR})
# add binary dir as include path as generated headers will be located there # add binary dir as include path as generated headers will be located there
...@@ -47,14 +47,66 @@ if (NOT "${CAF_NO_PROTOBUF_EXAMPLES}" STREQUAL "yes") ...@@ -47,14 +47,66 @@ if (NOT "${CAF_NO_PROTOBUF_EXAMPLES}" STREQUAL "yes")
add_executable(protobuf_broker remote_actors/protobuf_broker.cpp ${ProtoSources}) add_executable(protobuf_broker remote_actors/protobuf_broker.cpp ${ProtoSources})
target_link_libraries(protobuf_broker ${CMAKE_DL_LIBS} ${LIBCAF_LIBRARIES} ${PTHREAD_LIBRARIES} ${PROTOBUF_LIBRARIES}) target_link_libraries(protobuf_broker ${CMAKE_DL_LIBS} ${LIBCAF_LIBRARIES} ${PTHREAD_LIBRARIES} ${PROTOBUF_LIBRARIES})
add_dependencies(protobuf_broker all_examples) add_dependencies(protobuf_broker all_examples)
endif (PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE) endif(PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE)
endif () endif()
if (NOT "${CAF_NO_CURL_EXAMPLES}" STREQUAL "yes") if(NOT CAF_NO_QT_EXAMPLES)
find_package(Qt5 COMPONENTS Core Gui Widgets)
if(Qt5_FOUND)
message(STATUS "Found Qt5")
#include(${QT_USE_FILE})
QT5_ADD_RESOURCES(GROUP_CHAT_RCS )
QT5_WRAP_UI(GROUP_CHAT_UI_HDR qtsupport/chatwindow.ui)
QT5_WRAP_CPP(GROUP_CHAT_MOC_SRC qtsupport/chatwidget.hpp)
# generated headers will be in cmake build directory
#include_directories(. qtsupport ${CMAKE_CURRENT_BINARY_DIR} ${CPPA_INCLUDE})
include_directories(qtsupport
${CMAKE_CURRENT_BINARY_DIR}
${Qt5Core_INCLUDE_DIRS}
${Qt5Gui_INCLUDE_DIRS}
${Qt5Widgets_INCLUDE_DIRS})
set(GROUP_CHAT_SRC qtsupport/qt_group_chat.cpp qtsupport/chatwidget.cpp)
add_executable(qt_group_chat
${GROUP_CHAT_SRC}
${GROUP_CHAT_MOC_SRC}
${GROUP_CHAT_UI_HDR})
target_link_libraries(qt_group_chat
${CMAKE_DL_LIBS}
${LIBCAF_LIBRARIES}
Qt5::Core
Qt5::Gui
Qt5::Widgets)
add_dependencies(qt_group_chat all_examples)
else()
find_package(Qt4)
if(QT4_FOUND)
message(STATUS "Found Qt4")
include(${QT_USE_FILE})
QT4_ADD_RESOURCES(GROUP_CHAT_RCS )
QT4_WRAP_UI(GROUP_CHAT_UI_HDR qtsupport/chatwindow.ui)
QT4_WRAP_CPP(GROUP_CHAT_MOC_SRC qtsupport/chatwidget.hpp)
# generated headers will be in cmake build directory
#include_directories(. qtsupport ${CMAKE_CURRENT_BINARY_DIR} ${CPPA_INCLUDE})
include_directories(qtsupport ${CMAKE_CURRENT_BINARY_DIR})
set(GROUP_CHAT_SRCS qtsupport/qt_group_chat.cpp qtsupport/chatwidget.cpp)
add_executable(qt_group_chat
${GROUP_CHAT_SRCS}
${GROUP_CHAT_MOC_SRC}
${GROUP_CHAT_UI_HDR})
target_link_libraries(qt_group_chat
${CMAKE_DL_LIBS}
${LIBCAF_LIBRARIES}
${QT_LIBRARIES})
add_dependencies(qt_group_chat all_examples)
endif()
endif()
endif()
if(NOT CAF_NO_CURL_EXAMPLES)
find_package(CURL) find_package(CURL)
if (CURL_FOUND) if(CURL_FOUND)
add_executable(curl_fuse curl/curl_fuse.cpp) add_executable(curl_fuse curl/curl_fuse.cpp)
target_link_libraries(curl_fuse ${CMAKE_DL_LIBS} ${LIBCAF_LIBRARIES} ${PTHREAD_LIBRARIES} ${CURL_LIBRARY}) target_link_libraries(curl_fuse ${CMAKE_DL_LIBS} ${LIBCAF_LIBRARIES} ${PTHREAD_LIBRARIES} ${CURL_LIBRARY})
add_dependencies(curl_fuse all_examples) add_dependencies(curl_fuse all_examples)
endif (CURL_FOUND) endif(CURL_FOUND)
endif () endif()
#include <string>
#include <utility>
#include <QMessageBox>
#include <QInputDialog>
#include "chatwidget.hpp"
#include "caf/all.hpp"
#include "caf/detail/scope_guard.hpp"
using namespace std;
using namespace caf;
ChatWidget::ChatWidget(QWidget* parent, Qt::WindowFlags f)
: super(parent, f), m_input(nullptr), m_output(nullptr) {
set_message_handler ([=](local_actor* self) -> message_handler {
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() {
auto cleanup = detail::make_scope_guard([=] {
input()->setText(QString());
});
QString line = input()->text();
if (line.startsWith('/')) {
match_split(line.midRef(1).toUtf8().constData(), ' ') (
on("join", arg_match) >> [=](const string& mod, const string& g) {
group gptr;
try { gptr = group::get(mod, g); }
catch (exception& e) {
print("*** exception: " + QString::fromUtf8((e.what())));
}
if (gptr) {
send_as(as_actor(), as_actor(), atom("join"), gptr);
}
},
on("setName", arg_match) >> [=](const string& str) {
send_as(as_actor(), as_actor(), atom("setName"), str);
},
others() >> [=] {
print("*** list of commands:\n"
"/join <module> <group id>\n"
"/setName <new name>\n");
}
);
return;
}
if (m_name.empty()) {
print("*** please set a name before sending messages");
return;
}
if (!m_chatroom) {
print("*** no one is listening... please join a group");
return;
}
string msg = m_name;
msg += ": ";
msg += line.toUtf8().constData();
print("<you>: " + input()->text());
// NOTE: we have to use send_as(as_actor(), ...) outside of our
// message handler, because `self` is *not* set properly
// in this context
send_as(as_actor(), m_chatroom, std::move(msg));
}
void ChatWidget::joinGroup() {
if (m_name.empty()) {
QMessageBox::information(this,
"No Name, No Chat",
"Please set a name first.");
return;
}
auto gname = QInputDialog::getText(this,
"Join Group",
"Please enter a group as <module>:<id>",
QLineEdit::Normal,
"remote:chatroom@localhost:4242");
int pos = gname.indexOf(':');
if (pos < 0) {
QMessageBox::warning(this, "Not a Group", "Invalid format");
return;
}
string mod = gname.left(pos).toUtf8().constData();
string gid = gname.midRef(pos+1).toUtf8().constData();
try {
auto gptr = group::get(mod, gid);
send_as(as_actor(), as_actor(), atom("join"), gptr);
}
catch (exception& e) {
QMessageBox::critical(this, "Exception", e.what());
}
}
void ChatWidget::changeName() {
auto name = QInputDialog::getText(this, "Change Name", "Please enter a new name");
if (!name.isEmpty()) {
send_as(as_actor(), as_actor(), atom("setName"), name.toUtf8().constData());
}
}
#include <exception>
#include <QWidget>
#include <QLineEdit>
#include <QTextEdit>
#include "caf/all.hpp"
#include "caf/mixin/actor_widget.hpp"
class ChatWidget : public caf::mixin::actor_widget<QWidget> {
Q_OBJECT
typedef caf::mixin::actor_widget<QWidget> super;
public:
ChatWidget(QWidget* parent = nullptr, Qt::WindowFlags f = 0);
public slots:
void sendChatMessage();
void joinGroup();
void changeName();
private:
template<typename T>
T* get(T*& member, const char* name) {
if (member == nullptr) {
member = findChild<T*>(name);
if (member == nullptr)
throw std::runtime_error("unable to find child: "
+ std::string(name));
}
return member;
}
inline QLineEdit* input() {
return get(m_input, "input");
}
inline QTextEdit* output() {
return get(m_output, "output");
}
inline void print(const QString& what) {
output()->append(what);
}
QLineEdit* m_input;
QTextEdit* m_output;
std::string m_name;
caf::group m_chatroom;
};
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ChatWindow</class>
<widget class="QMainWindow" name="ChatWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="ChatWidget" name="chatwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QTextEdit" name="output">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="input">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionJoin_Group"/>
<addaction name="actionSet_Name"/>
</widget>
<addaction name="menuFile"/>
</widget>
<action name="actionJoin_Group">
<property name="text">
<string>Join Group</string>
</property>
</action>
<action name="actionSet_Name">
<property name="text">
<string>Set Name</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>ChatWidget</class>
<extends>QWidget</extends>
<header>chatwidget.hpp</header>
<container>1</container>
<slots>
<slot>sendChatMessage()</slot>
<slot>changeName()</slot>
<slot>joinGroup()</slot>
</slots>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>actionJoin_Group</sender>
<signal>activated()</signal>
<receiver>chatwidget</receiver>
<slot>joinGroup()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>300</y>
</hint>
</hints>
</connection>
<connection>
<sender>actionSet_Name</sender>
<signal>activated()</signal>
<receiver>chatwidget</receiver>
<slot>changeName()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>300</y>
</hint>
</hints>
</connection>
<connection>
<sender>input</sender>
<signal>returnPressed()</signal>
<receiver>chatwidget</receiver>
<slot>sendChatMessage()</slot>
<hints>
<hint type="sourcelabel">
<x>362</x>
<y>547</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>310</y>
</hint>
</hints>
</connection>
</connections>
</ui>
/******************************************************************************\
* This example program represents a minimal GUI chat program *
* based on group communication. This chat program is compatible to the *
* terminal version in remote_actors/group_chat.cpp. *
* *
* Setup for a minimal chat between "alice" and "bob": *
* - ./build/bin/group_server -p 4242 *
* - ./build/bin/qt_group_chat -g remote:chatroom@localhost:4242 -n alice *
* - ./build/bin/qt_group_chat -g remote:chatroom@localhost:4242 -n bob *
\******************************************************************************/
#include <set>
#include <map>
#include <vector>
#include <iostream>
#include <sstream>
#include <time.h>
#include <cstdlib>
#include <QMainWindow>
#include <QApplication>
#include "caf/all.hpp"
#include "cppa/opt.hpp"
#include "ui_chatwindow.h" // auto generated from chatwindow.ui
using namespace std;
using namespace caf;
/*
namespace {
struct line { string str; };
istream& operator>>(istream& is, line& l) {
getline(is, l.str);
return is;
}
any_tuple s_last_line;
any_tuple split_line(const line& l) {
vector<string> result;
stringstream strs(l.str);
string tmp;
while (getline(strs, tmp, ' ')) {
if (!tmp.empty()) result.push_back(std::move(tmp));
}
s_last_line = any_tuple::view(std::move(result));
return s_last_line;
}
} // namespace <anonymous>
*/
int main(int argc, char** argv) {
string name;
string group_id;
options_description desc;
bool args_valid = match_stream<string>(argv + 1, argv + argc) (
on_opt1('n', "name", &desc, "set name") >> rd_arg(name),
on_opt1('g', "group", &desc, "join group <arg1>") >> rd_arg(group_id),
on_opt0('h', "help", &desc, "print help") >> print_desc_and_exit(&desc)
);
group gptr;
// evaluate group parameter
if (!group_id.empty()) {
auto p = group_id.find(':');
if (p == std::string::npos) {
cerr << "*** error parsing argument " << group_id
<< ", expected format: <module_name>:<group_id>";
}
else {
try {
gptr = group::get(group_id.substr(0, p),
group_id.substr(p + 1));
}
catch (exception& e) {
ostringstream err;
cerr << "*** exception: group::get(\"" << group_id.substr(0, p)
<< "\", \"" << group_id.substr(p + 1) << "\") failed; "
<< to_verbose_string(e) << endl;
}
}
}
if (!args_valid) print_desc_and_exit(&desc)();
QApplication app(argc, argv);
app.setQuitOnLastWindowClosed(true);
QMainWindow mw;
Ui::ChatWindow helper;
helper.setupUi(&mw);
auto client = helper.chatwidget->as_actor();
if (!name.empty()) {
send_as(client, client, atom("setName"), move(name));
}
if (gptr) {
send_as(client, client, atom("join"), gptr);
}
mw.show();
auto res = app.exec();
shutdown();
await_all_actors_done();
return res;
}
...@@ -30,9 +30,9 @@ ...@@ -30,9 +30,9 @@
#include "caf/deserializer.hpp" #include "caf/deserializer.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/detail/types_array.hpp"
#include "caf/detail/abstract_uniform_type_info.hpp" #include "caf/detail/abstract_uniform_type_info.hpp"
#include "caf/detail/types_array.hpp"
namespace caf { namespace caf {
namespace detail { namespace detail {
...@@ -42,62 +42,66 @@ using uniform_type_info_ptr = uniform_type_info_ptr; ...@@ -42,62 +42,66 @@ using uniform_type_info_ptr = uniform_type_info_ptr;
// check if there's a 'push_back' that takes a C::value_type // check if there's a 'push_back' that takes a C::value_type
template <class T> template <class T>
char sfinae_has_push_back(T* ptr, typename T::value_type* val = nullptr, char sfinae_has_push_back(T* ptr, typename T::value_type* val = nullptr,
decltype(ptr->push_back(*val)) * = nullptr); decltype(ptr->push_back(*val)) * = nullptr);
long sfinae_has_push_back(void*); // SFNINAE default long sfinae_has_push_back(void*); // SFNINAE default
template <class T> template <class T>
struct is_stl_compliant_list { struct is_stl_compliant_list {
static constexpr bool value = static constexpr bool value =
detail::is_iterable<T>::value && detail::is_iterable<T>::value
sizeof(sfinae_has_push_back(static_cast<T*>(nullptr))) == sizeof(char); && sizeof(sfinae_has_push_back(static_cast<T*>(nullptr))) == sizeof(char);
}; };
// check if there's an 'insert' that takes a C::value_type // check if there's an 'insert' that takes a C::value_type
template <class T> template <class T>
char sfinae_has_insert(T* ptr, typename T::value_type* val = nullptr, char sfinae_has_insert(T* ptr, typename T::value_type* val = nullptr,
decltype(ptr->insert(*val)) * = nullptr); decltype(ptr->insert(*val)) * = nullptr);
long sfinae_has_insert(void*); // SFNINAE default long sfinae_has_insert(void*); // SFNINAE default
template <class T> template <class T>
struct is_stl_compliant_map { struct is_stl_compliant_map {
static constexpr bool value = static constexpr bool value =
detail::is_iterable<T>::value && detail::is_iterable<T>::value
sizeof(sfinae_has_insert(static_cast<T*>(nullptr))) == sizeof(char); && sizeof(sfinae_has_insert(static_cast<T*>(nullptr))) == sizeof(char);
}; };
template <class T> template <class T>
struct is_stl_pair : std::false_type {}; struct is_stl_pair : std::false_type {
// no members
};
template <class F, typename S> template <class F, typename S>
struct is_stl_pair<std::pair<F, S>> : std::true_type {}; struct is_stl_pair<std::pair<F, S>> : std::true_type {
// no members
};
using primitive_impl = std::integral_constant<int, 0>; using primitive_impl = std::integral_constant<int, 0>;
using list_impl = std::integral_constant<int, 1>; using list_impl = std::integral_constant<int, 1>;
using map_impl = std::integral_constant<int, 2>; using map_impl = std::integral_constant<int, 2>;
using pair_impl = std::integral_constant<int, 3>; using pair_impl = std::integral_constant<int, 3>;
using opt_impl = std::integral_constant<int, 4>;
using recursive_impl = std::integral_constant<int, 9>; using recursive_impl = std::integral_constant<int, 9>;
template <class T> template <class T>
constexpr int impl_id() { constexpr int impl_id() {
return detail::is_primitive<T>::value ? return detail::is_primitive<T>::value
0 : ? 0
(is_stl_compliant_list<T>::value ? : (is_stl_compliant_list<T>::value
1 : ? 1
(is_stl_compliant_map<T>::value ? : (is_stl_compliant_map<T>::value
2 : ? 2
(is_stl_pair<T>::value ? 3 : 9))); : (is_stl_pair<T>::value
? 3
: (detail::is_optional<T>::value
? 4
: 9))));
} }
template <class T> template <class T>
struct deconst_pair { struct deconst_pair {
using type = T; using type = T;
}; };
template <class K, typename V> template <class K, typename V>
...@@ -105,13 +109,10 @@ struct deconst_pair<std::pair<K, V>> { ...@@ -105,13 +109,10 @@ struct deconst_pair<std::pair<K, V>> {
using first_type = typename std::remove_const<K>::type; using first_type = typename std::remove_const<K>::type;
using second_type = typename std::remove_const<V>::type; using second_type = typename std::remove_const<V>::type;
using type = std::pair<first_type, second_type>; using type = std::pair<first_type, second_type>;
}; };
class default_serialize_policy { class default_serialize_policy {
public: public:
template <class T> template <class T>
void operator()(const T& val, serializer* s) const { void operator()(const T& val, serializer* s) const {
std::integral_constant<int, impl_id<T>()> token; std::integral_constant<int, impl_id<T>()> token;
...@@ -122,11 +123,9 @@ class default_serialize_policy { ...@@ -122,11 +123,9 @@ class default_serialize_policy {
void operator()(T& val, deserializer* d) const { void operator()(T& val, deserializer* d) const {
std::integral_constant<int, impl_id<T>()> token; std::integral_constant<int, impl_id<T>()> token;
dimpl(val, d, token); dimpl(val, d, token);
// static_types_array<T>::arr[0]->deserialize(&val, d);
} }
private: private:
template <class T> template <class T>
void simpl(const T& val, serializer* s, primitive_impl) const { void simpl(const T& val, serializer* s, primitive_impl) const {
s->write_value(val); s->write_value(val);
...@@ -154,6 +153,15 @@ class default_serialize_policy { ...@@ -154,6 +153,15 @@ class default_serialize_policy {
(*this)(val.second, s); (*this)(val.second, s);
} }
template <class T>
void simpl(const optional<T>& val, serializer* s, opt_impl) const {
uint8_t flag = val ? 1 : 0;
s->write_value(flag);
if (val) {
(*this)(*val, s);
}
}
template <class T> template <class T>
void simpl(const T& val, serializer* s, recursive_impl) const { void simpl(const T& val, serializer* s, recursive_impl) const {
static_types_array<T>::arr[0]->serialize(&val, s); static_types_array<T>::arr[0]->serialize(&val, s);
...@@ -195,19 +203,30 @@ class default_serialize_policy { ...@@ -195,19 +203,30 @@ class default_serialize_policy {
(*this)(storage.second, d); (*this)(storage.second, d);
} }
template <class T>
void dimpl(optional<T>& val, deserializer* d, opt_impl) const {
auto flag = d->read<uint8_t>();
if (flag != 0) {
T tmp;
(*this)(tmp, d);
val = std::move(tmp);
} else {
val = none;
}
}
template <class T> template <class T>
void dimpl(T& storage, deserializer* d, recursive_impl) const { void dimpl(T& storage, deserializer* d, recursive_impl) const {
static_types_array<T>::arr[0]->deserialize(&storage, d); static_types_array<T>::arr[0]->deserialize(&storage, d);
} }
}; };
class forwarding_serialize_policy { class forwarding_serialize_policy {
public: public:
inline forwarding_serialize_policy(uniform_type_info_ptr uti) inline forwarding_serialize_policy(uniform_type_info_ptr uti)
: m_uti(std::move(uti)) {} : m_uti(std::move(uti)) {
// nop
}
template <class T> template <class T>
void operator()(const T& val, serializer* s) const { void operator()(const T& val, serializer* s) const {
...@@ -220,25 +239,25 @@ class forwarding_serialize_policy { ...@@ -220,25 +239,25 @@ class forwarding_serialize_policy {
} }
private: private:
uniform_type_info_ptr m_uti; uniform_type_info_ptr m_uti;
}; };
template <class T, class AccessPolicy, template <class T, class AccessPolicy,
class SerializePolicy = default_serialize_policy, class SerializePolicy = default_serialize_policy,
bool IsEnum = std::is_enum<T>::value, bool IsEnum = std::is_enum<T>::value,
bool IsEmptyType = std::is_class<T>::value&& std::is_empty<T>::value> bool IsEmptyType = std::is_class<T>::value&& std::is_empty<T>::value>
class member_tinfo : public detail::abstract_uniform_type_info<T> { class member_tinfo : public detail::abstract_uniform_type_info<T> {
public: public:
member_tinfo(AccessPolicy apol, SerializePolicy spol) member_tinfo(AccessPolicy apol, SerializePolicy spol)
: m_apol(std::move(apol)), m_spol(std::move(spol)) {} : m_apol(std::move(apol)), m_spol(std::move(spol)) {
// nop
}
member_tinfo(AccessPolicy apol) : m_apol(std::move(apol)) {} member_tinfo(AccessPolicy apol) : m_apol(std::move(apol)) {
// nop
}
member_tinfo() {} member_tinfo() = default;
void serialize(const void* vptr, serializer* s) const override { void serialize(const void* vptr, serializer* s) const override {
m_spol(m_apol(vptr), s); m_spol(m_apol(vptr), s);
...@@ -278,9 +297,7 @@ class member_tinfo<T, A, S, false, true> ...@@ -278,9 +297,7 @@ class member_tinfo<T, A, S, false, true>
// nop // nop
} }
member_tinfo() { member_tinfo() = default;
// nop
}
void serialize(const void*, serializer*) const override { void serialize(const void*, serializer*) const override {
// nop // nop
...@@ -294,16 +311,15 @@ class member_tinfo<T, A, S, false, true> ...@@ -294,16 +311,15 @@ class member_tinfo<T, A, S, false, true>
template <class T, class AccessPolicy, class SerializePolicy> template <class T, class AccessPolicy, class SerializePolicy>
class member_tinfo<T, AccessPolicy, SerializePolicy, true, false> class member_tinfo<T, AccessPolicy, SerializePolicy, true, false>
: public detail::abstract_uniform_type_info<T> { : public detail::abstract_uniform_type_info<T> {
public:
using value_type = typename std::underlying_type<T>::type; using value_type = typename std::underlying_type<T>::type;
public:
member_tinfo(AccessPolicy apol, SerializePolicy spol) member_tinfo(AccessPolicy apol, SerializePolicy spol)
: m_apol(std::move(apol)), m_spol(std::move(spol)) {} : m_apol(std::move(apol)), m_spol(std::move(spol)) {}
member_tinfo(AccessPolicy apol) : m_apol(std::move(apol)) {} member_tinfo(AccessPolicy apol) : m_apol(std::move(apol)) {}
member_tinfo() {} member_tinfo() = default;
void serialize(const void* p, serializer* s) const override { void serialize(const void* p, serializer* s) const override {
auto val = m_apol(p); auto val = m_apol(p);
...@@ -319,18 +335,17 @@ class member_tinfo<T, AccessPolicy, SerializePolicy, true, false> ...@@ -319,18 +335,17 @@ class member_tinfo<T, AccessPolicy, SerializePolicy, true, false>
private: private:
AccessPolicy m_apol; AccessPolicy m_apol;
SerializePolicy m_spol; SerializePolicy m_spol;
}; };
template <class T, class C> template <class T, class C>
class memptr_access_policy { class memptr_access_policy {
public: public:
inline memptr_access_policy(T C::*memptr) : m_memptr(memptr) {
// nop
}
memptr_access_policy(const memptr_access_policy&) = default; memptr_access_policy(const memptr_access_policy&) = default;
memptr_access_policy& operator=(const memptr_access_policy&) = default; memptr_access_policy& operator=(const memptr_access_policy&) = default;
inline memptr_access_policy(T C::*memptr) : m_memptr(memptr) {}
inline T& operator()(void* vptr) const { inline T& operator()(void* vptr) const {
auto ptr = reinterpret_cast<C*>(vptr); auto ptr = reinterpret_cast<C*>(vptr);
return *ptr.*m_memptr; return *ptr.*m_memptr;
...@@ -355,7 +370,6 @@ class memptr_access_policy { ...@@ -355,7 +370,6 @@ class memptr_access_policy {
template <class C, typename GRes, typename SRes, typename SArg> template <class C, typename GRes, typename SRes, typename SArg>
class getter_setter_access_policy { class getter_setter_access_policy {
public: public:
using getter = GRes (C::*)() const; using getter = GRes (C::*)() const;
...@@ -377,15 +391,12 @@ class getter_setter_access_policy { ...@@ -377,15 +391,12 @@ class getter_setter_access_policy {
static constexpr bool grants_mutable_access = false; static constexpr bool grants_mutable_access = false;
private: private:
getter m_get; getter m_get;
setter m_set; setter m_set;
}; };
template <class T> template <class T>
struct fake_access_policy { struct fake_access_policy {
inline T& operator()(void* vptr) const { inline T& operator()(void* vptr) const {
return *reinterpret_cast<T*>(vptr); return *reinterpret_cast<T*>(vptr);
} }
...@@ -400,7 +411,6 @@ struct fake_access_policy { ...@@ -400,7 +411,6 @@ struct fake_access_policy {
} }
static constexpr bool grants_mutable_access = true; static constexpr bool grants_mutable_access = true;
}; };
template <class T, class C> template <class T, class C>
...@@ -436,15 +446,13 @@ uniform_type_info_ptr new_member_tinfo(GRes (C::*getter)() const, ...@@ -436,15 +446,13 @@ uniform_type_info_ptr new_member_tinfo(GRes (C::*getter)() const,
using value_type = typename detail::rm_const_and_ref<GRes>::type; using value_type = typename detail::rm_const_and_ref<GRes>::type;
using tinfo = member_tinfo<value_type, access_policy, using tinfo = member_tinfo<value_type, access_policy,
forwarding_serialize_policy>; forwarding_serialize_policy>;
return uniform_type_info_ptr( return uniform_type_info_ptr(new tinfo(access_policy(getter, setter),
new tinfo(access_policy(getter, setter), std::move(meminf))); std::move(meminf)));
} }
template <class T> template <class T>
class default_uniform_type_info : public detail::abstract_uniform_type_info<T> { class default_uniform_type_info : public detail::abstract_uniform_type_info<T> {
public: public:
template <class... Ts> template <class... Ts>
default_uniform_type_info(Ts&&... args) { default_uniform_type_info(Ts&&... args) {
push_back(std::forward<Ts>(args)...); push_back(std::forward<Ts>(args)...);
...@@ -457,22 +465,24 @@ class default_uniform_type_info : public detail::abstract_uniform_type_info<T> { ...@@ -457,22 +465,24 @@ class default_uniform_type_info : public detail::abstract_uniform_type_info<T> {
void serialize(const void* obj, serializer* s) const override { void serialize(const void* obj, serializer* s) const override {
// serialize each member // serialize each member
for (auto& m : m_members) m->serialize(obj, s); for (auto& m : m_members) {
m->serialize(obj, s);
}
} }
void deserialize(void* obj, deserializer* d) const override { void deserialize(void* obj, deserializer* d) const override {
// deserialize each member // deserialize each member
for (auto& m : m_members) m->deserialize(obj, d); for (auto& m : m_members) {
m->deserialize(obj, d);
}
} }
protected: protected:
bool pod_mems_equals(const T& lhs, const T& rhs) const override { bool pod_mems_equals(const T& lhs, const T& rhs) const override {
return pod_eq(lhs, rhs); return pod_eq(lhs, rhs);
} }
private: private:
template <class C> template <class C>
typename std::enable_if<std::is_pod<C>::value, bool>::type typename std::enable_if<std::is_pod<C>::value, bool>::type
pod_eq(const C& lhs, const C& rhs) const { pod_eq(const C& lhs, const C& rhs) const {
...@@ -488,8 +498,9 @@ class default_uniform_type_info : public detail::abstract_uniform_type_info<T> { ...@@ -488,8 +498,9 @@ class default_uniform_type_info : public detail::abstract_uniform_type_info<T> {
return false; return false;
} }
// terminates recursion inline void push_back() {
inline void push_back() {} // terminate recursion
}
template <class R, class C, class... Ts> template <class R, class C, class... Ts>
void push_back(R C::*memptr, Ts&&... args) { void push_back(R C::*memptr, Ts&&... args) {
...@@ -535,18 +546,17 @@ class default_uniform_type_info : public detail::abstract_uniform_type_info<T> { ...@@ -535,18 +546,17 @@ class default_uniform_type_info : public detail::abstract_uniform_type_info<T> {
} }
std::vector<uniform_type_info_ptr> m_members; std::vector<uniform_type_info_ptr> m_members;
}; };
template <class... Rs> template <class... Rs>
class default_uniform_type_info<typed_actor< class default_uniform_type_info<typed_actor<Rs...>> :
Rs...>> : public detail::abstract_uniform_type_info<typed_actor<Rs...>> { public detail::abstract_uniform_type_info<typed_actor<Rs...>> {
public: public:
using handle_type = typed_actor<Rs...>; using handle_type = typed_actor<Rs...>;
default_uniform_type_info() { sub_uti = uniform_typeid<actor>(); } default_uniform_type_info() {
sub_uti = uniform_typeid<actor>();
}
void serialize(const void* obj, serializer* s) const override { void serialize(const void* obj, serializer* s) const override {
auto tmp = actor_cast<actor>(deref(obj).address()); auto tmp = actor_cast<actor>(deref(obj).address());
...@@ -560,17 +570,13 @@ class default_uniform_type_info<typed_actor< ...@@ -560,17 +570,13 @@ class default_uniform_type_info<typed_actor<
} }
private: private:
const uniform_type_info* sub_uti;
static handle_type& deref(void* ptr) { static handle_type& deref(void* ptr) {
return *reinterpret_cast<handle_type*>(ptr); return *reinterpret_cast<handle_type*>(ptr);
} }
static const handle_type& deref(const void* ptr) { static const handle_type& deref(const void* ptr) {
return *reinterpret_cast<const handle_type*>(ptr); return *reinterpret_cast<const handle_type*>(ptr);
} }
const uniform_type_info* sub_uti;
}; };
} // namespace detail } // namespace detail
......
...@@ -479,6 +479,16 @@ struct type_at<0, T0, Ts...> { ...@@ -479,6 +479,16 @@ struct type_at<0, T0, Ts...> {
using type = T0; using type = T0;
}; };
template <class T>
struct is_optional : std::false_type {
// no members
};
template <class T>
struct is_optional<optional<T>> : std::true_type {
// no members
};
} // namespace detail } // namespace detail
} // namespace caf } // namespace caf
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcaf. *
* libcaf 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. *
* *
* libcaf 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 libcaf. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_ACTOR_WIDGET_MIXIN_HPP
#define CPPA_ACTOR_WIDGET_MIXIN_HPP
#include <QEvent>
#include <QApplication>
#include "caf/actor_companion.hpp"
#include "caf/message_handler.hpp"
#include "caf/policy/sequential_invoke.hpp"
namespace caf {
namespace mixin {
template<typename Base, int EventId = static_cast<int>(QEvent::User + 31337)>
class actor_widget : public Base {
public:
typedef typename actor_companion::message_pointer message_pointer;
struct event_type : public QEvent {
message_pointer mptr;
event_type(message_pointer ptr)
: QEvent(static_cast<QEvent::Type>(EventId)), mptr(std::move(ptr)) { }
};
template<typename... Ts>
actor_widget(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) {
m_invoke.handle_message(m_companion.get(),
ptr->mptr.release(),
m_companion->bhvr_stack().back(),
m_companion->bhvr_stack().back_id());
return true;
}
}
return Base::event(event);
}
actor as_actor() const {
return m_companion;
}
private:
policy::sequential_invoke m_invoke;
actor_companion_ptr m_companion;
};
} // namespace mixin
} // namespace caf
#endif // CPPA_ACTOR_WIDGET_MIXIN_HPP
...@@ -335,28 +335,23 @@ struct to_guard<anything, false> { ...@@ -335,28 +335,23 @@ struct to_guard<anything, false> {
template <class T> template <class T>
struct to_guard<detail::wrapped<T>, false> : to_guard<anything> {}; struct to_guard<detail::wrapped<T>, false> : to_guard<anything> {};
template <class T>
struct is_optional : std::false_type {};
template <class T>
struct is_optional<optional<T>> : std::true_type {};
template <class T> template <class T>
struct to_guard<T, true> { struct to_guard<T, true> {
using ct = typename detail::get_callable_trait<T>::type; using ct = typename detail::get_callable_trait<T>::type;
using arg_types = typename ct::arg_types; using arg_types = typename ct::arg_types;
static_assert(detail::tl_size<arg_types>::value == 1, static_assert(detail::tl_size<arg_types>::value == 1,
"projection/guard must take exactly one argument"); "projection/guard must take exactly one argument");
static_assert(is_optional<typename ct::result_type>::value, static_assert(detail::is_optional<typename ct::result_type>::value,
"projection/guard must return an optional value"); "projection/guard must return an optional value");
using value_type = using value_type =
typename std::conditional< typename std::conditional<
std::is_function<T>::value, std::is_function<T>::value,
T*, T*,
T T
>::type; >::type;
static value_type _(value_type val) { return val; } static value_type _(value_type val) {
return val;
}
}; };
template <class T> template <class T>
......
...@@ -84,14 +84,14 @@ class hook { ...@@ -84,14 +84,14 @@ class hook {
* Called whenever a message is forwarded to a different node. * Called whenever a message is forwarded to a different node.
*/ */
virtual void message_forwarded_cb(const node_id& from, const node_id& dest, virtual void message_forwarded_cb(const node_id& from, const node_id& dest,
std::vector<char>* payload); const std::vector<char>* payload);
/** /**
* Called whenever no route for a forwarding request exists. * Called whenever no route for a forwarding request exists.
*/ */
virtual void message_forwarding_failed_cb(const node_id& from, virtual void message_forwarding_failed_cb(const node_id& from,
const node_id& to, const node_id& to,
std::vector<char>* payload); const std::vector<char>* payload);
/** /**
* Called whenever an actor has been published. * Called whenever an actor has been published.
......
...@@ -32,26 +32,26 @@ namespace caf { ...@@ -32,26 +32,26 @@ namespace caf {
namespace io { namespace io {
template <class ActorHandle, class SocketAcceptor> template <class ActorHandle, class SocketAcceptor>
void publish_impl(ActorHandle whom, SocketAcceptor fd) { void publish_impl(ActorHandle whom, SocketAcceptor fd, uint16_t port) {
using namespace detail; using namespace detail;
auto mm = middleman::instance(); auto mm = middleman::instance();
// we can't move fd into our lambda in C++11 ... // we can't move fd into our lambda in C++11 ...
using pair_type = std::pair<ActorHandle, SocketAcceptor>; using pair_type = std::pair<ActorHandle, SocketAcceptor>;
auto data = std::make_shared<pair_type>(std::move(whom), std::move(fd)); auto data = std::make_shared<pair_type>(whom, std::move(fd));
mm->run_later([mm, data] { mm->run_later([mm, data, whom, port] {
auto bro = mm->get_named_broker<basp_broker>(atom("_BASP")); auto bro = mm->get_named_broker<basp_broker>(atom("_BASP"));
bro->publish(std::move(data->first), std::move(data->second)); bro->publish(std::move(data->first), std::move(data->second));
mm->notify<hook::actor_published>(whom->address(), port);
}); });
} }
inline void publish_impl(abstract_actor_ptr whom, uint16_t port, inline void publish_impl(abstract_actor_ptr whom, uint16_t port,
const char* ipaddr) { const char* ipaddr) {
using namespace detail; using namespace detail;
auto mm = middleman::instance(); auto mm = middleman::instance();
auto addr = whom->address();
network::default_socket_acceptor fd{mm->backend()}; network::default_socket_acceptor fd{mm->backend()};
network::ipv4_bind(fd, port, ipaddr); network::ipv4_bind(fd, port, ipaddr);
publish_impl(std::move(whom), std::move(fd)); publish_impl(std::move(whom), std::move(fd), port);
} }
} // namespace io } // namespace io
......
...@@ -261,9 +261,10 @@ basp_broker::handle_basp_header(connection_context& ctx, ...@@ -261,9 +261,10 @@ basp_broker::handle_basp_header(connection_context& ctx,
if (hdr.dest_node != invalid_node_id && hdr.dest_node != node()) { if (hdr.dest_node != invalid_node_id && hdr.dest_node != node()) {
auto route = get_route(hdr.dest_node); auto route = get_route(hdr.dest_node);
if (route.invalid()) { if (route.invalid()) {
// TODO: signalize that we don't have route to given node
CAF_LOG_INFO("message dropped: no route to node " CAF_LOG_INFO("message dropped: no route to node "
<< to_string(hdr.dest_node)); << to_string(hdr.dest_node));
parent().notify<hook::message_forwarding_failed>(hdr.source_node,
hdr.dest_node, payload);
return close_connection; return close_connection;
} }
auto& buf = wr_buf(route.hdl); auto& buf = wr_buf(route.hdl);
...@@ -271,6 +272,8 @@ basp_broker::handle_basp_header(connection_context& ctx, ...@@ -271,6 +272,8 @@ basp_broker::handle_basp_header(connection_context& ctx,
write(bs, hdr); write(bs, hdr);
if (payload) buf.insert(buf.end(), payload->begin(), payload->end()); if (payload) buf.insert(buf.end(), payload->begin(), payload->end());
flush(route.hdl); flush(route.hdl);
parent().notify<hook::message_forwarded>(hdr.source_node,
hdr.dest_node, payload);
return await_header; return await_header;
} }
// handle a message that is addressed to us // handle a message that is addressed to us
...@@ -334,6 +337,7 @@ basp_broker::handle_basp_header(connection_context& ctx, ...@@ -334,6 +337,7 @@ basp_broker::handle_basp_header(connection_context& ctx,
CAF_LOG_INFO("multiple incoming connections from the same node"); CAF_LOG_INFO("multiple incoming connections from the same node");
return close_connection; return close_connection;
} }
parent().notify<hook::new_connection_established>(ctx.remote_id );
break; break;
} }
case basp::server_handshake: { case basp::server_handshake: {
...@@ -427,6 +431,7 @@ basp_broker::handle_basp_header(connection_context& ctx, ...@@ -427,6 +431,7 @@ basp_broker::handle_basp_header(connection_context& ctx,
ctx.published_actor = proxy; ctx.published_actor = proxy;
ctx.handshake_data->result->set_value(std::move(proxy)); ctx.handshake_data->result->set_value(std::move(proxy));
ctx.handshake_data = nullptr; ctx.handshake_data = nullptr;
parent().notify<hook::new_connection_established>(nid);
break; break;
} }
} }
...@@ -516,6 +521,7 @@ void basp_broker::erase_proxy(const id_type& nid, actor_id aid) { ...@@ -516,6 +521,7 @@ void basp_broker::erase_proxy(const id_type& nid, actor_id aid) {
void basp_broker::add_route(const id_type& nid, connection_handle hdl) { void basp_broker::add_route(const id_type& nid, connection_handle hdl) {
if (m_blacklist.count(std::make_pair(nid, hdl)) == 0) { if (m_blacklist.count(std::make_pair(nid, hdl)) == 0) {
parent().notify<hook::new_route_added>(m_current_context->remote_id, nid);
m_routes[nid].second.insert({hdl, nid}); m_routes[nid].second.insert({hdl, nid});
} }
} }
......
...@@ -41,7 +41,7 @@ void hook::message_sent_cb(const actor_addr& from, const node_id& dest_node, ...@@ -41,7 +41,7 @@ void hook::message_sent_cb(const actor_addr& from, const node_id& dest_node,
} }
void hook::message_forwarded_cb(const node_id& from, const node_id& dest, void hook::message_forwarded_cb(const node_id& from, const node_id& dest,
std::vector<char>* payload) { const std::vector<char>* payload) {
call_next<message_forwarded>(from, dest, payload); call_next<message_forwarded>(from, dest, payload);
} }
...@@ -53,7 +53,7 @@ void hook::message_sending_failed_cb(const actor_addr& from, ...@@ -53,7 +53,7 @@ void hook::message_sending_failed_cb(const actor_addr& from,
} }
void hook::message_forwarding_failed_cb(const node_id& from, const node_id& to, void hook::message_forwarding_failed_cb(const node_id& from, const node_id& to,
std::vector<char>* payload) { const std::vector<char>* payload) {
call_next<message_forwarding_failed>(from, to, payload); call_next<message_forwarding_failed>(from, to, payload);
} }
......
#include <vector>
#include <iomanip>
#include <cassert>
#include <iostream>
#include <algorithm>
#include "test.hpp"
#include "cppa/cppa.hpp"
#include "cppa/opencl.hpp"
using namespace std;
using namespace cppa;
using namespace cppa::opencl;
namespace {
using ivec = vector<int>;
using fvec = vector<float>;
constexpr size_t matrix_size = 4;
constexpr size_t array_size = 32;
constexpr int magic_number = 23;
constexpr const char* kernel_name = "matrix_square";
constexpr const char* kernel_name_compiler_flag = "compiler_flag";
constexpr const char* kernel_name_reduce = "reduce";
constexpr const char* kernel_name_const = "const_mod";
constexpr const char* compiler_flag = "-D OPENCL_CPPA_TEST_FLAG";
constexpr const char* kernel_source = R"__(
__kernel void matrix_square(__global int* matrix,
__global int* output) {
size_t size = get_global_size(0); // == get_global_size_(1);
size_t x = get_global_id(0);
size_t y = get_global_id(1);
int result = 0;
for (size_t idx = 0; idx < size; ++idx) {
result += matrix[idx + y * size] * matrix[x + idx * size];
}
output[x + y * size] = result;
}
)__";
constexpr const char* kernel_source_error = R"__(
__kernel void missing(__global int*) {
size_t semicolon
}
)__";
constexpr const char* kernel_source_compiler_flag = R"__(
__kernel void compiler_flag(__global int* input,
__global int* output) {
size_t x = get_global_id(0);
#ifdef OPENCL_CPPA_TEST_FLAG
output[x] = input[x];
#else
output[x] = 0;
#endif
}
)__";
// http://developer.amd.com/resources/documentation-articles/articles-whitepapers/
// opencl-optimization-case-study-simple-reductions
constexpr const char* kernel_source_reduce = R"__(
__kernel void reduce(__global int* buffer,
__global int* result) {
__local int scratch[512];
int local_index = get_local_id(0);
scratch[local_index] = buffer[get_global_id(0)];
barrier(CLK_LOCAL_MEM_FENCE);
for(int offset = get_local_size(0) / 2; offset > 0; offset = offset / 2) {
if (local_index < offset) {
int other = scratch[local_index + offset];
int mine = scratch[local_index];
scratch[local_index] = (mine < other) ? mine : other;
}
barrier(CLK_LOCAL_MEM_FENCE);
}
if (local_index == 0) {
result[get_group_id(0)] = scratch[0];
}
}
)__";
constexpr const char* kernel_source_const = R"__(
__kernel void const_mod(__constant int* input,
__global int* output) {
size_t idx = get_global_id(0);
output[idx] = input[0];
}
)__";
}
template<size_t Size>
class square_matrix {
public:
static constexpr size_t num_elements = Size * Size;
static void announce() {
cppa::announce<square_matrix>(&square_matrix::m_data);
}
square_matrix(square_matrix&&) = default;
square_matrix(const square_matrix&) = default;
square_matrix& operator=(square_matrix&&) = default;
square_matrix& operator=(const square_matrix&) = default;
square_matrix() : m_data(num_elements) { }
explicit square_matrix(ivec d) : m_data(move(d)) {
assert(m_data.size() == num_elements);
}
inline float& operator()(size_t column, size_t row) {
return m_data[column + row * Size];
}
inline const float& operator()(size_t column, size_t row) const {
return m_data[column + row * Size];
}
inline void iota_fill() {
iota(m_data.begin(), m_data.end(), 0);
}
typedef typename ivec::const_iterator const_iterator;
const_iterator begin() const { return m_data.begin(); }
const_iterator end() const { return m_data.end(); }
ivec& data() { return m_data; }
const ivec& data() const { return m_data; }
void data(ivec new_data) { m_data = std::move(new_data); }
private:
ivec m_data;
};
template<size_t Size>
inline bool operator==(const square_matrix<Size>& lhs,
const square_matrix<Size>& rhs) {
return equal(lhs.begin(), lhs.end(), rhs.begin());
}
template<size_t Size>
inline bool operator!=(const square_matrix<Size>& lhs,
const square_matrix<Size>& rhs) {
return !(lhs == rhs);
}
using matrix_type = square_matrix<matrix_size>;
size_t get_max_workgroup_size(size_t device_id, size_t dimension) {
size_t max_size = 512;
auto devices = get_opencl_metainfo()->get_devices()[device_id];
size_t dimsize = devices.get_max_work_items_per_dim()[dimension];
return max_size < dimsize ? max_size : dimsize;
}
void test_opencl() {
scoped_actor self;
const ivec expected1{ 56, 62, 68, 74
, 152, 174, 196, 218
, 248, 286, 324, 362
, 344, 398, 452, 506};
auto worker1 = spawn_cl<ivec(ivec&)>(program::create(kernel_source),
kernel_name,
{matrix_size, matrix_size});
ivec m1(matrix_size * matrix_size);
iota(begin(m1), end(m1), 0);
self->send(worker1, move(m1));
self->receive (
on_arg_match >> [&] (const ivec& result) {
CPPA_CHECK(equal(begin(expected1), end(expected1), begin(result)));
}
);
auto worker2 = spawn_cl<ivec(ivec&)>(kernel_source,
kernel_name,
{matrix_size, matrix_size});
ivec m2(matrix_size * matrix_size);
iota(begin(m2), end(m2), 0);
self->send(worker2, move(m2));
self->receive (
on_arg_match >> [&] (const ivec& result) {
CPPA_CHECK(equal(begin(expected1), end(expected1), begin(result)));
}
);
const matrix_type expected2(move(expected1));
auto map_args = [] (any_tuple msg) -> optional<cow_tuple<ivec>> {
auto opt = tuple_cast<matrix_type>(msg);
if (opt) {
return make_cow_tuple(move(get_ref<0>(*opt).data()));
}
return none;
};
auto map_results = [] (ivec& result) -> any_tuple {
return make_any_tuple(matrix_type{move(result)});
};
matrix_type m3;
m3.iota_fill();
auto worker3 = spawn_cl(program::create(kernel_source), kernel_name,
map_args, map_results,
{matrix_size, matrix_size});
self->send(worker3, move(m3));
self->receive (
on_arg_match >> [&] (const matrix_type& result) {
CPPA_CHECK(expected2 == result);
}
);
matrix_type m4;
m4.iota_fill();
auto worker4 = spawn_cl(kernel_source, kernel_name,
map_args, map_results,
{matrix_size, matrix_size}
);
self->send(worker4, move(m4));
self->receive (
on_arg_match >> [&] (const matrix_type& result) {
CPPA_CHECK(expected2 == result);
}
);
try {
program create_error = program::create(kernel_source_error);
}
catch (const exception& exc) {
cout << exc.what() << endl;
CPPA_CHECK_EQUAL("clBuildProgram: CL_BUILD_PROGRAM_FAILURE", exc.what());
}
// test for opencl compiler flags
ivec arr5(array_size);
iota(begin(arr5), end(arr5), 0);
auto prog5 = program::create(kernel_source_compiler_flag, compiler_flag);
auto worker5 = spawn_cl<ivec(ivec&)>(prog5, kernel_name_compiler_flag, {array_size});
self->send(worker5, move(arr5));
ivec expected3(array_size);
iota(begin(expected3), end(expected3), 0);
self->receive (
on_arg_match >> [&] (const ivec& result) {
CPPA_CHECK(equal(begin(expected3), end(expected3), begin(result)));
}
);
// test for manuel return size selection
const int max_workgroup_size = static_cast<int>(get_max_workgroup_size(0,1)); // max workgroup size (1d)
const size_t reduce_buffer_size = max_workgroup_size * 8;
const size_t reduce_local_size = max_workgroup_size;
const size_t reduce_work_groups = reduce_buffer_size / reduce_local_size;
const size_t reduce_global_size = reduce_buffer_size;
const size_t reduce_result_size = reduce_work_groups;
ivec arr6(reduce_buffer_size);
int n{static_cast<int>(arr6.capacity())};
generate(begin(arr6), end(arr6), [&]{ return --n; });
auto worker6 = spawn_cl<ivec(ivec&)>(kernel_source_reduce,
kernel_name_reduce,
{reduce_global_size},
{},
{reduce_local_size},
reduce_result_size);
self->send(worker6, move(arr6));
const ivec expected4{ max_workgroup_size * 7, max_workgroup_size * 6,
max_workgroup_size * 5, max_workgroup_size * 4,
max_workgroup_size * 3, max_workgroup_size * 2,
max_workgroup_size, 0 };
self->receive (
on_arg_match >> [&] (const ivec& result) {
CPPA_CHECK(equal(begin(expected4), end(expected4), begin(result)));
}
);
// constant memory arguments
const ivec arr7{magic_number};
auto worker7 = spawn_cl<ivec(ivec&)>(kernel_source_const,
kernel_name_const,
{magic_number});
self->send(worker7, move(arr7));
ivec expected5(magic_number);
fill(begin(expected5), end(expected5), magic_number);
self->receive(
on_arg_match >> [&] (const ivec& result) {
CPPA_CHECK(equal(begin(expected5), end(expected5), begin(result)));
}
);
}
int main() {
CPPA_TEST(tkest_opencl);
announce<ivec>();
matrix_type::announce();
test_opencl();
await_all_actors_done();
shutdown();
return CPPA_TEST_RESULT();
}
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