Commit 7c67a86d authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'develop'

parents 14467ae0 99fcd2b1
......@@ -22,6 +22,9 @@ endif()
if(NOT CAF_BUILD_STATIC)
set(CAF_BUILD_STATIC no)
endif()
if(NOT CAF_NO_OPENCL)
set(CAF_NO_OPENCL no)
endif()
################################################################################
......@@ -98,31 +101,83 @@ if(NOT WIN32 AND NOT NO_COMPILER_CHECK)
"or is not supported")
endif()
endif()
# set optional build flags
set(EXTRA_FLAGS "")
# add "-Werror" flag if --pedantic-build is used
if(CXX_WARNINGS_AS_ERROS)
set(EXTRA_FLAGS "-Werror")
endif()
# enable a ton of warnings if --more-clang-warnings is used
if(MORE_WARNINGS)
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(WFLAGS "-Weverything -Wno-c++98-compat -Wno-padded "
"-Wno-documentation-unknown-command -Wno-exit-time-destructors "
"-Wno-global-constructors -Wno-missing-prototypes "
"-Wno-c++98-compat-pedantic -Wno-unused-member-function "
"-Wno-unused-const-variable -Wno-switch-enum "
"-Wno-missing-noreturn -Wno-covered-switch-default")
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
set(WFLAGS "-Waddress -Wall -Warray-bounds "
"-Wattributes -Wbuiltin-macro-redefined -Wcast-align "
"-Wcast-qual -Wchar-subscripts -Wclobbered -Wcomment "
"-Wconversion -Wconversion-null -Wcoverage-mismatch "
"-Wcpp -Wdelete-non-virtual-dtor -Wdeprecated "
"-Wdeprecated-declarations -Wdiv-by-zero -Wdouble-promotion "
"-Wempty-body -Wendif-labels -Wenum-compare -Wextra "
"-Wfloat-equal -Wformat -Wfree-nonheap-object "
"-Wignored-qualifiers -Winit-self "
"-Winline -Wint-to-pointer-cast -Winvalid-memory-model "
"-Winvalid-offsetof -Wlogical-op -Wmain -Wmaybe-uninitialized "
"-Wmissing-braces -Wmissing-field-initializers -Wmultichar "
"-Wnarrowing -Wnoexcept -Wnon-template-friend "
"-Wnon-virtual-dtor -Wnonnull -Woverflow "
"-Woverlength-strings -Wparentheses "
"-Wpmf-conversions -Wpointer-arith -Wreorder "
"-Wreturn-type -Wsequence-point -Wshadow "
"-Wsign-compare -Wswitch -Wtype-limits -Wundef "
"-Wuninitialized -Wunused -Wvla -Wwrite-strings")
endif()
# convert CMake list to a single string, erasing the ";" separators
string(REPLACE ";" "" WFLAGS_STR ${WFLAGS})
set(EXTRA_FLAGS "${EXTRA_FLAGS} ${WFLAGS_STR}")
endif()
# add -stdlib=libc++ when using Clang
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
message(STATUS "NOTE: Automatically added -stdlib=libc++ flag, "
"you can override this by defining CMAKE_CXX_FLAGS "
"(see 'configure --help')")
set(EXTRA_FLAGS "${EXTRA_FLAGS} -stdlib=libc++")
endif()
# enable address sanitizer if requested by the user
if(ENABLE_ADDRESS_SANITIZER)
# check whether address sanitizer is available
set(CXXFLAGS_BACKUP "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "-fsanitize=address -fno-omit-frame-pointer")
try_run(ProgramResult
CompilationSucceeded
"${CMAKE_BINARY_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/get_compiler_version.cpp")
if(NOT CompilationSucceeded)
message(WARNING "Address Sanitizer is not available on selected compiler")
else()
message(STATUS "Enable Address Sanitizer")
set(EXTRA_FLAGS "${EXTRA_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
endif()
# restore CXX flags
set(CMAKE_CXX_FLAGS "${CXXFLAGS_BACKUP}")
endif(ENABLE_ADDRESS_SANITIZER)
# -pthread is ignored on MacOSX but required on other platforms
if(NOT APPLE AND NOT WIN32)
set(EXTRA_FLAGS "${EXTRA_FLAGS} -pthread")
endif()
# check if the user provided CXXFLAGS, set defaults otherwise
if(CMAKE_CXX_FLAGS)
set(CXXFLAGS_PROVIDED true)
set(CMAKE_CXX_FLAGS_DEBUG "")
set(CMAKE_CXX_FLAGS_MINSIZEREL "")
set(CMAKE_CXX_FLAGS_RELEASE "")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "")
else()
set(CXXFLAGS_PROVIDED false)
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
message(STATUS "NOTE: Automatically added -stdlib=libc++ flag, "
"you can override this by defining CMAKE_CXX_FLAGS "
"(see 'configure --help')")
set(CMAKE_CXX_FLAGS "-std=c++11 -stdlib=libc++ -fPIC")
if(MORE_CLANG_WARNINGS)
set(CMAKE_CXX_FLAGS "-pedantic -Weverything -Wno-c++98-compat "
"-Wno-padded -Wno-documentation-unknown-command "
"-Wno-exit-time-destructors -Wno-global-constructors "
"-Wno-missing-prototypes -Wno-c++98-compat-pedantic "
"-Wno-unused-member-function "
"-Wno-unused-const-variable")
endif()
else()
set(CMAKE_CXX_FLAGS "-std=c++11 -Wextra -Wall -pedantic -fPIC")
endif()
set(CMAKE_CXX_FLAGS "-std=c++11 -Wextra -Wall -pedantic -fPIC ${EXTRA_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
......@@ -132,16 +187,6 @@ endif()
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif()
# enable clang's address sanitizer if requested by the user
if(ENABLE_ADDRESS_SANITIZER)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
message(STATUS "Enable address sanitizer")
endif(ENABLE_ADDRESS_SANITIZER)
# -pthread is ignored on MacOSX, enable it for all other platforms
if(NOT APPLE AND NOT WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()
# extra setup steps needed on MinGW
if(MINGW)
add_definitions(-D_WIN32_WINNT=0x0600)
......@@ -184,7 +229,7 @@ install(DIRECTORY libcaf_core/cppa/
install(DIRECTORY libcaf_io/caf/ DESTINATION include/caf
FILES_MATCHING PATTERN "*.hpp")
# install includes from opencl
if(EXISTS "${CMAKE_SOURCE_DIR}/libcaf_opencl/caf")
if(EXISTS "${CMAKE_SOURCE_DIR}/libcaf_opencl/CMakeLists.txt")
install(DIRECTORY libcaf_opencl/caf/ DESTINATION include/caf
FILES_MATCHING PATTERN "*.hpp")
endif()
......@@ -208,7 +253,7 @@ set(LIBCAF_INCLUDE_DIRS
"${CMAKE_SOURCE_DIR}/libcaf_core"
"${CMAKE_SOURCE_DIR}/libcaf_io")
# path to caf opencl headers
if(EXISTS "${CMAKE_SOURCE_DIR}/libcaf_opencl/caf")
if(EXISTS "${CMAKE_SOURCE_DIR}/libcaf_opencl/CMakeLists.txt")
set(LIBCAF_INCLUDE_DIRS
"${CMAKE_SOURCE_DIR}/libcaf_opencl/" "${LIBCAF_INCLUDE_DIRS}")
endif()
......@@ -230,7 +275,7 @@ add_subdirectory(libcaf_io)
# set io lib for sub directories
set(LIBCAF_IO_LIBRARY libcaf_io)
# 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/CMakeLists.txt")
message(STATUS "Enter subdirectory libcaf_opencl")
find_package(OPENCL REQUIRED)
add_subdirectory(libcaf_opencl)
......@@ -253,7 +298,7 @@ if(NOT CAF_NO_UNIT_TESTS)
message(STATUS "Enter subdirectory unit_testing")
add_subdirectory(unit_testing)
add_dependencies(all_unit_tests libcaf_io)
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/CMakeLists.txt")
add_subdirectory(libcaf_opencl/unit_testing)
endif()
endif()
......@@ -262,13 +307,13 @@ if(NOT CAF_NO_EXAMPLES)
message(STATUS "Enter subdirectory examples")
add_subdirectory(examples)
add_dependencies(all_examples libcaf_io)
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/CMakeLists.txt")
add_subdirectory(libcaf_opencl/examples)
add_dependencies(opencl_examples libcaf_opencl)
endif()
endif()
# build RIAC if not being told otherwise
if(NOT CAF_NO_RIAC AND EXISTS "${CMAKE_SOURCE_DIR}/libcaf_riac/caf/")
if(NOT CAF_NO_RIAC AND EXISTS "${CMAKE_SOURCE_DIR}/libcaf_riac/CMakeLists.txt")
message(STATUS "Enter subdirectory probe")
add_subdirectory(libcaf_riac)
if(CAF_BUILD_STATIC_ONLY OR CAF_BUILD_STATIC)
......@@ -288,7 +333,7 @@ else()
set(CAF_HAS_RIAC no)
endif()
# build nexus if not being told otherwise
if(NOT CAF_NO_NEXUS AND EXISTS "${CMAKE_SOURCE_DIR}/nexus/caf/")
if(NOT CAF_NO_NEXUS AND EXISTS "${CMAKE_SOURCE_DIR}/nexus/CMakeLists.txt")
if(NOT CAF_HAS_RIAC)
message(WARNING "cannot build nexus without RIAC submodule")
set(CAF_NO_NEXUS yes)
......@@ -307,7 +352,7 @@ else()
set(CAF_NO_NEXUS yes)
endif()
# build cash if not being told otherwise
if(NOT CAF_NO_CASH AND EXISTS "${CMAKE_SOURCE_DIR}/cash/caf/")
if(NOT CAF_NO_CASH AND EXISTS "${CMAKE_SOURCE_DIR}/cash/CMakeLists.txt")
if(NOT CAF_HAS_RIAC)
message(WARNING "cannot build cash without RIAC submodule")
set(CAF_NO_CASH yes)
......@@ -326,7 +371,7 @@ else()
set(CAF_NO_CASH yes)
endif()
# 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/CMakeLists.txt")
message(STATUS "Enter subdirectory benchmarks")
add_subdirectory(benchmarks)
add_dependencies(all_benchmarks libcaf_io)
......@@ -363,6 +408,12 @@ if(DOXYGEN_FOUND)
endif(DOXYGEN_FOUND)
################################################################################
# Add additional project files to GUI #
################################################################################
add_custom_target(gui_dummy SOURCES configure)
################################################################################
# print summary #
################################################################################
......
Subproject commit ed985aed8bbd0f3eb6c149beff01a5a32276433f
Subproject commit 725fb2bee0e24fe8dce73d1c3896f72f7be2424b
Subproject commit 8d709e6da3796161680c726802ea6152e88eaf08
Subproject commit 429df03e9483483b9fe78a6676b67c5407b5ac11
......@@ -19,6 +19,8 @@ if [ -d "$sourcedir/benchmarks/caf" ] ; then
benchmark_suite_options="\
Benchmark Suite Options:
--with-javac=FILE path to Java compiler
--with-java=FILE path to Java Runtime
--with-scalac=FILE path to Scala compiler
--with-erlc=FILE path to Erlang compiler
--with-charmc=FILE path to Charm++ compiler
......@@ -43,8 +45,9 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
--dual-build build using both gcc and clang
--build-static build as static and shared library
--build-static-only build as static library only
--more-clang-warnings enables most of Clang's warning flags
--more-warnings enables most warnings
--no-compiler-check disable compiler version check
--warnings-as-errors enables -Werror
Installation Directories:
--prefix=PREFIX installation directory [/usr/local]
......@@ -73,8 +76,7 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
- INFO
- DEBUG
- TRACE
(implicitly sets --enable-debug)
--enable-address-sanitizer build with Clang's address sanitizer
--with-address-sanitizer build with address sanitizer if available
Influential Environment Variables (only on first invocation):
CXX C++ compiler command
......@@ -88,7 +90,16 @@ $benchmark_suite_options"
# $3 is the cache entry variable value
append_cache_entry ()
{
CMakeCacheEntries="$CMakeCacheEntries -D $1:$2=$3"
case "$3" in
*\ * )
# string contains whitespace
CMakeCacheEntries="$CMakeCacheEntries -D \"$1:$2=$3\""
;;
*)
# string contains whitespace
CMakeCacheEntries="$CMakeCacheEntries -D $1:$2=$3"
;;
esac
}
# Creates a build directory via CMake.
......@@ -99,6 +110,7 @@ append_cache_entry ()
# $5 is the CMake generator.
configure ()
{
CMakeCacheEntries=$CMakeDefaultCache
if [ -n "$1" ]; then
......@@ -135,23 +147,23 @@ configure ()
append_cache_entry LIBRARY_OUTPUT_PATH PATH "$absolute_builddir/lib"
fi
if [ -d $workdir ]; then
if [ -d "$workdir" ]; then
# If a build directory exists, check if it has a CMake cache.
if [ -f $workdir/CMakeCache.txt ]; then
if [ -f "$workdir/CMakeCache.txt" ]; then
# If the CMake cache exists, delete it so that this configuration
# is not tainted by a previous one.
rm -f $workdir/CMakeCache.txt
rm -f "$workdir/CMakeCache.txt"
fi
else
mkdir -p $workdir
mkdir -p "$workdir"
fi
cd $workdir
cd "$workdir"
if [ -n "$5" ]; then
cmake -G "$5" $CMakeCacheEntries $sourcedir
cmake -G "$5" $CMakeCacheEntries "$sourcedir"
else
cmake $CMakeCacheEntries $sourcedir
cmake $CMakeCacheEntries "$sourcedir"
fi
echo "# This is the command used to configure this build" > config.status
......@@ -204,6 +216,10 @@ while [ $# -ne 0 ]; do
append_cache_entry CAF_ENABLE_RUNTIME_CHECKS BOOL yes
;;
--enable-address-sanitizer)
echo "*** warning: --enable-address-sanitizer is deprecated, please use --with-address-sanitizer instead"
append_cache_entry ENABLE_ADDRESS_SANITIZER BOOL yes
;;
--with-address-sanitizer)
append_cache_entry ENABLE_ADDRESS_SANITIZER BOOL yes
;;
--no-memory-management)
......@@ -216,12 +232,15 @@ while [ $# -ne 0 ]; do
--standalone-build)
echo "*** WARNING: --standalone-build is deprecated"
;;
--more-clang-warnings)
append_cache_entry MORE_CLANG_WARNINGS BOOL yes
--more-warnings)
append_cache_entry MORE_WARNINGS BOOL yes
;;
--no-compiler-check)
append_cache_entry NO_COMPILER_CHECK BOOL yes
;;
--warnings-as-errors)
append_cache_entry CXX_WARNINGS_AS_ERROS BOOL yes
;;
--with-log-level=*)
level=`echo "$optarg" | tr '[:lower:]' '[:upper:]'`
case $level in
......@@ -256,40 +275,46 @@ while [ $# -ne 0 ]; do
append_cache_entry CMAKE_BUILD_TYPE STRING $optarg
;;
--build-dir=*)
builddir=$optarg
builddir="$optarg"
;;
--bin-dir=*)
bindir=$optarg
bindir="$optarg"
;;
--lib-dir=*)
libdir=$optarg
libdir="$optarg"
;;
--dual-build)
dualbuild=1
;;
--no-examples)
append_cache_entry CAF_NO_EXAMPLES STRING yes
append_cache_entry CAF_NO_EXAMPLES BOOL yes
;;
--no-qt-examples)
append_cache_entry CAF_NO_QT_EXAMPLES STRING yes
append_cache_entry CAF_NO_QT_EXAMPLES BOOL yes
;;
--no-protobuf-examples)
append_cache_entry CAF_NO_PROTOBUF_EXAMPLES STRING yes
append_cache_entry CAF_NO_PROTOBUF_EXAMPLES BOOL yes
;;
--no-curl-examples)
append_cache_entry CAF_NO_CURL_EXAMPLES STRING yes
append_cache_entry CAF_NO_CURL_EXAMPLES BOOL yes
;;
--no-unit-tests)
append_cache_entry CAF_NO_UNIT_TESTS STRING yes
append_cache_entry CAF_NO_UNIT_TESTS BOOL yes
;;
--no-opencl)
append_cache_entry CAF_NO_OPENCL STRING yes
append_cache_entry CAF_NO_OPENCL BOOL yes
;;
--build-static)
append_cache_entry CAF_BUILD_STATIC STRING yes
append_cache_entry CAF_BUILD_STATIC BOOL yes
;;
--build-static-only)
append_cache_entry CAF_BUILD_STATIC_ONLY STRING yes
append_cache_entry CAF_BUILD_STATIC_ONLY BOOL yes
;;
--with-javac=*)
append_cache_entry CAF_JAVA_COMPILER FILEPATH "$optarg"
;;
--with-java=*)
append_cache_entry CAF_JAVA_BIN FILEPATH "$optarg"
;;
--with-scalac=*)
append_cache_entry CAF_SCALA_COMPILER FILEPATH "$optarg"
......
......@@ -107,6 +107,7 @@ if(NOT CAF_NO_CURL_EXAMPLES)
find_package(CURL)
if(CURL_FOUND)
add_executable(curl_fuse curl/curl_fuse.cpp)
include_directories(${CURL_INCLUDE_DIRS})
target_link_libraries(curl_fuse ${CMAKE_DL_LIBS} ${LIBCAF_LIBRARIES} ${PTHREAD_LIBRARIES} ${CURL_LIBRARY})
add_dependencies(curl_fuse all_examples)
endif(CURL_FOUND)
......
......@@ -67,12 +67,25 @@ void write_int(broker* self, connection_handle hdl, T value) {
self->flush(hdl);
}
void write_int(broker* self, connection_handle hdl, uint64_t value) {
// write two uint32 values instead (htonl does not work for 64bit integers)
write_int(self, hdl, static_cast<uint32_t>(value));
write_int(self, hdl, static_cast<uint32_t>(value >> sizeof(uint32_t)));
}
// utility function for reading an ingeger from incoming data
template <class T>
T read_int(const void* data) {
T value;
memcpy(&value, data, sizeof(T));
return static_cast<T>(ntohl(value));
void read_int(const void* data, T& storage) {
memcpy(&storage, data, sizeof(T));
storage = static_cast<T>(ntohl(storage));
}
void read_int(const void* data, uint64_t& storage) {
uint32_t first;
uint32_t second;
read_int(data, first);
read_int(reinterpret_cast<const char*>(data) + sizeof(uint32_t), second);
storage = first | (static_cast<uint64_t>(second) << sizeof(uint32_t));
}
// implemenation of our broker
......@@ -115,12 +128,14 @@ behavior broker_impl(broker* self, connection_handle hdl, const actor& buddy) {
},
[=](const new_data_msg& msg) {
// read the atom value as uint64_t from buffer
auto atm_val = read_int<uint64_t>(msg.buf.data());
uint64_t atm_val;
read_int(msg.buf.data(), atm_val);
// cast to original type
auto atm = static_cast<atom_value>(atm_val);
// read integer value from buffer, jumping to the correct
// position via offset_data(...)
auto ival = read_int<int32_t>(msg.buf.data() + sizeof(uint64_t));
int32_t ival;
read_int(msg.buf.data() + sizeof(uint64_t), ival);
// show some output
aout(self) << "received {" << to_string(atm) << ", " << ival << "}"
<< endl;
......
......@@ -38,6 +38,7 @@
// C++ includes
#include <string>
#include <vector>
#include <random>
#include <iostream>
// libcurl
......@@ -46,7 +47,7 @@
// libcaf
#include "caf/all.hpp"
// disable some clang warnings here caused by CURL and srand(time(nullptr))
// disable some clang warnings here caused by CURL
#ifdef __clang__
# pragma clang diagnostic ignored "-Wshorten-64-to-32"
# pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
......@@ -101,6 +102,8 @@ class base_actor : public event_based_actor {
// nop
}
~base_actor();
inline actor_ostream& print() {
return m_out << m_color << m_name << " (id = " << id() << "): ";
}
......@@ -117,6 +120,10 @@ class base_actor : public event_based_actor {
actor_ostream m_out;
};
base_actor::~base_actor() {
// avoid weak-vtables warning
}
// encapsulates an HTTP request
class client_job : public base_actor {
public:
......@@ -125,6 +132,8 @@ class client_job : public base_actor {
// nop
}
~client_job();
protected:
behavior make_behavior() override {
print() << "init" << color::reset_endl;
......@@ -149,15 +158,24 @@ class client_job : public base_actor {
}
};
client_job::~client_job() {
// avoid weak-vtables warning
}
// spawns HTTP requests
class client : public base_actor {
public:
client(const actor& parent)
: base_actor(parent, "client", color::green), m_count(0) {
: base_actor(parent, "client", color::green),
m_count(0),
m_re(m_rd()),
m_dist(min_req_interval, max_req_interval) {
// nop
}
~client();
protected:
behavior make_behavior() override {
using std::chrono::milliseconds;
......@@ -175,7 +193,7 @@ class client : public base_actor {
// and should thus be spawned in a separate thread
spawn<client_job, detached+linked>(m_parent);
// compute random delay until next job is launched
auto delay = (rand() + min_req_interval) % max_req_interval;
auto delay = m_dist(m_re);
delayed_send(this, milliseconds(delay), atom("next"));
}
);
......@@ -183,17 +201,25 @@ class client : public base_actor {
private:
size_t m_count;
std::random_device m_rd;
std::default_random_engine m_re;
std::uniform_int_distribution<int> m_dist;
};
client::~client() {
// avoid weak-vtables warning
}
// manages a CURL session
class curl_worker : public base_actor {
public:
curl_worker(const actor& parent)
: base_actor(parent, "curl_worker", color::yellow) {
// nop
}
~curl_worker();
protected:
behavior make_behavior() override {
print() << "init" << color::reset_endl;
......@@ -203,7 +229,7 @@ class curl_worker : public base_actor {
return (
on(atom("read"), arg_match)
>> [=](const std::string& fname, uint64_t offset, uint64_t range)
-> cow_tuple<atom_value, buffer_type> {
-> message {
print() << "read" << color::reset_endl;
for (;;) {
m_buf.clear();
......@@ -241,7 +267,7 @@ class curl_worker : public base_actor {
<< color::reset_endl;
// tell parent that this worker is done
send(m_parent, atom("finished"));
return make_cow_tuple(atom("reply"), m_buf);
return make_message(atom("reply"), m_buf);
case 404: // file does not exist
print() << "http error: download failed with "
<< "'HTTP RETURN CODE': 404 (file does "
......@@ -275,6 +301,11 @@ class curl_worker : public base_actor {
buffer_type m_buf;
};
curl_worker::~curl_worker() {
// avoid weak-vtables warning
}
// manages {num_curl_workers} workers with a round-robin protocol
class curl_master : public base_actor {
public:
......@@ -282,6 +313,8 @@ class curl_master : public base_actor {
// nop
}
~curl_master();
protected:
behavior make_behavior() override {
print() << "init" << color::reset_endl;
......@@ -337,12 +370,17 @@ class curl_master : public base_actor {
std::vector<actor> m_busy_worker;
};
curl_master::~curl_master() {
// avoid weak-vtables warning
}
// signal handling for ctrl+c
namespace {
std::atomic<bool> shutdown_flag{false};
} // namespace <anonymous>
int main() {
// random number setup
srand(time(nullptr));
// install signal handler
struct sigaction act;
act.sa_handler = [](int) { shutdown_flag = true; };
......
......@@ -80,9 +80,10 @@ void tester(event_based_actor* self, const calculator_type& testee) {
int main() {
// announce custom message types
announce<shutdown_request>();
announce<plus_request>(&plus_request::a, &plus_request::b);
announce<minus_request>(&minus_request::a, &minus_request::b);
announce<shutdown_request>("shutdown_request");
announce<plus_request>("plus_request", &plus_request::a, &plus_request::b);
announce<minus_request>("minus_request", &minus_request::a,
&minus_request::b);
// test function-based impl
spawn(tester, spawn_typed(typed_calculator));
await_all_actors_done();
......
......@@ -8,8 +8,8 @@
* - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n bob *
\ ******************************************************************************/
#include <cstdlib>
#include <string>
#include <cstdlib>
#include <iostream>
#include "caf/all.hpp"
......@@ -20,9 +20,9 @@ using namespace caf;
optional<uint16_t> to_port(const string& arg) {
char* last = nullptr;
auto res = strtol(arg.c_str(), &last, 10);
if (last == (arg.c_str() + arg.size()) && res > 1024) {
return res;
auto res = strtoul(arg.c_str(), &last, 10);
if (last == (arg.c_str() + arg.size()) && res <= 65536) {
return static_cast<uint16_t>(res);
}
return none;
}
......
......@@ -77,11 +77,11 @@ int main(int, char**) {
// announces foo to the libcaf type system;
// the function expects member pointers to all elements of foo
announce<foo>(&foo::a, &foo::b);
announce<foo>("foo", &foo::a, &foo::b);
// announce foo2 to the libcaf type system,
// note that recursive containers are managed automatically by libcaf
announce<foo2>(&foo2::a, &foo2::b);
announce<foo2>("foo2", &foo2::a, &foo2::b);
foo2 vd;
vd.a = 5;
......@@ -98,17 +98,11 @@ int main(int, char**) {
assert(vd == vd2);
// announce std::pair<int, int> to the type system;
// NOTE: foo_pair is NOT distinguishable from foo_pair2!
auto uti = announce<foo_pair>(&foo_pair::first, &foo_pair::second);
// since foo_pair and foo_pair2 are not distinguishable since typedefs
// do not 'create' an own type, this announce fails, since
// std::pair<int, int> is already announced
assert(announce<foo_pair2>(&foo_pair2::first, &foo_pair2::second) == uti);
// announce std::pair<int, int> to the type system
announce<foo_pair>("foo_pair", &foo_pair::first, &foo_pair::second);
// libcaf returns the same uniform_type_info
// instance for foo_pair and foo_pair2
// instance for the type aliases foo_pair and foo_pair2
assert(uniform_typeid<foo_pair>() == uniform_typeid<foo_pair2>());
// spawn a testee that receives two messages
......@@ -124,4 +118,3 @@ int main(int, char**) {
shutdown();
return 0;
}
......@@ -54,8 +54,8 @@ void testee(event_based_actor* self) {
int main(int, char**) {
// if a class uses getter and setter member functions,
// we pass those to the announce function as { getter, setter } pairs.
announce<foo>(make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b));
announce<foo>("foo", make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b));
{
scoped_actor self;
auto t = spawn(testee);
......
......@@ -68,14 +68,15 @@ int main(int, char**) {
foo_setter s2 = &foo::b;
// equal to example 3
announce<foo>(make_pair(g1, s1), make_pair(g2, s2));
announce<foo>("foo", make_pair(g1, s1), make_pair(g2, s2));
// alternative syntax that uses casts instead of variables
// (returns false since foo is already announced)
announce<foo>(make_pair(static_cast<foo_getter>(&foo::a),
static_cast<foo_setter>(&foo::a)),
make_pair(static_cast<foo_getter>(&foo::b),
static_cast<foo_setter>(&foo::b)));
announce<foo>("foo",
make_pair(static_cast<foo_getter>(&foo::a),
static_cast<foo_setter>(&foo::a)),
make_pair(static_cast<foo_getter>(&foo::b),
static_cast<foo_setter>(&foo::b)));
// spawn a new testee and send it a foo
{
......
......@@ -108,23 +108,20 @@ int main(int, char**) {
// it takes a pointer to the non-trivial member as first argument
// followed by all "sub-members" either as member pointer or
// { getter, setter } pair
announce<bar>(compound_member(&bar::f,
make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)),
&bar::i);
auto meta_bar_f = [] {
return compound_member(&bar::f,
make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b));
};
// with meta_bar_f, we can now announce bar
announce<bar>("bar", meta_bar_f(), &bar::i);
// baz has non-trivial data members with getter/setter pair
// and getter returning a mutable reference
announce<baz>(compound_member(make_pair(&baz::f, &baz::set_f),
make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)),
// compound member that has a compound member
compound_member(&baz::b,
compound_member(&bar::f,
make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)),
&bar::i));
announce<baz>("baz", compound_member(make_pair(&baz::f, &baz::set_f),
make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)),
// compound member that has a compound member
compound_member(&baz::b, meta_bar_f(), &bar::i));
// spawn a testee that receives two messages
auto t = spawn(testee, 2);
{
......
......@@ -86,9 +86,12 @@ bool operator==(const tree& lhs, const tree& rhs) {
// - does have a copy constructor
// - does provide operator==
class tree_type_info : public detail::abstract_uniform_type_info<tree> {
public:
tree_type_info() : detail::abstract_uniform_type_info<tree>("tree") {
// nop
}
protected:
void serialize(const void* ptr, serializer* sink) const {
// ptr is guaranteed to be a pointer of type tree
auto tree_ptr = reinterpret_cast<const tree*>(ptr);
......@@ -105,7 +108,6 @@ class tree_type_info : public detail::abstract_uniform_type_info<tree> {
}
private:
void serialize_node(const tree_node& node, serializer* sink) const {
// value, ... children ...
sink->write_value(node.value);
......@@ -127,7 +129,6 @@ class tree_type_info : public detail::abstract_uniform_type_info<tree> {
}
source->end_sequence();
}
};
using tree_vector = std::vector<tree>;
......@@ -171,7 +172,7 @@ void testee(event_based_actor* self, size_t remaining) {
int main() {
// the tree_type_info is owned by libcaf after this function call
announce(typeid(tree), std::unique_ptr<uniform_type_info>{new tree_type_info});
announce<tree_vector>();
announce<tree_vector>("tree_vector");
tree t0; // create a tree and fill it with some data
......
......@@ -38,13 +38,13 @@ set (LIBCAF_CORE_SRCS
src/continue_helper.cpp
src/decorated_tuple.cpp
src/default_attachable.cpp
src/demangle.cpp
src/deserializer.cpp
src/duration.cpp
src/event_based_actor.cpp
src/exception.cpp
src/execution_unit.cpp
src/exit_reason.cpp
src/forwarding_actor_proxy.cpp
src/get_mac_addresses.cpp
src/get_root_uuid.cpp
src/group.cpp
......@@ -59,9 +59,11 @@ set (LIBCAF_CORE_SRCS
src/message_builder.cpp
src/message_data.cpp
src/message_handler.cpp
src/message_iterator.cpp
src/node_id.cpp
src/ref_counted.cpp
src/response_promise.cpp
src/replies_to.cpp
src/resumable.cpp
src/ripemd_160.cpp
src/scoped_actor.cpp
......@@ -73,7 +75,7 @@ set (LIBCAF_CORE_SRCS
src/string_algorithms.cpp
src/string_serialization.cpp
src/sync_request_bouncer.cpp
src/to_uniform_name.cpp
src/try_match.cpp
src/uniform_type_info.cpp
src/uniform_type_info_map.cpp)
......
......@@ -78,16 +78,12 @@ class abstract_actor : public abstract_channel {
/**
* Attaches `ptr` to this actor. The actor will call `ptr->detach(...)` on
* exit, or immediately if it already finished execution.
* @returns `true` if `ptr` was successfully attached to the actor,
* otherwise (actor already exited) `false`.
*/
void attach(attachable_ptr ptr);
/**
* Convenience function that attaches the functor `f` to this actor. The
* actor executes `f()` on exit or immediatley if it is not running.
* @returns `true` if `f` was successfully attached to the actor,
* otherwise (actor already exited) `false`.
*/
template <class F>
void attach_functor(F f) {
......
......@@ -149,10 +149,10 @@ class actor : detail::comparable<actor>,
actor_id id() const;
private:
void swap(actor& other);
private:
inline abstract_actor* get() const {
return m_ptr.get();
}
......
......@@ -38,8 +38,8 @@ class actor_proxy;
using actor_proxy_ptr = intrusive_ptr<actor_proxy>;
/**
* Represents a remote actor.
* @extends abstract_actor
* Represents an actor running on a remote machine,
* or different hardware, or in a separate process.
*/
class actor_proxy : public abstract_actor {
public:
......
......@@ -29,6 +29,7 @@
#include "caf/match.hpp"
#include "caf/spawn.hpp"
#include "caf/config.hpp"
#include "caf/either.hpp"
#include "caf/extend.hpp"
#include "caf/channel.hpp"
#include "caf/message.hpp"
......
......@@ -79,8 +79,8 @@ namespace caf {
*/
/**
* Adds a new mapping to the type system. Returns `false` if a mapping
* for `tinfo` already exists, otherwise `true`.
* Adds a new mapping to the type system. Returns `utype.get()` on
* success, otherwise a pointer to the previously installed singleton.
* @warning `announce` is **not** thead-safe!
*/
const uniform_type_info* announce(const std::type_info& tinfo,
......@@ -95,7 +95,7 @@ const uniform_type_info* announce(const std::type_info& tinfo,
template <class C, class Parent, class... Ts>
std::pair<C Parent::*, detail::abstract_uniform_type_info<C>*>
compound_member(C Parent::*c_ptr, const Ts&... args) {
return {c_ptr, new detail::default_uniform_type_info<C>(args...)};
return {c_ptr, new detail::default_uniform_type_info<C>("???", args...)};
}
// deals with getter returning a mutable reference
......@@ -108,7 +108,7 @@ compound_member(C Parent::*c_ptr, const Ts&... args) {
template <class C, class Parent, class... Ts>
std::pair<C& (Parent::*)(), detail::abstract_uniform_type_info<C>*>
compound_member(C& (Parent::*getter)(), const Ts&... args) {
return {getter, new detail::default_uniform_type_info<C>(args...)};
return {getter, new detail::default_uniform_type_info<C>("???", args...)};
}
// deals with getter/setter pair
......@@ -126,16 +126,17 @@ compound_member(const std::pair<GRes (Parent::*)() const,
SRes (Parent::*)(SArg)>& gspair,
const Ts&... args) {
using mtype = typename std::decay<GRes>::type;
return {gspair, new detail::default_uniform_type_info<mtype>(args...)};
return {gspair, new detail::default_uniform_type_info<mtype>("???", args...)};
}
/**
* Adds a new type mapping for `C` to the type system.
* Adds a new type mapping for `C` to the type system
* using `tname` as its uniform name.
* @warning `announce` is **not** thead-safe!
*/
template <class C, class... Ts>
inline const uniform_type_info* announce(const Ts&... args) {
auto ptr = new detail::default_uniform_type_info<C>(args...);
inline const uniform_type_info* announce(std::string tname, const Ts&... args) {
auto ptr = new detail::default_uniform_type_info<C>(std::move(tname), args...);
return announce(typeid(C), uniform_type_info_ptr{ptr});
}
......
......@@ -21,6 +21,7 @@
#define CAF_ATOM_HPP
#include <string>
#include <type_traits>
#include "caf/detail/atom_val.hpp"
......@@ -46,6 +47,9 @@ constexpr atom_value atom(char const (&str)[Size]) {
return static_cast<atom_value>(detail::atom_val(str, 0xF));
}
template <atom_value Value>
using atom_constant = std::integral_constant<atom_value, Value>;
} // namespace caf
#endif // CAF_ATOM_HPP
......@@ -44,11 +44,6 @@ class behavior {
public:
friend class message_handler;
/**
* The type of continuations that can be used to extend an existing behavior.
*/
using continuation_fun = std::function<optional<message>(message&)>;
behavior() = default;
behavior(behavior&&) = default;
behavior(const behavior&) = default;
......@@ -115,12 +110,6 @@ class behavior {
return (m_impl) ? m_impl->invoke(std::forward<T>(arg)) : none;
}
/**
* Adds a continuation to this behavior that is executed
* whenever this behavior was successfully applied to a message.
*/
behavior add_continuation(continuation_fun fun);
/**
* Checks whether this behavior is not empty.
*/
......
......@@ -51,6 +51,8 @@ class blocking_actor
blocking_actor();
~blocking_actor();
/**************************************************************************
* utility stuff and receive() member function family *
**************************************************************************/
......
......@@ -34,7 +34,7 @@
* whereas each number is a two-digit decimal number without
* leading zeros (e.g. 900 is version 0.9.0).
*/
#define CAF_VERSION 1102
#define CAF_VERSION 1200
#define CAF_MAJOR_VERSION (CAF_VERSION / 10000)
#define CAF_MINOR_VERSION ((CAF_VERSION / 100) % 100)
......@@ -61,7 +61,18 @@
_Pragma("clang diagnostic ignored \"-Wconversion\"") \
_Pragma("clang diagnostic ignored \"-Wcast-align\"") \
_Pragma("clang diagnostic ignored \"-Wundef\"") \
_Pragma("clang diagnostic ignored \"-Wnested-anon-types\"")
_Pragma("clang diagnostic ignored \"-Wnested-anon-types\"") \
_Pragma("clang diagnostic ignored \"-Wdeprecated\"") \
_Pragma("clang diagnostic ignored \"-Wdisabled-macro-expansion\"") \
_Pragma("clang diagnostic ignored \"-Wdocumentation\"") \
_Pragma("clang diagnostic ignored \"-Wfloat-equal\"") \
_Pragma("clang diagnostic ignored \"-Wimplicit-fallthrough\"") \
_Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
_Pragma("clang diagnostic ignored \"-Wshorten-64-to-32\"") \
_Pragma("clang diagnostic ignored \"-Wsign-conversion\"") \
_Pragma("clang diagnostic ignored \"-Wundef\"") \
_Pragma("clang diagnostic ignored \"-Wweak-vtables\"")
# define CAF_POP_WARNINGS \
_Pragma("clang diagnostic pop")
# define CAF_ANNOTATE_FALLTHROUGH [[clang::fallthrough]]
......@@ -104,44 +115,32 @@
# error Platform and/or compiler not supportet
#endif
#include <memory>
#include <cstdio>
#include <cstdlib>
// import backtrace and backtrace_symbols_fd into caf::detail
#ifdef CAF_WINDOWS
#include "caf/detail/execinfo_windows.hpp"
#else
#include <execinfo.h>
namespace caf {
namespace detail {
using ::backtrace;
using ::backtrace_symbols_fd;
} // namespace detail
} // namespace caf
#endif
#ifdef CAF_ENABLE_RUNTIME_CHECKS
# define CAF_REQUIRE__(stmt, file, line) \
printf("%s:%u: requirement failed '%s'\n", file, line, stmt); { \
void* array[10]; \
auto caf_bt_size = ::caf::detail::backtrace(array, 10); \
::caf::detail::backtrace_symbols_fd(array, caf_bt_size, 2); \
} abort()
# define CAF_REQUIRE(stmt) \
if (static_cast<bool>(stmt) == false) { \
CAF_REQUIRE__(#stmt, __FILE__, __LINE__); \
} static_cast<void>(0)
#else
# define CAF_REQUIRE(unused) static_cast<void>(0)
#endif
#define CAF_CRITICAL__(error, file, line) { \
printf("%s:%u: critical error: '%s'\n", file, line, error); \
exit(7); \
#ifndef CAF_ENABLE_RUNTIME_CHECKS
# define CAF_REQUIRE(unused) static_cast<void>(0)
#elif defined(CAF_WINDOWS) || defined(CAF_BSD)
# define CAF_REQUIRE(stmt) \
if (static_cast<bool>(stmt) == false) { \
printf("%s:%u: requirement failed '%s'\n", __FILE__, __LINE__, #stmt); \
abort(); \
} static_cast<void>(0)
#else // defined(CAF_LINUX) || defined(CAF_MACOS)
# include <execinfo.h>
# define CAF_REQUIRE(stmt) \
if (static_cast<bool>(stmt) == false) { \
printf("%s:%u: requirement failed '%s'\n", __FILE__, __LINE__, #stmt); \
void* array[10]; \
auto caf_bt_size = ::backtrace(array, 10); \
::backtrace_symbols_fd(array, caf_bt_size, 2); \
abort(); \
} static_cast<void>(0)
#endif
#define CAF_CRITICAL(error) CAF_CRITICAL__(error, __FILE__, __LINE__)
#define CAF_CRITICAL(error) \
printf("%s:%u: critical error: '%s'\n", __FILE__, __LINE__, error); \
abort()
#endif // CAF_CONFIG_HPP
......@@ -38,35 +38,17 @@ class local_actor;
class continue_helper {
public:
using message_id_wrapper_tag = int;
using getter = std::function<optional<behavior&> (message_id msg_id)>;
continue_helper(message_id mid, getter get_sync_handler);
/**
* Adds the continuation `fun` to the synchronous message handler
* that is invoked if the response handler successfully returned.
*/
template <class F>
continue_helper& continue_with(F fun) {
return continue_with(behavior::continuation_fun{
message_handler{on(any_vals, arg_match) >> fun}});
}
/**
* Adds the continuation `fun` to the synchronous message handler
* that is invoked if the response handler successfully returned.
*/
continue_helper& continue_with(behavior::continuation_fun fun);
continue_helper(message_id mid);
/**
* Returns the ID of the expected response message.
*/
message_id get_message_id() const { return m_mid; }
message_id get_message_id() const {
return m_mid;
}
private:
message_id m_mid;
getter m_getter;
//local_actor* m_self;
};
} // namespace caf
......
......@@ -26,7 +26,6 @@
#include "caf/detail/type_traits.hpp"
#include "caf/detail/to_uniform_name.hpp"
#include "caf/detail/uniform_type_info_map.hpp"
namespace caf {
......@@ -61,13 +60,8 @@ class abstract_uniform_type_info : public uniform_type_info {
protected:
abstract_uniform_type_info() {
auto uname = detail::to_uniform_name<T>();
auto cname = detail::mapped_name_by_decorated_name(uname.c_str());
if (cname == uname.c_str())
m_name = std::move(uname);
else
m_name = cname;
abstract_uniform_type_info(std::string tname) {
m_name = detail::mapped_name_by_decorated_name(std::move(tname));
}
static inline const T& deref(const void* ptr) {
......
......@@ -20,6 +20,8 @@
#ifndef CAF_DETAIL_APPLY_ARGS_HPP
#define CAF_DETAIL_APPLY_ARGS_HPP
#include <utility>
#include "caf/detail/int_list.hpp"
#include "caf/detail/type_list.hpp"
......
......@@ -29,6 +29,7 @@
#include "caf/intrusive_ptr.hpp"
#include "caf/atom.hpp"
#include "caf/either.hpp"
#include "caf/message.hpp"
#include "caf/duration.hpp"
#include "caf/ref_counted.hpp"
......@@ -39,10 +40,6 @@
#include "caf/detail/apply_args.hpp"
#include "caf/detail/type_traits.hpp"
// <backward_compatibility version="0.9">
#include "cppa/cow_tuple.hpp"
// </backward_compatibility>
namespace caf {
class message_handler;
......@@ -72,7 +69,8 @@ struct optional_message_visitor_enable_tpl {
skip_message_t,
optional<skip_message_t>
>::value
&& !is_message_id_wrapper<T>::value;
&& !is_message_id_wrapper<T>::value
&& !std::is_convertible<T, message>::value;
};
struct optional_message_visitor : static_visitor<bhvr_invoke_result> {
......@@ -95,15 +93,19 @@ struct optional_message_visitor : static_visitor<bhvr_invoke_result> {
}
template <class T, class... Ts>
typename std::enable_if<optional_message_visitor_enable_tpl<T>::value,
bhvr_invoke_result>::type
typename std::enable_if<
optional_message_visitor_enable_tpl<T>::value,
bhvr_invoke_result
>::type
operator()(T& v, Ts&... vs) const {
return make_message(std::move(v), std::move(vs)...);
}
template <class T>
typename std::enable_if<is_message_id_wrapper<T>::value,
bhvr_invoke_result>::type
typename std::enable_if<
is_message_id_wrapper<T>::value,
bhvr_invoke_result
>::type
operator()(T& value) const {
return make_message(atom("MESSAGE_ID"),
value.get_message_id().integer_value());
......@@ -113,17 +115,24 @@ struct optional_message_visitor : static_visitor<bhvr_invoke_result> {
return std::move(value);
}
template <class L, class R>
bhvr_invoke_result operator()(either_or_t<L, R>& value) const {
return std::move(value.value);
}
template <class... Ts>
bhvr_invoke_result operator()(std::tuple<Ts...>& value) const {
return detail::apply_args(*this, detail::get_indices(value), value);
}
// <backward_compatibility version="0.9">
template <class... Ts>
bhvr_invoke_result operator()(cow_tuple<Ts...>& value) const {
return static_cast<message>(std::move(value));
template <class T>
typename std::enable_if<
std::is_convertible<T, message>::value,
bhvr_invoke_result
>::type
operator()(const T& value) const {
return static_cast<message>(value);
}
// </backward_compatibility>
};
......
......@@ -27,9 +27,9 @@ namespace detail {
* Barton–Nackman trick implementation.
* `Subclass` must provide a compare member function that compares
* to instances of `T` and returns an integer x with:
* - `x < 0</tt> if <tt>*this < other
* - `x > 0</tt> if <tt>*this > other
* - `x == 0</tt> if <tt>*this == other
* - `x < 0` if `*this < other`
* - `x > 0` if `*this > other`
* - `x == 0` if `*this == other`
*/
template <class Subclass, class T = Subclass>
class comparable {
......
......@@ -17,43 +17,56 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
/******************************************************************************\
* Based on work by the mingw-w64 project; *
* original header: *
* *
* Copyright (c) 2012 mingw-w64 project *
* *
* Contributing author: Kai Tietz *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
* DEALINGS IN THE SOFTWARE. *
\ ******************************************************************************/
#ifndef CAF_DETAIL_EXECINFO_WINDOWS_HPP
#define CAF_DETAIL_EXECINFO_WINDOWS_HPP
#ifndef CAF_DETAIL_CTM_HPP
#define CAF_DETAIL_CTM_HPP
#include "caf/replies_to.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/typed_actor_util.hpp"
namespace caf {
namespace detail {
int backtrace(void** buffer, int size);
void backtrace_symbols_fd(void* const* buffer, int size, int fd);
// CTM: Compile-Time Match
// left hand side is the MPI we are comparing to, this is *not* commutative
template <class A, class B>
struct ctm_cmp : std::false_type { };
template <class T>
struct ctm_cmp<T, T> : std::true_type { };
template <class In, class Out>
struct ctm_cmp<typed_mpi<In, Out, empty_type_list>,
typed_mpi<In, type_list<typed_continue_helper<Out>>, empty_type_list>>
: std::true_type { };
template <class In, class L, class R>
struct ctm_cmp<typed_mpi<In, L, R>,
typed_mpi<In, type_list<skip_message_t>, empty_type_list>>
: std::true_type { };
template <class A, class B>
struct ctm : std::false_type { };
template <>
struct ctm<empty_type_list, empty_type_list> : std::true_type { };
template <class A, class... As, class... Bs>
struct ctm<type_list<A, As...>, type_list<Bs...>>
: std::conditional<
sizeof...(As) + 1 != sizeof...(Bs),
std::false_type,
ctm<type_list<As...>,
typename tl_filter_not<
type_list<Bs...>,
tbind<ctm_cmp, A>::template type
>::type
>
>::type { };
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_EXECINFO_WINDOWS_HPP
#endif // CAF_DETAIL_CTM_HPP
......@@ -248,16 +248,22 @@ template <class T, class AccessPolicy,
bool IsEmptyType = std::is_class<T>::value&& std::is_empty<T>::value>
class member_tinfo : public detail::abstract_uniform_type_info<T> {
public:
using super = detail::abstract_uniform_type_info<T>;
member_tinfo(AccessPolicy apol, SerializePolicy spol)
: m_apol(std::move(apol)), m_spol(std::move(spol)) {
: super("--member--"),
m_apol(std::move(apol)), m_spol(std::move(spol)) {
// nop
}
member_tinfo(AccessPolicy apol) : m_apol(std::move(apol)) {
member_tinfo(AccessPolicy apol)
: super("--member--"),
m_apol(std::move(apol)) {
// nop
}
member_tinfo() = default;
member_tinfo() : super("--member--") {
// nop
}
void serialize(const void* vptr, serializer* s) const override {
m_spol(m_apol(vptr), s);
......@@ -289,15 +295,19 @@ template <class T, class A, class S>
class member_tinfo<T, A, S, false, true>
: public detail::abstract_uniform_type_info<T> {
public:
member_tinfo(const A&, const S&) {
using super = detail::abstract_uniform_type_info<T>;
member_tinfo(const A&, const S&) : super("--member--") {
// nop
}
member_tinfo(const A&) {
member_tinfo(const A&) : super("--member--") {
// nop
}
member_tinfo() = default;
member_tinfo() : super("--member--") {
// nop
}
void serialize(const void*, serializer*) const override {
// nop
......@@ -312,14 +322,24 @@ template <class T, class AccessPolicy, class SerializePolicy>
class member_tinfo<T, AccessPolicy, SerializePolicy, true, false>
: public detail::abstract_uniform_type_info<T> {
public:
using super = detail::abstract_uniform_type_info<T>;
using value_type = typename std::underlying_type<T>::type;
member_tinfo(AccessPolicy apol, SerializePolicy spol)
: m_apol(std::move(apol)), m_spol(std::move(spol)) {}
: super("--member--"),
m_apol(std::move(apol)), m_spol(std::move(spol)) {
// nop
}
member_tinfo(AccessPolicy apol) : m_apol(std::move(apol)) {}
member_tinfo(AccessPolicy apol)
: super("--member--"),
m_apol(std::move(apol)) {
// nop
}
member_tinfo() = default;
member_tinfo() : super("--member--") {
// nop
}
void serialize(const void* p, serializer* s) const override {
auto val = m_apol(p);
......@@ -453,12 +473,15 @@ uniform_type_info_ptr new_member_tinfo(GRes (C::*getter)() const,
template <class T>
class default_uniform_type_info : public detail::abstract_uniform_type_info<T> {
public:
using super = detail::abstract_uniform_type_info<T>;
template <class... Ts>
default_uniform_type_info(Ts&&... args) {
default_uniform_type_info(std::string tname, Ts&&... args)
: super(std::move(tname)) {
push_back(std::forward<Ts>(args)...);
}
default_uniform_type_info() {
default_uniform_type_info(std::string tname) : super(std::move(tname)) {
using result_type = member_tinfo<T, fake_access_policy<T>>;
m_members.push_back(uniform_type_info_ptr(new result_type));
}
......@@ -552,9 +575,10 @@ template <class... Rs>
class default_uniform_type_info<typed_actor<Rs...>> :
public detail::abstract_uniform_type_info<typed_actor<Rs...>> {
public:
using super = detail::abstract_uniform_type_info<typed_actor<Rs...>>;
using handle_type = typed_actor<Rs...>;
default_uniform_type_info() {
default_uniform_type_info(std::string tname) : super(std::move(tname)) {
sub_uti = uniform_typeid<actor>();
}
......
......@@ -166,7 +166,7 @@ class double_ended_queue {
{ // lifetime scope of guard
lock_guard guard(m_head_lock);
first.reset(m_head.load());
node* next = m_head.load()->next;
node* next = first->next;
if (next == nullptr) {
// queue is empty
first.release();
......
......@@ -68,7 +68,9 @@ typename ieee_754_trait<T>::packed_type pack754(T f) {
typedef ieee_754_trait<T> trait; // using trait = ... fails on GCC 4.7
using result_type = typename trait::packed_type;
// filter special type
if (fabs(f) <= trait::zero) return 0; // only true if f equals +0 or -0
if (std::fabs(f) <= trait::zero) {
return 0; // only true if f equals +0 or -0
}
auto significandbits = trait::bits - trait::expbits - 1; // -1 for sign bit
// check sign and begin normalization
result_type sign;
......@@ -92,14 +94,14 @@ typename ieee_754_trait<T>::packed_type pack754(T f) {
}
fnorm = fnorm - static_cast<T>(1);
// calculate 2^significandbits
auto pownum = static_cast<result_type>(1) << significandbits;
auto pownum = static_cast<T>(result_type{1} << significandbits);
// calculate the binary form (non-float) of the significand data
auto significand = static_cast<result_type>(fnorm * (pownum + trait::p5));
// get the biased exponent
auto exp = shift + ((1 << (trait::expbits - 1)) - 1); // shift + bias
// return the final answer
return (sign << (trait::bits - 1)) |
(exp << (trait::bits - trait::expbits - 1)) | significand;
return (sign << (trait::bits - 1))
| (exp << (trait::bits - trait::expbits - 1)) | significand;
}
template <class T>
......@@ -109,11 +111,10 @@ typename ieee_754_trait<T>::float_type unpack754(T i) {
using result_type = typename trait::float_type;
if (i == 0) return trait::zero;
auto significandbits = trait::bits - trait::expbits - 1; // -1 for sign bit
// pull the significand
result_type result =
(i & ((static_cast<T>(1) << significandbits) - 1)); // mask
result /= (static_cast<T>(1) << significandbits); // convert back to float
result += static_cast<result_type>(1); // add the one back on
// pull the significand: mask, convert back to float + add the one back on
auto result = static_cast<result_type>(i & ((T{1} << significandbits) - 1));
result /= static_cast<result_type>(T{1} << significandbits);
result += static_cast<result_type>(1);
// deal with the exponent
auto si = static_cast<signed_type>(i);
auto bias = (1 << (trait::expbits - 1)) - 1;
......
......@@ -82,24 +82,24 @@ class lifted_fun_invoker {
using arg_types = typename get_callable_trait<F>::arg_types;
static constexpr size_t args = tl_size<arg_types>::value;
static constexpr size_t num_args = tl_size<arg_types>::value;
public:
lifted_fun_invoker(F& fun) : f(fun) {}
template <class... Ts>
typename std::enable_if<sizeof...(Ts) == args, R>::type
operator()(Ts&... args) const {
if (has_none(args...)) return none;
return f(unopt(args)...);
typename std::enable_if<sizeof...(Ts) == num_args, R>::type
operator()(Ts&... vs) const {
if (has_none(vs...)) return none;
return f(unopt(vs)...);
}
template <class T, class... Ts>
typename std::enable_if<(sizeof...(Ts) + 1 > args), R>::type
operator()(T& arg, Ts&... args) const {
if (has_none(arg)) return none;
return (*this)(args...);
typename std::enable_if<(sizeof...(Ts) + 1 > num_args), R>::type
operator()(T& v, Ts&... vs) const {
if (has_none(v)) return none;
return (*this)(vs...);
}
private:
......@@ -113,25 +113,25 @@ class lifted_fun_invoker<bool, F> {
using arg_types = typename get_callable_trait<F>::arg_types;
static constexpr size_t args = tl_size<arg_types>::value;
static constexpr size_t num_args = tl_size<arg_types>::value;
public:
lifted_fun_invoker(F& fun) : f(fun) {}
template <class... Ts>
typename std::enable_if<sizeof...(Ts) == args, bool>::type
operator()(Ts&&... args) const {
if (has_none(args...)) return false;
f(unopt(args)...);
typename std::enable_if<sizeof...(Ts) == num_args, bool>::type
operator()(Ts&&... vs) const {
if (has_none(vs...)) return false;
f(unopt(vs)...);
return true;
}
template <class T, class... Ts>
typename std::enable_if<(sizeof...(Ts) + 1 > args), bool>::type
operator()(T&& arg, Ts&&... args) const {
typename std::enable_if<(sizeof...(Ts) + 1 > num_args), bool>::type
operator()(T&& arg, Ts&&... vs) const {
if (has_none(arg)) return false;
return (*this)(args...);
return (*this)(vs...);
}
private:
......
......@@ -29,7 +29,6 @@
#include "caf/to_string.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/detail/demangle.hpp"
#include "caf/detail/singletons.hpp"
#include "caf/detail/scope_guard.hpp"
......@@ -184,7 +183,7 @@ inline caf::actor_id caf_set_aid_dummy() { return 0; }
caf::detail::singletons::get_logger()->set_aid(aid_arg)
#endif
#define CAF_CLASS_NAME caf::detail::demangle(typeid(decltype(*this))).c_str()
#define CAF_CLASS_NAME typeid(*this).name()
#define CAF_PRINT0(lvlname, classname, funname, msg) \
CAF_LOG_IMPL(lvlname, classname, funname, msg)
......@@ -201,7 +200,7 @@ inline caf::actor_id caf_set_aid_dummy() { return 0; }
#define CAF_PRINT_IF1(stmt, lvlname, classname, funname, msg) \
CAF_PRINT_IF0(stmt, lvlname, classname, funname, msg)
#if CAF_LOG_LEVEL < CAF_TRACE
#if !defined(CAF_LOG_LEVEL) || CAF_LOG_LEVEL < CAF_TRACE
#define CAF_PRINT4(arg0, arg1, arg2, arg3)
#else
#define CAF_PRINT4(lvlname, classname, funname, msg) \
......@@ -211,7 +210,7 @@ inline caf::actor_id caf_set_aid_dummy() { return 0; }
}
#endif
#if CAF_LOG_LEVEL < CAF_DEBUG
#if !defined(CAF_LOG_LEVEL) || CAF_LOG_LEVEL < CAF_DEBUG
#define CAF_PRINT3(arg0, arg1, arg2, arg3)
#define CAF_PRINT_IF3(arg0, arg1, arg2, arg3, arg4)
#else
......@@ -221,7 +220,7 @@ inline caf::actor_id caf_set_aid_dummy() { return 0; }
CAF_PRINT_IF0(stmt, lvlname, classname, funname, msg)
#endif
#if CAF_LOG_LEVEL < CAF_INFO
#if !defined(CAF_LOG_LEVEL) || CAF_LOG_LEVEL < CAF_INFO
#define CAF_PRINT2(arg0, arg1, arg2, arg3)
#define CAF_PRINT_IF2(arg0, arg1, arg2, arg3, arg4)
#else
......
......@@ -31,7 +31,6 @@
#include "caf/uniform_type_info.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/message_iterator.hpp"
namespace caf {
......@@ -74,7 +73,7 @@ class message_data : public ref_counted {
bool equals(const message_data& other) const;
using const_iterator = message_iterator<message_data>;
using const_iterator = message_iterator;
inline const_iterator begin() const {
return {this};
......@@ -133,37 +132,6 @@ class message_data : public ref_counted {
};
struct full_eq_type {
constexpr full_eq_type() {}
template <class Tuple>
inline bool operator()(const message_iterator<Tuple>& lhs,
const message_iterator<Tuple>& rhs) const {
return lhs.type() == rhs.type() &&
lhs.type()->equals(lhs.value(), rhs.value());
}
};
struct types_only_eq_type {
constexpr types_only_eq_type() {}
template <class Tuple>
inline bool operator()(const message_iterator<Tuple>& lhs,
const uniform_type_info* rhs) const {
return lhs.type() == rhs;
}
template <class Tuple>
inline bool operator()(const uniform_type_info* lhs,
const message_iterator<Tuple>& rhs) const {
return lhs == rhs.type();
}
};
namespace {
constexpr full_eq_type full_eq;
constexpr types_only_eq_type types_only_eq;
} // namespace <anonymous>
std::string get_tuple_type_names(const detail::message_data&);
} // namespace detail
......
......@@ -17,53 +17,41 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_TUPLE_ITERATOR_HPP
#define CAF_DETAIL_TUPLE_ITERATOR_HPP
#ifndef CAF_DETAIL_MESSAGE_ITERATOR_HPP
#define CAF_DETAIL_MESSAGE_ITERATOR_HPP
#include <cstddef>
#include "caf/config.hpp"
#include "caf/fwd.hpp"
namespace caf {
namespace detail {
template <class Tuple>
class message_iterator {
size_t m_pos;
const Tuple* m_tuple;
class message_data;
class message_iterator {
public:
using pointer = message_data*;
using const_pointer = const message_data*;
inline message_iterator(const Tuple* tup, size_t pos = 0)
: m_pos(pos), m_tuple(tup) {}
message_iterator(const_pointer data, size_t pos = 0);
message_iterator(const message_iterator&) = default;
message_iterator& operator=(const message_iterator&) = default;
inline bool operator==(const message_iterator& other) const {
CAF_REQUIRE(other.m_tuple == other.m_tuple);
return other.m_pos == m_pos;
}
inline bool operator!=(const message_iterator& other) const {
return !(*this == other);
}
inline message_iterator& operator++() {
++m_pos;
return *this;
}
inline message_iterator& operator--() {
CAF_REQUIRE(m_pos > 0);
--m_pos;
return *this;
}
inline message_iterator operator+(size_t offset) {
return {m_tuple, m_pos + offset};
return {m_data, m_pos + offset};
}
inline message_iterator& operator+=(size_t offset) {
......@@ -72,29 +60,46 @@ class message_iterator {
}
inline message_iterator operator-(size_t offset) {
CAF_REQUIRE(m_pos >= offset);
return {m_tuple, m_pos - offset};
return {m_data, m_pos - offset};
}
inline message_iterator& operator-=(size_t offset) {
CAF_REQUIRE(m_pos >= offset);
m_pos -= offset;
return *this;
}
inline size_t position() const { return m_pos; }
inline const void* value() const { return m_tuple->at(m_pos); }
inline size_t position() const {
return m_pos;
}
inline const uniform_type_info* type() const {
return m_tuple->type_at(m_pos);
inline const_pointer data() const {
return m_data;
}
inline message_iterator& operator*() { return *this; }
const void* value() const;
const uniform_type_info* type() const;
inline message_iterator& operator*() {
return *this;
}
private:
size_t m_pos;
const message_data* m_data;
};
inline bool operator==(const message_iterator& lhs,
const message_iterator& rhs) {
return lhs.data() == rhs.data() && lhs.position() == rhs.position();
}
inline bool operator!=(const message_iterator& lhs,
const message_iterator& rhs) {
return !(lhs == rhs);
}
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_TUPLE_ITERATOR_HPP
#endif // CAF_DETAIL_MESSAGE_ITERATOR_HPP
......@@ -64,10 +64,10 @@ class proper_actor_base : public Policies::resume_policy::template
scheduling_policy().enqueue(dptr(), sender, mid, msg, eu);
}
inline void launch(bool hide, execution_unit* host) {
inline void launch(bool hide, bool lazy, execution_unit* eu) {
CAF_LOG_TRACE("");
this->is_registered(!hide);
this->scheduling_policy().launch(this, host);
this->scheduling_policy().launch(this, eu, lazy);
}
template <class F>
......@@ -255,17 +255,17 @@ class proper_actor<Base, Policies, true>
}
restore_cache();
}
bool has_timeout = false;
bool timeout_valid = false;
uint32_t timeout_id;
// request timeout if needed
if (bhvr.timeout().valid()) {
has_timeout = true;
timeout_valid = true;
timeout_id = this->request_timeout(bhvr.timeout());
}
// workaround for GCC 4.7 bug (const this when capturing refs)
auto& pending_timeouts = m_pending_timeouts;
auto guard = detail::make_scope_guard([&] {
if (has_timeout) {
if (timeout_valid) {
auto e = pending_timeouts.end();
auto i = std::find(pending_timeouts.begin(), e, timeout_id);
if (i != e) {
......
......@@ -47,15 +47,17 @@ template <size_t N, class... Ts>
const typename detail::type_at<N, Ts...>::type&
get(const detail::pseudo_tuple<Ts...>& tv) {
static_assert(N < sizeof...(Ts), "N >= tv.size()");
return *reinterpret_cast<const typename detail::type_at<N, Ts...>::type*>(
tv.at(N));
auto vp = tv.at(N);
CAF_REQUIRE(vp != nullptr);
return *reinterpret_cast<const typename detail::type_at<N, Ts...>::type*>(vp);
}
template <size_t N, class... Ts>
typename detail::type_at<N, Ts...>::type& get(detail::pseudo_tuple<Ts...>& tv) {
static_assert(N < sizeof...(Ts), "N >= tv.size()");
return *reinterpret_cast<typename detail::type_at<N, Ts...>::type*>(
tv.mutable_at(N));
auto vp = tv.mutable_at(N);
CAF_REQUIRE(vp != nullptr);
return *reinterpret_cast<typename detail::type_at<N, Ts...>::type*>(vp);
}
} // namespace detail
......
......@@ -17,19 +17,13 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_SPLIT_HPP
#define CAF_DETAIL_SPLIT_HPP
#ifndef CAF_DETAIL_SAFE_EQUAL_HPP
#define CAF_DETAIL_SAFE_EQUAL_HPP
#include <cmath> // fabs
#include <string>
#include <vector>
#include <limits>
#include <sstream>
#include <algorithm>
#include <type_traits>
#include "caf/detail/type_traits.hpp"
namespace caf {
namespace detail {
......@@ -39,18 +33,18 @@ namespace detail {
* performs an epsilon comparison.
*/
template <class T, typename U>
typename std::enable_if< !std::is_floating_point<T>::value
&& !std::is_floating_point<U>::value,
bool
typename std::enable_if<
!std::is_floating_point<T>::value && !std::is_floating_point<U>::value,
bool
>::type
safe_equal(const T& lhs, const U& rhs) {
return lhs == rhs;
}
template <class T, typename U>
typename std::enable_if< std::is_floating_point<T>::value
|| std::is_floating_point<U>::value,
bool
typename std::enable_if<
std::is_floating_point<T>::value || std::is_floating_point<U>::value,
bool
>::type
safe_equal(const T& lhs, const U& rhs) {
using res_type = decltype(lhs - rhs);
......@@ -60,4 +54,4 @@ safe_equal(const T& lhs, const U& rhs) {
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_SPLIT_HPP
#endif // CAF_DETAIL_SAFE_EQUAL_HPP
......@@ -336,7 +336,7 @@ class single_reader_queue {
pointer reader_blocked_dummy() {
// we are not going to dereference this pointer either
return reinterpret_cast<pointer>(reinterpret_cast<intptr_t>(this)
+ sizeof(void*));
+ static_cast<intptr_t>(sizeof(void*)));
}
bool is_dummy(pointer ptr) {
......
......@@ -20,7 +20,9 @@
#ifndef CAF_DETAIL_MATCHES_HPP
#define CAF_DETAIL_MATCHES_HPP
#include <array>
#include <numeric>
#include <typeinfo>
#include "caf/message.hpp"
#include "caf/wildcard_position.hpp"
......@@ -31,80 +33,75 @@
namespace caf {
namespace detail {
template <class Pattern, class FilteredPattern>
struct matcher;
template <class... Ts, class... Us>
struct matcher<type_list<Ts...>, type_list<Us...>> {
template <class TupleIter, class PatternIter, class Push, class Commit,
class Rollback>
bool operator()(TupleIter tbegin, TupleIter tend, PatternIter pbegin,
PatternIter pend, Push& push, Commit& commit,
Rollback& rollback) const {
while (!(pbegin == pend && tbegin == tend)) {
if (pbegin == pend) {
// reached end of pattern while some values remain unmatched
return false;
}
if (*pbegin == nullptr) { // nullptr == wildcard (anything)
// perform submatching
++pbegin;
// always true at the end of the pattern
if (pbegin == pend) {
return true;
}
// safe current mapping as fallback
commit();
// iterate over tuple values until we found a match
for (; tbegin != tend; ++tbegin) {
if ((*this)(tbegin, tend, pbegin, pend, push, commit, rollback)) {
return true;
}
// restore mapping to fallback (delete invalid mappings)
rollback();
}
return false; // no submatch found
}
// compare types
if (tbegin.type() != *pbegin) {
// type mismatch
return false;
}
// next iteration
push(tbegin);
++tbegin;
++pbegin;
}
return true; // pbegin == pend && tbegin == tend
bool match_element(const std::type_info* type, const message_iterator& iter,
void** storage);
template <class T>
bool match_integral_constant_element(const std::type_info* type,
const message_iterator& iter,
void** storage) {
auto value = T::value;
auto uti = iter.type();
if (!uti->equal_to(*type) || !uti->equals(iter.value(), &value)) {
return false;
}
if (storage) {
// This assignment implicitly casts `T*` to `integral_constant<T, V>*`.
// This type violation could theoretically cause undefined behavior.
// However, `T::value` does have an address that is guaranteed to be valid
// throughout the runtime of the program and the integral constant
// objects does not have any members. Hence, this is nonetheless safe.
auto ptr = reinterpret_cast<const void*>(&T::value);
// Again, this const cast is always safe because we will never derefence
// this pointer since `integral_constant<T, V>` has no members.
*storage = const_cast<void*>(ptr);
}
return true;
}
struct meta_element {
const std::type_info* type;
bool (*fun)(const std::type_info*, const message_iterator&, void**);
};
template <class T>
struct meta_element_factory {
static meta_element create() {
return {&typeid(T), match_element};
}
};
bool operator()(const message& tup, pseudo_tuple<Us...>* out) const {
auto& tarr = static_types_array<Ts...>::arr;
if (sizeof...(Us) == 0) {
// this pattern only has wildcards and thus always matches
return true;
}
if (tup.size() < sizeof...(Us)) {
return false;
}
if (out) {
size_t pos = 0;
size_t fallback_pos = 0;
auto fpush = [&](const typename message::const_iterator& iter) {
(*out)[pos++] = const_cast<void*>(iter.value());
};
auto fcommit = [&] { fallback_pos = pos; };
auto frollback = [&] { pos = fallback_pos; };
return (*this)(tup.begin(), tup.end(), tarr.begin(), tarr.end(), fpush,
fcommit, frollback);
}
auto no_push = [](const typename message::const_iterator&) { };
auto nop = [] { };
return (*this)(tup.begin(), tup.end(), tarr.begin(), tarr.end(), no_push,
nop, nop);
template <class T, T V>
struct meta_element_factory<std::integral_constant<T, V>> {
static meta_element create() {
return {&typeid(T),
match_integral_constant_element<std::integral_constant<T, V>>};
}
};
template <>
struct meta_element_factory<anything> {
static meta_element create() {
return {nullptr, nullptr};
}
};
template <class TypeList>
struct meta_elements;
template <class... Ts>
struct meta_elements<type_list<Ts...>> {
std::array<meta_element, sizeof...(Ts)> arr;
meta_elements() : arr{{meta_element_factory<Ts>::create()...}} {
// nop
}
};
bool try_match(const message& msg,
const meta_element* pattern_begin,
size_t pattern_size,
void** out = nullptr);
} // namespace detail
} // namespace caf
......
......@@ -207,8 +207,8 @@ class is_forward_iterator {
};
/**
* Checks wheter `T` has `begin()</tt> and <tt>end() member
* functions returning forward iterators.
* Checks wheter `T` has `begin()` and `end()` member
* functions returning forward iterators.
*/
template <class T>
class is_iterable {
......@@ -256,6 +256,23 @@ struct is_mutable_ref {
&& !std::is_const<T>::value;
};
/**
* Checks whether `T::static_type_name()` exists.
*/
template <class T>
class has_static_type_name {
private:
template <class U,
class = typename std::enable_if<
!std::is_member_pointer<decltype(&U::is_baz)>::value
>::type>
static std::true_type sfinae_fun(int);
template <class>
static std::false_type sfinae_fun(...);
public:
static constexpr bool value = decltype(sfinae_fun<T>(0))::value;
};
/**
* Returns either `T` or `T::type` if `T` is an option.
*/
......@@ -464,6 +481,16 @@ struct is_optional<optional<T>> : std::true_type {
// no members
};
template <class T>
struct is_integral_constant : std::false_type {
// no members
};
template <class T, T V>
struct is_integral_constant<std::integral_constant<T, V>> : std::true_type {
// no members
};
} // namespace detail
} // namespace caf
......
......@@ -23,6 +23,7 @@
#include <tuple>
#include "caf/replies_to.hpp"
#include "caf/system_messages.hpp"
#include "caf/detail/type_list.hpp"
......@@ -36,26 +37,56 @@ class typed_continue_helper;
namespace caf {
namespace detail {
template <class R, typename T>
struct deduce_signature_helper;
template <class T>
struct unwrap_std_tuple {
using type = type_list<T>;
};
template <class... Ts>
struct unwrap_std_tuple<std::tuple<Ts...>> {
using type = type_list<Ts...>;
};
template <class R, class... Ts>
struct deduce_signature_helper<R, type_list<Ts...>> {
using type = typename replies_to<Ts...>::template with<R>;
template <class T>
struct deduce_lhs_result {
using type = typename unwrap_std_tuple<T>::type;
};
template <class L, class R>
struct deduce_lhs_result<either_or_t<L, R>> {
using type = L;
};
template <class... Rs, class... Ts>
struct deduce_signature_helper<std::tuple<Rs...>, type_list<Ts...>> {
using type = typename replies_to<Ts...>::template with<Rs...>;
template <class T>
struct deduce_rhs_result {
using type = type_list<>;
};
template <class L, class R>
struct deduce_rhs_result<either_or_t<L, R>> {
using type = R;
};
template <class T>
struct deduce_signature {
using result_ = typename implicit_conversions<typename T::result_type>::type;
struct is_hidden_msg_handler : std::false_type { };
template <>
struct is_hidden_msg_handler<typed_mpi<type_list<exit_msg>,
type_list<void>,
empty_type_list>> : std::true_type { };
template <>
struct is_hidden_msg_handler<typed_mpi<type_list<down_msg>,
type_list<void>,
empty_type_list>> : std::true_type { };
template <class T>
struct deduce_mpi {
using result = typename implicit_conversions<typename T::result_type>::type;
using arg_t = typename tl_map<typename T::arg_types, std::decay>::type;
using type = typename deduce_signature_helper<result_, arg_t>::type;
using type = typed_mpi<arg_t,
typename deduce_lhs_result<result>::type,
typename deduce_rhs_result<result>::type>;
};
template <class Arguments>
......@@ -67,20 +98,50 @@ struct input_is {
};
};
template <class OutputList, typename F>
inline void assert_types() {
using arg_types =
typename tl_map<
typename get_callable_trait<F>::arg_types,
std::decay
>::type;
static constexpr size_t fun_args = tl_size<arg_types>::value;
static_assert(fun_args <= tl_size<OutputList>::value,
"functor takes too much arguments");
using recv_types = typename tl_right<OutputList, fun_args>::type;
static_assert(std::is_same<arg_types, recv_types>::value,
"wrong functor signature");
}
template <class OutputPair, class... Fs>
struct type_checker;
template <class OutputList, class F1>
struct type_checker<OutputList, F1> {
static void check() {
using arg_types =
typename tl_map<
typename get_callable_trait<F1>::arg_types,
std::decay
>::type;
static constexpr size_t args = tl_size<arg_types>::value;
static_assert(args <= tl_size<OutputList>::value,
"functor takes too much arguments");
using rtypes = typename tl_right<OutputList, args>::type;
static_assert(std::is_same<arg_types, rtypes>::value,
"wrong functor signature");
}
};
template <class Opt1, class Opt2, class F1>
struct type_checker<type_pair<Opt1, Opt2>, F1> {
static void check() {
type_checker<Opt1, F1>::check();
}
};
template <class OutputPair, class F1>
struct type_checker<OutputPair, F1, none_t> : type_checker<OutputPair, F1> { };
template <class Opt1, class Opt2, class F1, class F2>
struct type_checker<type_pair<Opt1, Opt2>, F1, F2> {
static void check() {
type_checker<Opt1, F1>::check();
type_checker<Opt2, F2>::check();
}
};
template <class A, class B, template <class, class> class Predicate>
struct static_asserter {
static void verify_match() {
static_assert(Predicate<A, B>::value, "exact match needed");
}
};
template <class T>
struct lifted_result_type {
......@@ -93,27 +154,50 @@ struct lifted_result_type<std::tuple<Ts...>> {
};
template <class T>
struct deduce_output_type_step2 {
struct deduce_lifted_output_type {
using type = T;
};
template <class R>
struct deduce_output_type_step2<type_list<typed_continue_helper<R>>> {
struct deduce_lifted_output_type<type_list<typed_continue_helper<R>>> {
using type = typename lifted_result_type<R>::type;
};
template <class Signatures, typename InputTypes>
struct deduce_output_type {
static constexpr int input_pos = tl_find_if<
Signatures,
input_is<InputTypes>::template eval
>::value;
static_assert(input_pos >= 0, "typed actor does not support given input");
static_assert(tl_find<
InputTypes,
atom_value
>::value == -1,
"atom(...) notation is not sufficient for static type "
"checking, please use atom_constant instead in this context");
static constexpr int input_pos =
tl_find_if<
Signatures,
input_is<InputTypes>::template eval
>::value;
static_assert(input_pos != -1, "typed actor does not support given input");
using signature = typename tl_at<Signatures, input_pos>::type;
using type =
typename deduce_output_type_step2<
typename signature::output_types
>::type;
using type = detail::type_pair<typename signature::output_opt1_types,
typename signature::output_opt2_types>;
};
template <class... Ts>
struct common_result_type;
template <class T>
struct common_result_type<T> {
using type = T;
};
template <class T, class... Us>
struct common_result_type<T, T, Us...> {
using type = typename common_result_type<T, Us...>::type;
};
template <class T1, class T2, class... Us>
struct common_result_type<T1, T2, Us...> {
using type = void;
};
} // namespace detail
......
......@@ -23,15 +23,11 @@
#include <atomic>
#include <typeinfo>
#include "caf/uniform_typeid.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp"
// forward declarations
namespace caf {
class uniform_type_info;
const uniform_type_info* uniform_typeid(const std::type_info&);
} // namespace caf
namespace caf {
namespace detail {
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_EITHER_HPP
#define CAF_EITHER_HPP
#include <tuple>
#include <string>
#include <type_traits>
#include "caf/message.hpp"
#include "caf/replies_to.hpp"
#include "caf/type_name_access.hpp"
#include "caf/illegal_message_element.hpp"
#include "caf/detail/type_list.hpp"
namespace caf {
/** @cond PRIVATE */
std::string either_or_else_type_name(size_t lefts_size,
const std::string* lefts,
size_t rights_size,
const std::string* rights);
template <class L, class R>
struct either_or_t;
template <class... Ls, class... Rs>
struct either_or_t<detail::type_list<Ls...>,
detail::type_list<Rs...>> : illegal_message_element {
static_assert(!std::is_same<detail::type_list<Ls...>,
detail::type_list<Rs...>>::value,
"template parameter packs must differ");
either_or_t(Ls... ls) : value(make_message(std::move(ls)...)) {
// nop
}
either_or_t(Rs... rs) : value(make_message(std::move(rs)...)) {
// nop
}
using opt1_type = std::tuple<Ls...>;
using opt2_type = std::tuple<Rs...>;
message value;
static std::string static_type_name() {
std::string lefts[] = {type_name_access<Ls>::get()...};
std::string rights[] = {type_name_access<Rs>::get()...};
return either_or_else_type_name(sizeof...(Ls), lefts,
sizeof...(Rs), rights);
}
};
/** @endcond */
template <class... Ts>
struct either {
template <class... Us>
using or_else = either_or_t<detail::type_list<Ts...>,
detail::type_list<Us...>>;
};
} // namespace caf
#endif // CAF_EITHER_HPP
......@@ -17,50 +17,24 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_IO_REMOTE_ACTOR_PROXY_HPP
#define CAF_IO_REMOTE_ACTOR_PROXY_HPP
#ifndef CAF_FORWARDING_ACTOR_PROXY_HPP
#define CAF_FORWARDING_ACTOR_PROXY_HPP
#include "caf/extend.hpp"
#include "caf/actor.hpp"
#include "caf/actor_proxy.hpp"
#include "caf/mixin/memory_cached.hpp"
#include "caf/detail/single_reader_queue.hpp"
namespace caf {
namespace detail {
class memory;
} // namespace detail
} // namespace caf
#include "caf/detail/shared_spinlock.hpp"
namespace caf {
namespace io {
class middleman;
class sync_request_info : public extend<memory_managed>::
with<mixin::memory_cached> {
friend class detail::memory;
/**
* Implements a simple proxy forwarding all operations to a manager.
*/
class forwarding_actor_proxy : public actor_proxy {
public:
using pointer = sync_request_info*;
~sync_request_info();
forwarding_actor_proxy(actor_id mid, node_id pinfo, actor parent);
pointer next; // intrusive next pointer
actor_addr sender; // points to the sender of the message
message_id mid; // sync message ID
private:
sync_request_info(actor_addr sptr, message_id id);
};
class remote_actor_proxy : public actor_proxy {
using super = actor_proxy;
public:
remote_actor_proxy(actor_id mid, node_id pinfo,
actor parent);
~forwarding_actor_proxy();
void enqueue(const actor_addr&, message_id,
message, execution_unit*) override;
......@@ -73,17 +47,17 @@ class remote_actor_proxy : public actor_proxy {
void kill_proxy(uint32_t reason) override;
protected:
~remote_actor_proxy();
actor manager() const;
void manager(actor new_manager);
private:
void forward_msg(const actor_addr& sender, message_id mid, message msg);
actor m_parent;
};
using remote_actor_proxy_ptr = intrusive_ptr<remote_actor_proxy>;
mutable detail::shared_spinlock m_manager_mtx;
actor m_manager;
};
} // namespace io
} // namespace caf
#endif // CAF_IO_REMOTE_ACTOR_PROXY_HPP
#endif // CAF_FORWARDING_ACTOR_PROXY_HPP
......@@ -47,11 +47,13 @@ class blocking_actor;
class message_handler;
class uniform_type_info;
class event_based_actor;
class forwarding_actor_proxy;
// structs
struct anything;
struct invalid_actor_t;
struct invalid_actor_addr_t;
struct illegal_message_element;
// enums
enum class atom_value : uint64_t;
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_ILLEGAL_MESSAGE_ELEMENT_HPP
#define CAF_ILLEGAL_MESSAGE_ELEMENT_HPP
#include <type_traits>
namespace caf {
/**
* Marker class identifying classes in CAF that are not allowed
* to be used as message element.
*/
struct illegal_message_element {
// no members (marker class)
};
template <class T>
struct is_illegal_message_element
: std::is_base_of<illegal_message_element, T> { };
} // namespace caf
#endif // CAF_ILLEGAL_MESSAGE_ELEMENT_HPP
......@@ -504,8 +504,8 @@ class local_actor : public extend<abstract_actor>::with<mixin::memory_cached> {
// returns 0 if last_dequeued() is an asynchronous or sync request message,
// a response id generated from the request id otherwise
inline message_id get_response_id() {
auto id = m_current_node->mid;
return (id.is_request()) ? id.response_id() : message_id();
auto mid = m_current_node->mid;
return (mid.is_request()) ? mid.response_id() : message_id();
}
void reply_message(message&& what);
......
......@@ -34,7 +34,7 @@
#include "caf/detail/type_traits.hpp"
#include "caf/detail/left_or_right.hpp"
#include "caf/detail/matcher.hpp"
#include "caf/detail/try_match.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/lifted_fun.hpp"
#include "caf/detail/pseudo_tuple.hpp"
......@@ -227,10 +227,9 @@ Result unroll_expr(PPFPs& fs, uint64_t bitmask, long_constant<N>, Msg& msg) {
}
auto& f = get<N>(fs);
using ft = typename std::decay<decltype(f)>::type;
detail::matcher<typename ft::pattern, typename ft::filtered_pattern> match;
meta_elements<typename ft::pattern> ms;
typename ft::intermediate_tuple targs;
if (match(msg, &targs)) {
//if (policy::prepare_invoke(targs, type_token, is_dynamic, ptr, tup)) {
if (try_match(msg, ms.arr.data(), ms.arr.size(), targs.data)) {
auto is = detail::get_indices(targs);
auto res = detail::apply_args(f, is, deduce_const(msg, targs));
if (unroll_expr_result_valid(res)) {
......@@ -240,19 +239,21 @@ Result unroll_expr(PPFPs& fs, uint64_t bitmask, long_constant<N>, Msg& msg) {
return none;
}
template <class PPFPs, class Tuple>
uint64_t calc_bitmask(PPFPs&, minus1l, const std::type_info&, const Tuple&) {
template <class PPFPs>
uint64_t calc_bitmask(PPFPs&, minus1l, const std::type_info&, const message&) {
return 0x00;
}
template <class Case, long N, class Tuple>
template <class Case, long N>
uint64_t calc_bitmask(Case& fs, long_constant<N>,
const std::type_info& tinf, const Tuple& tup) {
const std::type_info& tinf, const message& msg) {
auto& f = get<N>(fs);
using ft = typename std::decay<decltype(f)>::type;
detail::matcher<typename ft::pattern, typename ft::filtered_pattern> match;
uint64_t result = match(tup, nullptr) ? (0x01 << N) : 0x00;
return result | calc_bitmask(fs, long_constant<N - 1l>(), tinf, tup);
meta_elements<typename ft::pattern> ms;
uint64_t result = try_match(msg, ms.arr.data(), ms.arr.size(), nullptr)
? (0x01 << N)
: 0x00;
return result | calc_bitmask(fs, long_constant<N - 1l>(), tinf, msg);
}
template <bool IsManipulator, typename T0, typename T1>
......
......@@ -181,16 +181,12 @@ class message {
/**
* Returns an iterator to the beginning.
*/
inline const_iterator begin() const {
return m_vals->begin();
}
const_iterator begin() const;
/**
* Returns an iterator to the end.
*/
inline const_iterator end() const {
return m_vals->end();
}
const_iterator end() const;
/**
* Returns a copy-on-write pointer to the internal data.
......@@ -285,6 +281,16 @@ inline bool operator!=(const message& lhs, const message& rhs) {
return !(lhs == rhs);
}
template <class T>
struct lift_message_element {
using type = T;
};
template <class T, T V>
struct lift_message_element<std::integral_constant<T, V>> {
using type = T;
};
/**
* Creates a new `message` containing the elements `args...`.
* @relates message
......@@ -296,10 +302,14 @@ typename std::enable_if<
message
>::type
make_message(T&& arg, Ts&&... args) {
using namespace detail;
using data = tuple_vals<typename strip_and_convert<T>::type,
typename strip_and_convert<Ts>::type...>;
auto ptr = new data(std::forward<T>(arg), std::forward<Ts>(args)...);
using storage
= detail::tuple_vals<typename lift_message_element<
typename detail::strip_and_convert<T>::type
>::type,
typename lift_message_element<
typename detail::strip_and_convert<Ts>::type
>::type...>;
auto ptr = new storage(std::forward<T>(arg), std::forward<Ts>(args)...);
return message{detail::message_data::ptr{ptr}};
}
......
......@@ -69,6 +69,13 @@ class message_handler {
*/
message_handler(impl_ptr ptr);
/**
* Checks whether the message handler is not empty.
*/
inline operator bool() const {
return static_cast<bool>(m_impl);
}
/**
* Create a message handler a list of match expressions,
* functors, or other message handlers.
......@@ -104,7 +111,13 @@ class message_handler {
// using a behavior is safe here, because we "cast"
// it back to a message_handler when appropriate
behavior tmp{std::forward<Ts>(args)...};
return m_impl->or_else(tmp.as_behavior_impl());
if (! tmp) {
return *this;
}
if (m_impl) {
return m_impl->or_else(tmp.as_behavior_impl());
}
return tmp;
}
private:
......
......@@ -36,7 +36,6 @@ template <class Base, class Subtype, class ResponseHandleTag>
class sync_sender_impl : public Base {
public:
using response_handle_type = response_handle<Subtype, message,
ResponseHandleTag>;
......@@ -130,10 +129,12 @@ class sync_sender_impl : public Base {
**************************************************************************/
template <class... Rs, class... Ts>
response_handle<
Subtype, typename detail::deduce_output_type<
detail::type_list<Rs...>, detail::type_list<Ts...>>::type,
ResponseHandleTag>
response_handle<Subtype,
typename detail::deduce_output_type<
detail::type_list<Rs...>,
detail::type_list<Ts...>
>::type,
ResponseHandleTag>
sync_send_tuple(message_priority prio, const typed_actor<Rs...>& dest,
std::tuple<Ts...> what) {
return sync_send_impl(prio, dest, detail::type_list<Ts...>{},
......@@ -157,7 +158,8 @@ class sync_sender_impl : public Base {
typename detail::deduce_output_type<
detail::type_list<Rs...>,
typename detail::implicit_conversions<
typename std::decay<Ts>::type>::type...>::type,
typename std::decay<Ts>::type>::type...
>::type,
ResponseHandleTag>
sync_send(message_priority prio, const typed_actor<Rs...>& dest,
Ts&&... what) {
......
......@@ -27,6 +27,8 @@
#include "caf/unit.hpp"
#include "caf/config.hpp"
#include "caf/detail/safe_equal.hpp"
namespace caf {
/**
......@@ -272,7 +274,7 @@ class optional<T&> {
template <class T, typename U>
bool operator==(const optional<T>& lhs, const optional<U>& rhs) {
if ((lhs) && (rhs)) {
return *lhs == *rhs;
return detail::safe_equal(*lhs, *rhs);
}
return !lhs && !rhs;
}
......
......@@ -40,13 +40,18 @@ class cooperative_scheduling {
using timeout_type = int;
template <class Actor>
inline void launch(Actor* self, execution_unit* host) {
inline void launch(Actor* self, execution_unit* host, bool lazy) {
// detached in scheduler::worker::run
self->attach_to_scheduler();
if (host)
if (lazy) {
self->mailbox().try_block();
return;
}
if (host) {
host->exec_later(self);
else
} else {
detail::singletons::get_scheduling_coordinator()->enqueue(self);
}
}
template <class Actor>
......
......@@ -125,6 +125,7 @@ class event_based_resume {
auto ptr = d->next_message();
if (ptr) {
if (d->invoke_message(ptr)) {
d->bhvr_stack().cleanup();
++handled_msgs;
if (actor_done()) {
CAF_LOG_DEBUG("actor exited");
......@@ -170,9 +171,8 @@ class event_based_resume {
}
}
catch (std::exception& e) {
CAF_LOG_INFO("actor died because of an exception: "
<< detail::demangle(typeid(e))
<< ", what() = " << e.what());
CAF_LOG_INFO("actor died because of an exception, what: " << e.what());
static_cast<void>(e); // keep compiler happy when not logging
if (d->exit_reason() == exit_reason::not_exited) {
d->quit(exit_reason::unhandled_exception);
}
......
......@@ -153,36 +153,22 @@ class invoke_policy {
auto id = res->template get_as<uint64_t>(1);
auto msg_id = message_id::from_integer_value(id);
auto ref_opt = self->sync_handler(msg_id);
// calls self->response_promise() if hdl is a dummy
// argument, forwards hdl otherwise to reply to the
// original request message
auto fhdl = fetch_response_promise(self, hdl);
// install a behavior that calls the user-defined behavior
// and using the result of its inner behavior as response
if (ref_opt) {
behavior cpy = *ref_opt;
*ref_opt =
cpy.add_continuation([=](message & intermediate)
->optional<message> {
if (!intermediate.empty()) {
// do no use lamba expresion type to
// avoid recursive template instantiaton
behavior::continuation_fun f2 = [=](
message & m)->optional<message> {
return std::move(m);
};
auto mutable_mid = mid;
// recursively call invoke_fun on the
// result to correctly handle stuff like
// sync_send(...).then(...).then(...)...
return this->invoke_fun(self, intermediate,
mutable_mid, f2, fhdl);
auto fhdl = fetch_response_promise(self, hdl);
behavior inner = *ref_opt;
*ref_opt = behavior {
others() >> [=] {
// inner is const inside this lambda and mutable a C++14 feature
behavior cpy = inner;
auto inner_res = cpy(self->last_dequeued());
if (inner_res) {
fhdl.deliver(*inner_res);
}
return none;
});
}
};
}
// reset res to prevent "outer" invoke_fun
// from handling the result again
res->reset();
} else {
// respond by using the result of 'fun'
CAF_LOG_DEBUG("respond via response_promise");
......
......@@ -65,7 +65,7 @@ class no_scheduling {
}
template <class Actor>
void launch(Actor* self, execution_unit*) {
void launch(Actor* self, execution_unit*, bool) {
CAF_REQUIRE(self != nullptr);
CAF_PUSH_AID(self->id());
CAF_LOG_TRACE(CAF_ARG(self));
......
......@@ -20,22 +20,88 @@
#ifndef CAF_REPLIES_TO_HPP
#define CAF_REPLIES_TO_HPP
#include <string>
#include "caf/either.hpp"
#include "caf/uniform_typeid.hpp"
#include "caf/type_name_access.hpp"
#include "caf/uniform_type_info.hpp"
#include "caf/illegal_message_element.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_pair.hpp"
#include "caf/detail/type_traits.hpp"
namespace caf {
/** @cond PRIVATE */
std::string replies_to_type_name(size_t input_size,
const std::string* input,
size_t output_opt1_size,
const std::string* output_opt1,
size_t output_opt2_size,
const std::string* output_opt2);
/** @endcond */
template <class InputTypes, class LeftOutputTypes, class RightOutputTypes>
struct typed_mpi;
template <class... Is, class... Ls, class... Rs>
struct typed_mpi<detail::type_list<Is...>,
detail::type_list<Ls...>,
detail::type_list<Rs...>> {
static_assert(sizeof...(Is) > 0, "template parameter pack Is empty");
static_assert(sizeof...(Ls) > 0, "template parameter pack Ls empty");
using input_types = detail::type_list<Is...>;
using output_opt1_types = detail::type_list<Ls...>;
using output_opt2_types = detail::type_list<Rs...>;
static_assert(!std::is_same<output_opt1_types, output_opt2_types>::value,
"result types must differ when using with_either<>::or_else<>");
static_assert(!detail::tl_exists<
input_types,
is_illegal_message_element
>::value
&& !detail::tl_exists<
output_opt1_types,
is_illegal_message_element
>::value
&& !detail::tl_exists<
output_opt2_types,
is_illegal_message_element
>::value,
"interface definition contains an illegal message type, "
"did you use with<either...> instead of with_either<...>?");
static std::string static_type_name() {
std::string input[] = {type_name_access<Is>::get()...};
std::string output_opt1[] = {type_name_access<Ls>::get()...};
// Rs... is allowed to be empty, hence we need to add a dummy element
// to make sure this array is not of size 0 (to prevent compiler errors)
std::string output_opt2[] = {std::string(), type_name_access<Rs>::get()...};
return replies_to_type_name(sizeof...(Is), input,
sizeof...(Ls), output_opt1,
sizeof...(Rs), output_opt2 + 1);
}
};
template <class... Is>
struct replies_to {
template <class... Os>
struct with {
using input_types = detail::type_list<Is...>;
using output_types = detail::type_list<Os...>;
using with = typed_mpi<detail::type_list<Is...>,
detail::type_list<Os...>,
detail::empty_type_list>;
template <class... Ls>
struct with_either {
template <class... Rs>
using or_else = typed_mpi<detail::type_list<Is...>,
detail::type_list<Ls...>,
detail::type_list<Rs...>>;
};
};
template <class... Is>
using reacts_to = typename replies_to<Is...>::template with<void>;
using reacts_to = typed_mpi<detail::type_list<Is...>,
detail::type_list<void>,
detail::empty_type_list>;
} // namespace caf
......
......@@ -51,7 +51,7 @@ struct blocking_response_handle_tag {};
* This helper class identifies an expected response message
* and enables `sync_send(...).then(...)`.
*/
template <class Self, class Result, class Tag>
template <class Self, class ResultOptPairOrMessage, class Tag>
class response_handle;
/******************************************************************************
......@@ -80,8 +80,7 @@ class response_handle<Self, message, nonblocking_response_handle_tag> {
}
};
m_self->bhvr_stack().push_back(std::move(bhvr), m_mid);
auto ptr = m_self;
return {m_mid, [ptr](message_id mid) { return ptr->sync_handler(mid); }};
return {m_mid};
}
private:
......@@ -92,9 +91,8 @@ class response_handle<Self, message, nonblocking_response_handle_tag> {
/******************************************************************************
* nonblocking + typed *
******************************************************************************/
template <class Self, class... Ts>
class response_handle<Self, detail::type_list<Ts...>,
nonblocking_response_handle_tag> {
template <class Self, class TypedOutputPair>
class response_handle<Self, TypedOutputPair, nonblocking_response_handle_tag> {
public:
response_handle() = delete;
response_handle(const response_handle&) = default;
......@@ -104,28 +102,30 @@ class response_handle<Self, detail::type_list<Ts...>,
// nop
}
template <class F,
class Enable = typename std::enable_if<
detail::is_callable<F>::value
&& !is_match_expr<F>::value
>::type>
template <class... Fs>
typed_continue_helper<
typename detail::lifted_result_type<
typename detail::get_callable_trait<F>::result_type
typename detail::common_result_type<
typename detail::get_callable_trait<Fs>::result_type...
>::type
>::type>
then(F fun) {
detail::assert_types<detail::type_list<Ts...>, F>();
then(Fs... fs) {
static_assert(sizeof...(Fs) > 0, "at least one functor is requried");
static_assert(detail::conjunction<detail::is_callable<Fs>::value...>::value,
"all arguments must be callable");
static_assert(detail::conjunction<!is_match_expr<Fs>::value...>::value,
"match expressions are not allowed in this context");
detail::type_checker<TypedOutputPair, Fs...>::check();
auto selfptr = m_self;
behavior tmp{
fun,
fs...,
on<sync_timeout_msg>() >> [selfptr]() -> skip_message_t {
selfptr->handle_sync_timeout();
return {};
}
};
m_self->bhvr_stack().push_back(std::move(tmp), m_mid);
auto get = [selfptr](message_id mid) { return selfptr->sync_handler(mid); };
return {m_mid, get};
return {m_mid};
}
private:
......@@ -173,12 +173,9 @@ class response_handle<Self, message, blocking_response_handle_tag> {
/******************************************************************************
* blocking + typed *
******************************************************************************/
template <class Self, class... Ts>
class response_handle<Self, detail::type_list<Ts...>,
blocking_response_handle_tag> {
template <class Self, class OutputPair>
class response_handle<Self, OutputPair, blocking_response_handle_tag> {
public:
using result_types = detail::type_list<Ts...>;
response_handle() = delete;
response_handle(const response_handle&) = default;
response_handle& operator=(const response_handle&) = default;
......@@ -187,26 +184,27 @@ class response_handle<Self, detail::type_list<Ts...>,
// nop
}
template <class F>
void await(F fun) {
using arg_types =
typename detail::tl_map<
typename detail::get_callable_trait<F>::arg_types,
std::decay
>::type;
static constexpr size_t fun_args = detail::tl_size<arg_types>::value;
static_assert(fun_args <= detail::tl_size<result_types>::value,
"functor takes too much arguments");
using recv_types =
typename detail::tl_right<
result_types,
fun_args
>::type;
static_assert(std::is_same<arg_types, recv_types>::value,
"wrong functor signature");
static constexpr bool is_either_or_handle =
!std::is_same<
none_t,
typename OutputPair::second
>::value;
template <class... Fs>
void await(Fs... fs) {
static_assert(sizeof...(Fs) > 0,
"at least one argument is required");
static_assert((is_either_or_handle && sizeof...(Fs) == 2)
|| sizeof...(Fs) == 1,
"wrong number of functors");
static_assert(detail::conjunction<detail::is_callable<Fs>::value...>::value,
"all arguments must be callable");
static_assert(detail::conjunction<!is_match_expr<Fs>::value...>::value,
"match expressions are not allowed in this context");
detail::type_checker<OutputPair, Fs...>::check();
auto selfptr = m_self;
behavior tmp{
fun,
fs...,
on<sync_timeout_msg>() >> [selfptr]() -> skip_message_t {
selfptr->handle_sync_timeout();
return {};
......
......@@ -43,10 +43,10 @@ class worker : public execution_unit {
using coordinator_ptr = coordinator<Policy>*;
using policy_data = typename Policy::worker_data;
worker(size_t id, coordinator_ptr parent, size_t max_throughput)
: m_max_throughput(max_throughput),
m_id(id),
m_parent(parent) {
worker(size_t worker_id, coordinator_ptr worker_parent, size_t throughput)
: m_max_throughput(throughput),
m_id(worker_id),
m_parent(worker_parent) {
// nop
}
......
......@@ -26,8 +26,6 @@
#include "caf/uniform_type_info.hpp"
#include "caf/primitive_variant.hpp"
#include "caf/detail/to_uniform_name.hpp"
namespace caf {
class actor_namespace;
......@@ -111,8 +109,7 @@ template <class T>
serializer& operator<<(serializer& s, const T& what) {
auto mtype = uniform_typeid<T>();
if (mtype == nullptr) {
throw std::logic_error("no uniform type info found for "
+ detail::to_uniform_name(typeid(T)));
throw std::logic_error("no uniform type info found for T");
}
mtype->serialize(&what, &s);
return s;
......
......@@ -69,7 +69,7 @@ intrusive_ptr<C> spawn_impl(execution_unit* host,
"spawned without blocking_api_flag");
static_assert(is_unbound(Os),
"top-level spawns cannot have monitor or link flag");
CAF_LOGF_TRACE("spawn " << detail::demangle<C>());
CAF_LOGF_TRACE("");
using scheduling_policy =
typename std::conditional<
has_detach_flag(Os) || has_blocking_api_flag(Os),
......@@ -114,7 +114,7 @@ intrusive_ptr<C> spawn_impl(execution_unit* host,
CAF_LOGF_DEBUG("spawned actor with ID " << ptr->id());
CAF_PUSH_AID(ptr->id());
before_launch_fun(ptr.get());
ptr->launch(has_hide_flag(Os), host);
ptr->launch(has_hide_flag(Os), has_lazy_init_flag(Os), host);
return ptr;
}
......
......@@ -40,8 +40,8 @@ enum class spawn_options : int {
detach_flag = 0x04,
hide_flag = 0x08,
blocking_api_flag = 0x10,
priority_aware_flag = 0x20
priority_aware_flag = 0x20,
lazy_init_flag = 0x40
};
#endif
......@@ -95,6 +95,12 @@ constexpr spawn_options blocking_api = spawn_options::blocking_api_flag;
*/
constexpr spawn_options priority_aware = spawn_options::priority_aware_flag;
/**
* Causes the new actor to delay its
* initialization until a message arrives.
*/
constexpr spawn_options lazy_init = spawn_options::lazy_init_flag;
/**
* Checks wheter `haystack` contains `needle`.
* @relates spawn_options
......@@ -151,6 +157,14 @@ constexpr bool has_blocking_api_flag(spawn_options opts) {
return has_spawn_option(opts, blocking_api);
}
/**
* Checks wheter the {@link lazy_init} flag is set in `opts`.
* @relates spawn_options
*/
constexpr bool has_lazy_init_flag(spawn_options opts) {
return has_spawn_option(opts, lazy_init);
}
/** @} */
/** @cond PRIVATE */
......
......@@ -72,21 +72,22 @@ void splice(std::string& str, const std::string& glue, T&& arg, Ts&&... args) {
splice(str, glue, std::forward<Ts>(args)...);
}
template <size_t WhatSize, size_t WithSize>
template <ptrdiff_t WhatSize, ptrdiff_t WithSize>
void replace_all(std::string& str,
const char (&what)[WhatSize],
const char (&with)[WithSize]) {
// end(what) - 1 points to the null-terminator
auto next = [&](std::string::iterator pos) -> std::string::iterator{
auto next = [&](std::string::iterator pos) -> std::string::iterator {
return std::search(pos, str.end(), std::begin(what), std::end(what) - 1);
};
auto i = next(std::begin(str));
while (i != std::end(str)) {
auto before = static_cast<size_t>(std::distance(std::begin(str), i));
auto before = std::distance(std::begin(str), i);
CAF_REQUIRE(before >= 0);
str.replace(i, i + WhatSize - 1, with);
// i became invalidated -> use new iterator pointing
// to the first character after the replaced text
i = next(std::begin(str) + before + (WithSize - 1));
i = next(str.begin() + before + (WithSize - 1));
}
}
......
......@@ -44,11 +44,6 @@ std::string to_string(const actor_addr& what);
std::string to_string(const actor& what);
/**
* @relates node_id
*/
//std::string to_string(const node_id::host_id_type& node_id);
/**
* @relates node_id
*/
......@@ -60,7 +55,7 @@ std::string to_string(const node_id& what);
std::string to_string(const atom_value& what);
/**
* Converts `e` to a string including the demangled type of `e` and `e.what()`.
* Converts `e` to a string including `e.what()`.
*/
std::string to_verbose_string(const std::exception& e);
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_TYPE_NAME_ACCESS_HPP
#define CAF_TYPE_NAME_ACCESS_HPP
#include <string>
#include "caf/uniform_typeid.hpp"
#include "caf/uniform_type_info.hpp"
#include "caf/detail/type_traits.hpp"
namespace caf {
template <class T, bool HasTypeName = detail::has_static_type_name<T>::value>
struct type_name_access {
static std::string get() {
auto uti = uniform_typeid<T>(true);
return uti ? uti->name() : "void";
}
};
template <class T>
struct type_name_access<T, true> {
static std::string get() {
return T::static_type_name();
}
};
} // namespace caf
#endif // CAF_TYPE_NAME_ACCESS_HPP
......@@ -131,7 +131,7 @@ class typed_actor
}
static std::set<std::string> message_types() {
return {detail::to_uniform_name<Rs>()...};
return {Rs::static_type_name()...};
}
explicit operator bool() const { return static_cast<bool>(m_ptr); }
......
......@@ -20,11 +20,13 @@
#ifndef TYPED_BEHAVIOR_HPP
#define TYPED_BEHAVIOR_HPP
#include "caf/either.hpp"
#include "caf/behavior.hpp"
#include "caf/match_expr.hpp"
#include "caf/system_messages.hpp"
#include "caf/typed_continue_helper.hpp"
#include "caf/detail/ctm.hpp"
#include "caf/detail/typed_actor_util.hpp"
namespace caf {
......@@ -46,17 +48,27 @@ struct input_only<detail::type_list<Ts...>> {
using skip_list = detail::type_list<skip_message_t>;
template <class Opt1, class Opt2>
struct collapse_replies_to_statement {
using type = typename either<Opt1>::template or_else<Opt2>;
};
template <class List>
struct collapse_replies_to_statement<List, none_t> {
using type = List;
};
/*
template <class List>
struct unbox_typed_continue_helper {
// do nothing if List is actually a list, i.e., not a typed_continue_helper
using type = List;
};
template <class List>
struct unbox_typed_continue_helper<
detail::type_list<typed_continue_helper<List>>> {
struct unbox_typed_continue_helper<typed_continue_helper<List>> {
using type = List;
};
*/
template <class Input, class RepliesToWith>
struct same_input : std::is_same<Input, typename RepliesToWith::input_types> {};
......@@ -75,8 +87,9 @@ struct valid_input_predicate {
struct inner {
using input_types = typename Expr::input_types;
using output_types =
typename unbox_typed_continue_helper<
typename Expr::output_types
typename collapse_replies_to_statement<
typename Expr::output_opt1_types,
typename Expr::output_opt2_types
>::type;
// get matching elements for input type
using filtered_slist =
......@@ -215,10 +228,12 @@ class typed_behavior {
template <class... Cs>
void set(match_expr<Cs...>&& expr) {
using input =
detail::type_list<typename detail::deduce_signature<Cs>::type...>;
// check types
detail::static_check_typed_behavior_input<signatures, input>();
using mpi =
typename detail::tl_filter_not<
detail::type_list<typename detail::deduce_mpi<Cs>::type...>,
detail::is_hidden_msg_handler
>::type;
detail::static_asserter<signatures, mpi, detail::ctm>::verify_match();
// final (type-erasure) step
m_bhvr = std::move(expr);
}
......
......@@ -32,10 +32,8 @@ template <class OutputList>
class typed_continue_helper {
public:
using message_id_wrapper_tag = int;
using getter = std::function<optional<behavior&> (message_id msg_id)>;
typed_continue_helper(message_id mid, getter get_sync_handler)
: m_ch(mid, std::move(get_sync_handler)) {
typed_continue_helper(message_id mid) : m_ch(mid) {
// nop
}
......@@ -43,14 +41,6 @@ class typed_continue_helper {
// nop
}
template <class F>
typed_continue_helper<typename detail::get_callable_trait<F>::result_type>
continue_with(F fun) {
detail::assert_types<OutputList, F>();
m_ch.continue_with(std::move(fun));
return {m_ch};
}
message_id get_message_id() const {
return m_ch.get_message_id();
}
......
......@@ -49,7 +49,7 @@ class typed_event_based_actor : public
using behavior_type = typed_behavior<Rs...>;
std::set<std::string> message_types() const override {
return {detail::to_uniform_name<Rs>()...};
return {Rs::static_type_name()...};
}
protected:
......
......@@ -29,20 +29,16 @@
#include <type_traits>
#include "caf/config.hpp"
#include "caf/uniform_typeid.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/detail/demangle.hpp"
#include "caf/detail/to_uniform_name.hpp"
namespace caf {
class serializer;
class deserializer;
class uniform_type_info;
const uniform_type_info* uniform_typeid(const std::type_info&);
struct uniform_value_t;
using uniform_value = std::unique_ptr<uniform_value_t>;
......@@ -203,8 +199,8 @@ class uniform_type_info {
/**
* Creates a copy of `other`.
*/
virtual uniform_value
create(const uniform_value& other = uniform_value{}) const = 0;
virtual uniform_value create(const uniform_value& other
= uniform_value{}) const = 0;
/**
* Deserializes an object of this type from `source`.
......@@ -279,18 +275,14 @@ using uniform_type_info_ptr = std::unique_ptr<uniform_type_info>;
/**
* @relates uniform_type_info
*/
template <class T>
inline const uniform_type_info* uniform_typeid() {
return uniform_typeid(typeid(T));
}
/**
* @relates uniform_type_info
*/
inline bool operator==(const uniform_type_info& lhs,
const uniform_type_info& rhs) {
// uniform_type_info instances are singletons,
// thus, equal == identical
const uniform_type_info& rhs) {
// uniform_type_info instances are singletons
return &lhs == &rhs;
}
......@@ -306,7 +298,7 @@ inline bool operator!=(const uniform_type_info& lhs,
* @relates uniform_type_info
*/
inline bool operator==(const uniform_type_info& lhs,
const std::type_info& rhs) {
const std::type_info& rhs) {
return lhs.equal_to(rhs);
}
......@@ -314,7 +306,7 @@ inline bool operator==(const uniform_type_info& lhs,
* @relates uniform_type_info
*/
inline bool operator!=(const uniform_type_info& lhs,
const std::type_info& rhs) {
const std::type_info& rhs) {
return !(lhs.equal_to(rhs));
}
......@@ -322,7 +314,7 @@ inline bool operator!=(const uniform_type_info& lhs,
* @relates uniform_type_info
*/
inline bool operator==(const std::type_info& lhs,
const uniform_type_info& rhs) {
const uniform_type_info& rhs) {
return rhs.equal_to(lhs);
}
......@@ -330,7 +322,7 @@ inline bool operator==(const std::type_info& lhs,
* @relates uniform_type_info
*/
inline bool operator!=(const std::type_info& lhs,
const uniform_type_info& rhs) {
const uniform_type_info& rhs) {
return !(rhs.equal_to(lhs));
}
......
......@@ -17,24 +17,23 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_TO_UNIFORM_NAME_HPP
#define CAF_DETAIL_TO_UNIFORM_NAME_HPP
#ifndef CAF_UNIFORM_TYPEID_HPP
#define CAF_UNIFORM_TYPEID_HPP
#include <string>
#include <typeinfo>
namespace caf {
namespace detail {
std::string to_uniform_name(const std::string& demangled_name);
std::string to_uniform_name(const std::type_info& tinfo);
class uniform_type_info;
const uniform_type_info* uniform_typeid(const std::type_info& tinf,
bool allow_nullptr = false);
template <class T>
inline std::string to_uniform_name() {
return to_uniform_name(typeid(T));
const uniform_type_info* uniform_typeid(bool allow_nullptr = false) {
return uniform_typeid(typeid(T), allow_nullptr);
}
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_TO_UNIFORM_NAME_HPP
#endif // CAF_UNIFORM_TYPEID_HPP
......@@ -23,11 +23,17 @@
namespace caf {
struct unit_t {
constexpr unit_t() {}
constexpr unit_t(const unit_t&) {}
constexpr unit_t() {
// nop
}
constexpr unit_t(const unit_t&) {
// nop
}
template <class T>
explicit constexpr unit_t(T&&) {}
explicit constexpr unit_t(T&&) {
// nop
}
unit_t& operator=(const unit_t&) = default;
};
static constexpr unit_t unit = unit_t{};
......@@ -35,25 +41,21 @@ static constexpr unit_t unit = unit_t{};
template <class T>
struct lift_void {
using type = T;
};
template <>
struct lift_void<void> {
using type = unit_t;
};
template <class T>
struct unlift_void {
using type = T;
};
template <>
struct unlift_void<unit_t> {
using type = void;
};
} // namespace caf
......
......@@ -94,7 +94,7 @@ class cow_tuple<Head, Tail...> {
return cow_tuple<Tail...>::offset_subtuple(m_vals, 1);
}
inline operator message() {
inline operator message() const {
return message{m_vals};
}
......
......@@ -32,8 +32,6 @@
#include "caf/on.hpp"
#include "caf/optional.hpp"
#include "caf/detail/demangle.hpp"
#include "cppa/opt_impls.hpp"
namespace caf {
......@@ -43,7 +41,8 @@ using string_proj = std::function<optional<std::string> (const std::string&)>;
inline string_proj extract_longopt_arg(const std::string& prefix) {
return [prefix](const std::string& arg) -> optional<std::string> {
if (arg.compare(0, prefix.size(), prefix) == 0) {
return std::string(arg.begin() + prefix.size(), arg.end());
return std::string(arg.begin() + static_cast<ptrdiff_t>(prefix.size()),
arg.end());
}
return none;
};
......
......@@ -93,7 +93,7 @@ class rd_arg_functor {
auto opt = conv_arg_impl<T>::_(arg);
if (!opt) {
std::cerr << "*** error: cannot convert \"" << arg << "\" to "
<< detail::demangle(typeid(T).name())
<< typeid(T).name()
<< " [option: \"" << m_storage->arg_name << "\"]"
<< std::endl;
return false;
......@@ -126,7 +126,7 @@ class add_arg_functor {
auto opt = conv_arg_impl<T>::_(arg);
if (!opt) {
std::cerr << "*** error: cannot convert \"" << arg << "\" to "
<< detail::demangle(typeid(T))
<< typeid(T).name()
<< " [option: \"" << m_storage->arg_name << "\"]"
<< std::endl;
return false;
......
......@@ -32,6 +32,8 @@
#include "caf/detail/types_array.hpp"
#include "caf/detail/decorated_tuple.hpp"
#include "cppa/cow_tuple.hpp"
namespace caf {
template <class TupleIter, class PatternIter,
......@@ -133,8 +135,11 @@ auto moving_tuple_cast(message& tup)
}
}
// same for nil, leading, and trailing
if (std::equal(sub.begin(), sub.end(),
arr_pos, detail::types_only_eq)) {
auto eq = [](const detail::message_iterator& lhs,
const uniform_type_info* rhs) {
return lhs.type() == rhs;
};
if (std::equal(sub.begin(), sub.end(), arr_pos, eq)) {
return result_type::from(sub);
}
return none;
......
......@@ -121,8 +121,9 @@ bool abstract_actor::link_impl(linking_operation op, const actor_addr& other) {
return remove_link_impl(other);
case remove_backlink_op:
return remove_backlink_impl(other);
default:
return false;
}
return false;
}
bool abstract_actor::establish_link_impl(const actor_addr& other) {
......@@ -217,7 +218,7 @@ void abstract_actor::cleanup(uint32_t reason) {
CAF_LOG_INFO_IF(!is_remote(), "cleanup actor with ID "
<< m_id << "; exit reason = "
<< reason << ", class = "
<< detail::demangle(typeid(*this)));
<< class_name());
// send exit messages
for (attachable* i = head.get(); i != nullptr; i = i->next.get()) {
i->actor_exited(this, reason);
......
......@@ -44,7 +44,7 @@ bool abstract_group::subscription::matches(const token& what) {
return ot.group == m_group;
}
abstract_group::module::module(std::string name) : m_name(std::move(name)) {
abstract_group::module::module(std::string mname) : m_name(std::move(mname)) {
// nop
}
......
......@@ -91,7 +91,7 @@ uint32_t actor_registry::next_id() {
}
void actor_registry::inc_running() {
# if CAF_LOG_LEVEL >= CAF_DEBUG
# if defined(CAF_LOG_LEVEL) && CAF_LOG_LEVEL >= CAF_DEBUG
CAF_LOG_DEBUG("new value = " << ++m_running);
# else
++m_running;
......
......@@ -24,57 +24,8 @@
namespace caf {
namespace {
class continuation_decorator : public detail::behavior_impl {
public:
using super = behavior_impl;
using continuation_fun = behavior::continuation_fun;
using pointer = typename behavior_impl::pointer;
continuation_decorator(continuation_fun fun, pointer ptr)
: super(ptr->timeout()), m_fun(fun), m_decorated(std::move(ptr)) {
CAF_REQUIRE(m_decorated != nullptr);
}
template <class T>
inline bhvr_invoke_result invoke_impl(T& tup) {
auto res = m_decorated->invoke(tup);
if (res) {
return m_fun(*res);
}
return none;
}
bhvr_invoke_result invoke(message& tup) {
return invoke_impl(tup);
}
bhvr_invoke_result invoke(const message& tup) {
return invoke_impl(tup);
}
pointer copy(const generic_timeout_definition& tdef) const {
return new continuation_decorator(m_fun, m_decorated->copy(tdef));
}
void handle_timeout() {
m_decorated->handle_timeout();
}
private:
continuation_fun m_fun;
pointer m_decorated;
};
} // namespace <anonymous>
behavior::behavior(const message_handler& mh) : m_impl(mh.as_behavior_impl()) {
// nop
}
behavior behavior::add_continuation(continuation_fun fun) {
return behavior::impl_ptr{new continuation_decorator(std::move(fun), m_impl)};
}
} // namespace caf
......@@ -30,6 +30,10 @@ blocking_actor::blocking_actor() {
is_blocking(true);
}
blocking_actor::~blocking_actor() {
// avoid weak-vtables warning
}
void blocking_actor::await_all_other_actors_done() {
detail::singletons::get_actor_registry()->await_running_count_equal(1);
}
......
......@@ -22,18 +22,8 @@
namespace caf {
continue_helper::continue_helper(message_id mid, getter g)
: m_mid(mid), m_getter(std::move(g)) {}
continue_helper& continue_helper::continue_with(behavior::continuation_fun f) {
auto ref_opt = m_getter(m_mid); //m_self->sync_handler(m_mid);
if (ref_opt) {
behavior cpy = *ref_opt;
*ref_opt = cpy.add_continuation(std::move(f));
} else {
CAF_LOG_ERROR("failed to add continuation");
}
return *this;
continue_helper::continue_helper(message_id mid) : m_mid(mid) {
// nop
}
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/either.hpp"
#include "caf/to_string.hpp"
#include "caf/string_algorithms.hpp"
namespace caf {
std::string either_or_else_type_name(size_t lefts_size,
const std::string* lefts,
size_t rights_size,
const std::string* rights) {
std::string glue = ",";
std::string result;
result = "caf::either<";
result += join(lefts, lefts + lefts_size, glue);
result += ">::or_else<";
result += join(rights, rights + rights_size, glue);
result += ">";
return result;
}
} // namespace caf
......@@ -64,8 +64,8 @@ actor_exited::~actor_exited() noexcept {
// nop
}
actor_exited::actor_exited(uint32_t reason) : caf_exception(ae_what(reason)) {
m_reason = reason;
actor_exited::actor_exited(uint32_t rsn) : caf_exception(ae_what(rsn)) {
m_reason = rsn;
}
network_error::network_error(const std::string& str) : super(str) {
......
/******************************************************************************
* _________________________ *
* __ ____/__ |__ ____/ C++ *
* _ / __ /| |_ /_ Actor *
* / /___ _ ___ | __/ Framework *
* ____/ /_/ |_/_/ *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENCE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
/******************************************************************************\
* Based on work by the mingw-w64 project; *
* original header: *
* *
* Copyright (c) 2012 mingw-w64 project *
* *
* Contributing author: Kai Tietz *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
* DEALINGS IN THE SOFTWARE. *
\ ******************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <sstream>
#include <iostream>
#include "cppa/detail/execinfo_windows.hpp"
namespace cppa {
namespace detail {
int backtrace(void** buffer, int size) {
if (size <= 0) return 0;
auto frames = CaptureStackBackTrace (0, (DWORD) size, buffer, NULL);
return static_cast<int>(frames);
}
void backtrace_symbols_fd(void* const* buffer, int size, int fd) {
std::ostringstream out;
for (int i = 0; i < size; i++) {
out << "[" << std::hex << reinterpret_cast<size_t>(buffer[i])
<< "]" << std::endl;
auto s = out.str();
write(fd, s.c_str(), s.size());
}
_commit(fd);
}
} // namespace detail
} // namespace cppa
......@@ -17,63 +17,63 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/forwarding_actor_proxy.hpp"
#include "caf/send.hpp"
#include "caf/locks.hpp"
#include "caf/to_string.hpp"
#include "caf/io/middleman.hpp"
#include "caf/io/remote_actor_proxy.hpp"
#include "caf/detail/memory.hpp"
#include "caf/detail/logging.hpp"
#include "caf/detail/singletons.hpp"
#include "caf/detail/sync_request_bouncer.hpp"
using namespace std;
namespace caf {
namespace io {
inline sync_request_info* new_req_info(actor_addr sptr, message_id id) {
return detail::memory::create<sync_request_info>(std::move(sptr), id);
}
sync_request_info::~sync_request_info() {
// nop
forwarding_actor_proxy::forwarding_actor_proxy(actor_id aid, node_id nid,
actor mgr)
: actor_proxy(aid, nid),
m_manager(mgr) {
CAF_REQUIRE(mgr != invalid_actor);
CAF_LOG_INFO(CAF_ARG(aid) << ", " << CAF_TARG(nid, to_string));
}
sync_request_info::sync_request_info(actor_addr sptr, message_id id)
: next(nullptr), sender(std::move(sptr)), mid(id) {
// nop
forwarding_actor_proxy::~forwarding_actor_proxy() {
anon_send(m_manager, make_message(atom("_DelProxy"), node(), id()));
}
remote_actor_proxy::remote_actor_proxy(actor_id aid, node_id nid, actor parent)
: super(aid, nid), m_parent(parent) {
CAF_REQUIRE(parent != invalid_actor);
CAF_LOG_INFO(CAF_ARG(aid) << ", " << CAF_TARG(nid, to_string));
actor forwarding_actor_proxy::manager() const {
actor result;
{
shared_lock<detail::shared_spinlock> m_guard(m_manager_mtx);
result = m_manager;
}
return result;
}
remote_actor_proxy::~remote_actor_proxy() {
anon_send(m_parent, make_message(atom("_DelProxy"), node(), id()));
void forwarding_actor_proxy::manager(actor new_manager) {
std::unique_lock<detail::shared_spinlock> m_guard(m_manager_mtx);
m_manager.swap(new_manager);
}
void remote_actor_proxy::forward_msg(const actor_addr& sender, message_id mid,
message msg) {
void forwarding_actor_proxy::forward_msg(const actor_addr& sender,
message_id mid, message msg) {
CAF_LOG_TRACE(CAF_ARG(id()) << ", " << CAF_TSARG(sender) << ", "
<< CAF_MARG(mid, integer_value) << ", "
<< CAF_TSARG(msg));
m_parent->enqueue(
invalid_actor_addr, invalid_message_id,
make_message(atom("_Dispatch"), sender, address(), mid, std::move(msg)),
nullptr);
shared_lock<detail::shared_spinlock> m_guard(m_manager_mtx);
m_manager->enqueue(invalid_actor_addr, invalid_message_id,
make_message(atom("_Dispatch"), sender,
address(), mid, std::move(msg)),
nullptr);
}
void remote_actor_proxy::enqueue(const actor_addr& sender, message_id mid,
message m, execution_unit*) {
void forwarding_actor_proxy::enqueue(const actor_addr& sender, message_id mid,
message m, execution_unit*) {
forward_msg(sender, mid, std::move(m));
}
bool remote_actor_proxy::link_impl(linking_operation op,
const actor_addr& other) {
bool forwarding_actor_proxy::link_impl(linking_operation op,
const actor_addr& other) {
switch (op) {
case establish_link_op:
if (establish_link_impl(other)) {
......@@ -83,7 +83,7 @@ bool remote_actor_proxy::link_impl(linking_operation op,
make_message(atom("_Link"), other));
return true;
}
return false;
break;
case remove_link_op:
if (remove_link_impl(other)) {
// causes remote actor to unlink from (proxy of) other
......@@ -91,7 +91,7 @@ bool remote_actor_proxy::link_impl(linking_operation op,
make_message(atom("_Unlink"), other));
return true;
}
return false;
break;
case establish_backlink_op:
if (establish_backlink_impl(other)) {
// causes remote actor to unlink from (proxy of) other
......@@ -99,7 +99,7 @@ bool remote_actor_proxy::link_impl(linking_operation op,
make_message(atom("_Link"), other));
return true;
}
return false;
break;
case remove_backlink_op:
if (remove_backlink_impl(other)) {
// causes remote actor to unlink from (proxy of) other
......@@ -107,22 +107,21 @@ bool remote_actor_proxy::link_impl(linking_operation op,
make_message(atom("_Unlink"), other));
return true;
}
return false;
break;
}
return false;
}
void remote_actor_proxy::local_link_to(const actor_addr& other) {
void forwarding_actor_proxy::local_link_to(const actor_addr& other) {
establish_link_impl(other);
}
void remote_actor_proxy::local_unlink_from(const actor_addr& other) {
void forwarding_actor_proxy::local_unlink_from(const actor_addr& other) {
remove_link_impl(other);
}
void remote_actor_proxy::kill_proxy(uint32_t reason) {
void forwarding_actor_proxy::kill_proxy(uint32_t reason) {
cleanup(reason);
}
} // namespace io
} // namespace caf
......@@ -134,10 +134,10 @@ std::vector<iface_info> get_mac_addresses() {
oss << hex;
oss.width(2);
oss << ctoi(item->ifr_hwaddr.sa_data[0]);
for (size_t i = 1; i < 6; ++i) {
for (size_t j = 1; j < 6; ++j) {
oss << ":";
oss.width(2);
oss << ctoi(item->ifr_hwaddr.sa_data[i]);
oss << ctoi(item->ifr_hwaddr.sa_data[j]);
}
auto addr = oss.str();
if (addr != "00:00:00:00:00:00") {
......
......@@ -30,7 +30,7 @@ group::group(const invalid_group_t&) : m_ptr(nullptr) {
// nop
}
group::group(abstract_group_ptr ptr) : m_ptr(std::move(ptr)) {
group::group(abstract_group_ptr gptr) : m_ptr(std::move(gptr)) {
// nop
}
......
......@@ -32,7 +32,7 @@ namespace caf {
// later on in spawn(); this prevents subtle bugs that lead to segfaults,
// e.g., when calling address() in the ctor of a derived class
local_actor::local_actor()
: super(1),
: super(size_t{1}),
m_dummy_node(),
m_current_node(&m_dummy_node),
m_planned_exit_reason(exit_reason::not_exited) {
......@@ -103,13 +103,13 @@ void local_actor::reply_message(message&& what) {
if (!whom) {
return;
}
auto& id = m_current_node->mid;
if (id.valid() == false || id.is_response()) {
auto& mid = m_current_node->mid;
if (mid.valid() == false || mid.is_response()) {
send_tuple(actor_cast<channel>(whom), std::move(what));
} else if (!id.is_answered()) {
} else if (!mid.is_answered()) {
auto ptr = actor_cast<actor>(whom);
ptr->enqueue(address(), id.response_id(), std::move(what), host());
id.mark_as_answered();
ptr->enqueue(address(), mid.response_id(), std::move(what), host());
mid.mark_as_answered();
}
}
......@@ -117,10 +117,10 @@ void local_actor::forward_message(const actor& dest, message_priority prio) {
if (!dest) {
return;
}
auto id = (prio == message_priority::high)
? m_current_node->mid.with_high_priority()
: m_current_node->mid.with_normal_priority();
dest->enqueue(m_current_node->sender, id, m_current_node->msg, host());
auto mid = (prio == message_priority::high)
? m_current_node->mid.with_high_priority()
: m_current_node->mid.with_normal_priority();
dest->enqueue(m_current_node->sender, mid, m_current_node->msg, host());
// treat this message as asynchronous message from now on
m_current_node->mid = invalid_message_id;
}
......@@ -130,11 +130,11 @@ void local_actor::send_tuple(message_priority prio, const channel& dest,
if (!dest) {
return;
}
message_id id;
message_id mid;
if (prio == message_priority::high) {
id = id.with_high_priority();
mid = mid.with_high_priority();
}
dest->enqueue(address(), id, std::move(what), host());
dest->enqueue(address(), mid, std::move(what), host());
}
void local_actor::send_exit(const actor_addr& whom, uint32_t reason) {
......@@ -166,8 +166,8 @@ void local_actor::cleanup(uint32_t reason) {
}
void local_actor::quit(uint32_t reason) {
CAF_LOG_TRACE("reason = " << reason << ", class "
<< detail::demangle(typeid(*this)));
CAF_LOG_TRACE("reason = " << reason << ", class = "
<< class_name());
planned_exit_reason(reason);
if (is_blocking()) {
throw actor_exited(reason);
......
......@@ -33,7 +33,7 @@ message::message(message&& other) : m_vals(std::move(other.m_vals)) {
// nop
}
message::message(const data_ptr& vals) : m_vals(vals) {
message::message(const data_ptr& ptr) : m_vals(ptr) {
// nop
}
......@@ -103,4 +103,15 @@ bool message::dynamically_typed() const {
return m_vals ? m_vals->dynamically_typed() : false;
}
message::const_iterator message::begin() const {
return m_vals ? m_vals->begin() : const_iterator{nullptr, 0};
}
/**
* Returns an iterator to the end.
*/
message::const_iterator message::end() const {
return m_vals ? m_vals->end() : const_iterator{nullptr, 0};
}
} // namespace caf
......@@ -46,6 +46,8 @@ class message_builder::dynamic_msg_data : public detail::message_data {
// nop
}
~dynamic_msg_data();
const void* at(size_t pos) const override {
CAF_REQUIRE(pos < size());
return m_elements[pos]->val;
......@@ -76,6 +78,10 @@ class message_builder::dynamic_msg_data : public detail::message_data {
std::vector<uniform_value> m_elements;
};
message_builder::dynamic_msg_data::~dynamic_msg_data() {
// avoid weak-vtables warning
}
message_builder::message_builder() {
init();
}
......
......@@ -27,9 +27,13 @@ message_data::message_data(bool is_dynamic) : m_is_dynamic(is_dynamic) {
}
bool message_data::equals(const message_data& other) const {
auto full_eq = [](const message_iterator& lhs, const message_iterator& rhs) {
return lhs.type() == rhs.type()
&& lhs.type()->equals(lhs.value(), rhs.value());
};
return this == &other
|| (size() == other.size()
&& std::equal(begin(), end(), other.begin(), detail::full_eq));
&& std::equal(begin(), end(), other.begin(), full_eq));
}
message_data::message_data(const message_data& other)
......
......@@ -17,24 +17,26 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_DEMANGLE_HPP
#define CAF_DETAIL_DEMANGLE_HPP
#include "caf/detail/message_iterator.hpp"
#include <string>
#include <typeinfo>
#include "caf/detail/message_data.hpp"
namespace caf {
namespace detail {
std::string demangle(const char* typeid_name);
std::string demangle(const std::type_info& tinf);
message_iterator::message_iterator(const_pointer dataptr, size_t pos)
: m_pos(pos),
m_data(dataptr) {
// nop
}
const void* message_iterator::value() const {
return m_data->at(m_pos);
}
template <class T>
inline std::string demangle() {
return demangle(typeid(T));
const uniform_type_info* message_iterator::type() const {
return m_data->type_at(m_pos);
}
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_DEMANGLE_HPP
......@@ -68,8 +68,9 @@ void host_id_from_string(const std::string& hash,
for (size_t i = 0; i < node_id.size(); ++i) {
// read two characters, each representing 4 bytes
auto& val = node_id[i];
val = static_cast<uint8_t>(hex_char_value(*j++) << 4);
val |= hex_char_value(*j++);
val = static_cast<uint8_t>(hex_char_value(j[0]) << 4)
| hex_char_value(j[1]);
j += 2;
}
}
......@@ -84,8 +85,9 @@ bool equal(const std::string& hash, const node_id::host_id_type& node_id) {
for (size_t i = 0; i < node_id.size(); ++i) {
// read two characters, each representing 4 bytes
uint8_t val;
val = static_cast<uint8_t>(hex_char_value(*j++) << 4);
val |= hex_char_value(*j++);
val = static_cast<uint8_t>(hex_char_value(j[0]) << 4)
| hex_char_value(j[1]);
j += 2;
if (val != node_id[i]) {
return false;
}
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/replies_to.hpp"
#include "caf/to_string.hpp"
#include "caf/string_algorithms.hpp"
namespace caf {
std::string replies_to_type_name(size_t input_size,
const std::string* input,
size_t output_opt1_size,
const std::string* output_opt1,
size_t output_opt2_size,
const std::string* output_opt2) {
std::string glue = ",";
std::string result;
// 'void' is not an announced type, hence we check whether uniform_typeid
// did return a valid pointer to identify 'void' (this has the
// possibility of false positives, but those will be catched anyways)
result = "caf::replies_to<";
result += join(input, input + input_size, glue);
if (output_opt2_size == 0) {
result += ">::with<";
result += join(output_opt1, output_opt1 + output_opt1_size, glue);
} else {
result += ">::with_either<";
result += join(output_opt1, output_opt1 + output_opt1_size, glue);
result += ">::or_else<";
result += join(output_opt2, output_opt2 + output_opt2_size, glue);
}
result += ">";
return result;
}
} // namespace caf
......@@ -65,12 +65,16 @@ namespace {
using byte = unsigned char;
using dword = uint32_t;
static_assert(sizeof(dword) == sizeof(unsigned), "platform not supported");
// macro definitions
// collect four bytes into one word:
#define BYTES_TO_DWORD(strptr) \
(((dword) * ((strptr) + 3) << 24) | ((dword) * ((strptr) + 2) << 16) \
| ((dword) * ((strptr) + 1) << 8) | ((dword) * (strptr)))
((static_cast<dword>(*((strptr) + 3)) << 24) \
| (static_cast<dword>(*((strptr) + 2)) << 16) \
| (static_cast<dword>(*((strptr) + 1)) << 8) \
| (static_cast<dword>(*(strptr))))
// ROL(x, n) cyclically rotates x over n bits to the left
// x must be of an unsigned 32 bits type and 0 <= n < 32.
......@@ -93,28 +97,28 @@ using dword = uint32_t;
#define GG(a, b, c, d, e, x, s) \
{ \
(a) += G((b), (c), (d)) + (x) + 0x5a827999UL; \
(a) += G((b), (c), (d)) + (x) + 0x5a827999U; \
(a) = ROL((a), (s)) + (e); \
(c) = ROL((c), 10); \
}
#define HH(a, b, c, d, e, x, s) \
{ \
(a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL; \
(a) += H((b), (c), (d)) + (x) + 0x6ed9eba1U; \
(a) = ROL((a), (s)) + (e); \
(c) = ROL((c), 10); \
}
#define II(a, b, c, d, e, x, s) \
{ \
(a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL; \
(a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcU; \
(a) = ROL((a), (s)) + (e); \
(c) = ROL((c), 10); \
}
#define JJ(a, b, c, d, e, x, s) \
{ \
(a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL; \
(a) += J((b), (c), (d)) + (x) + 0xa953fd4eU; \
(a) = ROL((a), (s)) + (e); \
(c) = ROL((c), 10); \
}
......@@ -128,28 +132,28 @@ using dword = uint32_t;
#define GGG(a, b, c, d, e, x, s) \
{ \
(a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL; \
(a) += G((b), (c), (d)) + (x) + 0x7a6d76e9U; \
(a) = ROL((a), (s)) + (e); \
(c) = ROL((c), 10); \
}
#define HHH(a, b, c, d, e, x, s) \
{ \
(a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL; \
(a) += H((b), (c), (d)) + (x) + 0x6d703ef3U; \
(a) = ROL((a), (s)) + (e); \
(c) = ROL((c), 10); \
}
#define III(a, b, c, d, e, x, s) \
{ \
(a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL; \
(a) += I((b), (c), (d)) + (x) + 0x5c4dd124U; \
(a) = ROL((a), (s)) + (e); \
(c) = ROL((c), 10); \
}
#define JJJ(a, b, c, d, e, x, s) \
{ \
(a) += J((b), (c), (d)) + (x) + 0x50a28be6UL; \
(a) += J((b), (c), (d)) + (x) + 0x50a28be6U; \
(a) = ROL((a), (s)) + (e); \
(c) = ROL((c), 10); \
}
......@@ -360,10 +364,10 @@ void MDfinish(dword* MDbuf, const byte* strptr, dword lswlen, dword mswlen) {
// put bytes from strptr into X
for (unsigned int i = 0; i < (lswlen & 63); ++i) {
// byte i goes into word X[i div 4] at pos. 8*(i mod 4)
X[i >> 2] ^= (dword) * strptr++ << (8 * (i & 3));
X[i >> 2] ^= static_cast<dword>(*strptr++) << (8 * (i & 3));
}
// append the bit m_n == 1
X[(lswlen >> 2) & 15] ^= (dword)1 << (8 * (lswlen & 3) + 7);
X[(lswlen >> 2) & 15] ^= static_cast<dword>(1) << (8 * (lswlen & 3) + 7);
if ((lswlen & 63) > 55) {
// length goes to next block
compress(MDbuf, X);
......
......@@ -609,7 +609,7 @@ string to_string(const node_id& what) {
string to_verbose_string(const std::exception& e) {
std::ostringstream oss;
oss << detail::demangle(typeid(e)) << ": " << e.what();
oss << "std::exception, what(): " << e.what();
return oss.str();
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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