diff -Nru actor-framework-0.13.2/.clang-format actor-framework-0.16.3/.clang-format --- actor-framework-0.13.2/.clang-format 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/.clang-format 2018-12-27 20:33:32.000000000 +0000 @@ -1,14 +1,15 @@ --- -AccessModifierOffset: -1 +AccessModifierOffset: -2 AlignEscapedNewlinesLeft: false AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: false AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: true BinPackParameters: true -BreakBeforeBinaryOperators: true +BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Attach BreakBeforeTernaryOperators: false ColumnLimit: 80 @@ -17,13 +18,18 @@ ContinuationIndentWidth: 2 Cpp11BracedListStyle: true IndentCaseLabels: true -IndentFunctionDeclarationAfterType: false IndentWidth: 2 MaxEmptyLinesToKeep: 1 NamespaceIndentation: None -PointerBindsToType: true + +# Force pointers to the type +DerivePointerAlignment: false +PointerAlignment: Left + +# Put space after = and after control statements SpaceBeforeAssignmentOperators: true -SpaceAfterControlStatementKeyword: true +SpaceBeforeParens: ControlStatements + SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false diff -Nru actor-framework-0.13.2/.clang-tidy actor-framework-0.16.3/.clang-tidy --- actor-framework-0.13.2/.clang-tidy 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/.clang-tidy 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,30 @@ +--- +Checks: 'clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-alpha*,modernize-*,performance-*,readability-*,-readability-braces-around-statements,-readability-named-parameter' +WarningsAsErrors: '' +HeaderFilterRegex: '/caf/' +AnalyzeTemporaryDtors: false +CheckOptions: + - key: cert-oop11-cpp.UseCERTSemantics + value: '1' + - key: google-readability-braces-around-statements.ShortStatementLines + value: '1' + - key: google-readability-function-size.StatementThreshold + value: '800' + - key: google-readability-namespace-comments.ShortNamespaceLines + value: '10' + - key: google-readability-namespace-comments.SpacesBeforeComments + value: '2' + - key: modernize-loop-convert.MaxCopySize + value: '16' + - key: modernize-loop-convert.MinConfidence + value: reasonable + - key: modernize-loop-convert.NamingStyle + value: CamelCase + - key: modernize-pass-by-value.IncludeStyle + value: llvm + - key: modernize-replace-auto-ptr.IncludeStyle + value: llvm + - key: modernize-use-nullptr.NullMacros + value: 'NULL' +... + diff -Nru actor-framework-0.13.2/cmake/build_config.hpp.in actor-framework-0.16.3/cmake/build_config.hpp.in --- actor-framework-0.13.2/cmake/build_config.hpp.in 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/cmake/build_config.hpp.in 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,33 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright (C) 2011 - 2016 * + * Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include "caf/detail/log_level.hpp" + +// this header is auto-generated by CMake + +#define CAF_LOG_LEVEL CAF_LOG_LEVEL_@CAF_LOG_LEVEL@ + +#cmakedefine CAF_NO_MEM_MANAGEMENT + +#cmakedefine CAF_ENABLE_RUNTIME_CHECKS + +#cmakedefine CAF_NO_EXCEPTIONS + diff -Nru actor-framework-0.13.2/cmake/FindCAF.cmake actor-framework-0.16.3/cmake/FindCAF.cmake --- actor-framework-0.13.2/cmake/FindCAF.cmake 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/cmake/FindCAF.cmake 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,121 @@ +# Try to find CAF headers and libraries. +# +# Use this module as follows: +# +# find_package(CAF [COMPONENTS *] [REQUIRED]) +# +# Variables used by this module (they can change the default behaviour and need +# to be set before calling find_package): +# +# CAF_ROOT_DIR Set this variable either to an installation prefix or to wa +# CAF build directory where to look for the CAF libraries. +# +# Variables defined by this module: +# +# CAF_FOUND System has CAF headers and library +# CAF_LIBRARIES List of library files for all components +# CAF_INCLUDE_DIRS List of include paths for all components +# CAF_LIBRARY_$C Library file for component $C +# CAF_INCLUDE_DIR_$C Include path for component $C + +if(CAF_FIND_COMPONENTS STREQUAL "") + message(FATAL_ERROR "FindCAF requires at least one COMPONENT.") +endif() + +# iterate over user-defined components +foreach (comp ${CAF_FIND_COMPONENTS}) + # we use uppercase letters only for variable names + string(TOUPPER "${comp}" UPPERCOMP) + if ("${comp}" STREQUAL "core") + set(HDRNAME "caf/all.hpp") + elseif ("${comp}" STREQUAL "test") + set(HDRNAME "caf/test/unit_test.hpp") + else () + set(HDRNAME "caf/${comp}/all.hpp") + endif () + if (CAF_ROOT_DIR) + set(header_hints + "${CAF_ROOT_DIR}/include" + "${CAF_ROOT_DIR}/libcaf_${comp}" + "${CAF_ROOT_DIR}/../libcaf_${comp}" + "${CAF_ROOT_DIR}/../../libcaf_${comp}") + endif () + find_path(CAF_INCLUDE_DIR_${UPPERCOMP} + NAMES + ${HDRNAME} + HINTS + ${header_hints} + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ${CMAKE_INSTALL_PREFIX}/include) + mark_as_advanced(CAF_INCLUDE_DIR_${UPPERCOMP}) + if (NOT "${CAF_INCLUDE_DIR_${UPPERCOMP}}" + STREQUAL "CAF_INCLUDE_DIR_${UPPERCOMP}-NOTFOUND") + # mark as found (set back to false when missing library or build header) + set(CAF_${comp}_FOUND true) + # check for CMake-generated build header for the core component + if ("${comp}" STREQUAL "core") + find_path(caf_build_header_path + NAMES + caf/detail/build_config.hpp + HINTS + ${header_hints} + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ${CMAKE_INSTALL_PREFIX}/include) + if ("${caf_build_header_path}" STREQUAL "caf_build_header_path-NOTFOUND") + message(WARNING "Found all.hpp for CAF core, but not build_config.hpp") + set(CAF_${comp}_FOUND false) + else() + list(APPEND CAF_INCLUDE_DIRS "${caf_build_header_path}") + endif() + endif() + list(APPEND CAF_INCLUDE_DIRS "${CAF_INCLUDE_DIR_${UPPERCOMP}}") + # look for (.dll|.so|.dylib) file, again giving hints for non-installed CAFs + # skip probe_event as it is header only + if (NOT ${comp} STREQUAL "probe_event" AND NOT ${comp} STREQUAL "test") + if (CAF_ROOT_DIR) + set(library_hints "${CAF_ROOT_DIR}/lib") + endif () + find_library(CAF_LIBRARY_${UPPERCOMP} + NAMES + "caf_${comp}" + "caf_${comp}_static" + HINTS + ${library_hints} + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ${CMAKE_INSTALL_PREFIX}/lib) + mark_as_advanced(CAF_LIBRARY_${UPPERCOMP}) + if ("${CAF_LIBRARY_${UPPERCOMP}}" + STREQUAL "CAF_LIBRARY_${UPPERCOMP}-NOTFOUND") + set(CAF_${comp}_FOUND false) + else () + set(CAF_LIBRARIES ${CAF_LIBRARIES} ${CAF_LIBRARY_${UPPERCOMP}}) + endif () + endif () + endif () +endforeach () + +if (DEFINED CAF_INCLUDE_DIRS) + list(REMOVE_DUPLICATES CAF_INCLUDE_DIRS) +endif() + +# let CMake check whether all requested components have been found +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CAF + FOUND_VAR CAF_FOUND + REQUIRED_VARS CAF_LIBRARIES CAF_INCLUDE_DIRS + HANDLE_COMPONENTS) + +# final step to tell CMake we're done +mark_as_advanced(CAF_ROOT_DIR + CAF_LIBRARIES + CAF_INCLUDE_DIRS) + diff -Nru actor-framework-0.13.2/cmake/FindLibcaf.cmake actor-framework-0.16.3/cmake/FindLibcaf.cmake --- actor-framework-0.13.2/cmake/FindLibcaf.cmake 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/cmake/FindLibcaf.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -# Try to find libcaf headers and library. -# -# Use this module as follows: -# -# find_package(Libcaf) -# -# Variables used by this module (they can change the default behaviour and need -# to be set before calling find_package): -# -# LIBCAF_ROOT_DIR Set this variable to the root installation of -# libcaf if the module has problems finding -# the proper installation path. -# -# Variables defined by this module: -# -# LIBCAF_FOUND System has libcaf headers and library -# LIBCAF_LIBRARIES List of library files for all components -# LIBCAF_INCLUDE_DIRS List of include paths for all components -# LIBCAF_LIBRARY_$C Library file for component $C -# LIBCAF_INCLUDE_DIR_$C Include path for component $C - -# iterate over user-defined components -foreach (comp ${Libcaf_FIND_COMPONENTS}) - # we use uppercase letters only for variable names - string(TOUPPER "${comp}" UPPERCOMP) - if ("${comp}" STREQUAL "core") - set(HDRNAME "caf/all.hpp") - else () - set(HDRNAME "caf/${comp}/all.hpp") - endif () - # look for headers: give CMake hints where to find non-installed CAF versions - # note that we look for the headers of each component individually: this is - # necessary to support non-installed versions of CAF, i.e., accessing the - # checked out "actor-framework" or "caf" directory structure directly; - # also check whether LIBCAF_ROOT_DIR is a source directory - set(HDRHINT "${LIBCAF_ROOT_DIR}/libcaf_${comp}") - foreach(dir ".." "../.." "../../..") - foreach(subdir "actor-framework" "caf") - set(HDRHINT ${HDRHINT} "${dir}/${subdir}/libcaf_${comp}") - endforeach() - endforeach() - find_path(LIBCAF_INCLUDE_DIR_${UPPERCOMP} - NAMES - ${HDRNAME} - HINTS - ${LIBCAF_ROOT_DIR}/include - /usr/include - /usr/local/include - /opt/local/include - /sw/include - ${CMAKE_INSTALL_PREFIX}/include - ${HDRHINT}) - mark_as_advanced(LIBCAF_INCLUDE_DIR_${UPPERCOMP}) - if (NOT "${LIBCAF_INCLUDE_DIR_${UPPERCOMP}}" STREQUAL "LIBCAF_INCLUDE_DIR_${UPPERCOMP}-NOTFOUND") - # mark as found (set back to false in case library cannot be found) - set(Libcaf_${comp}_FOUND true) - # add to LIBCAF_INCLUDE_DIRS only if path isn't already set - set(duplicate false) - foreach (p ${LIBCAF_INCLUDE_DIRS}) - if (${p} STREQUAL ${LIBCAF_INCLUDE_DIR_${UPPERCOMP}}) - set(duplicate true) - endif () - endforeach () - if (NOT duplicate) - set(LIBCAF_INCLUDE_DIRS ${LIBCAF_INCLUDE_DIRS} ${LIBCAF_INCLUDE_DIR_${UPPERCOMP}}) - endif() - # look for (.dll|.so|.dylib) file, again giving hints for non-installed CAFs - # skip probe_event as it is header only - if (NOT ${comp} STREQUAL "probe_event") - unset(LIBHINT) - foreach(dir ".." "../.." "../../..") - foreach(subdir "actor-framework" "caf") - set(LIBHINT ${LIBHINT} "${dir}/${subdir}/build/lib") - endforeach() - endforeach() - message(STATUS "libhint: ${LIBHINT}") - find_library(LIBCAF_LIBRARY_${UPPERCOMP} - NAMES - "caf_${comp}" - HINTS - ${LIBCAF_ROOT_DIR}/lib - ${LIBCAF_ROOT_DIR}/build/lib - /usr/lib - /usr/local/lib - /opt/local/lib - /sw/lib - ${CMAKE_INSTALL_PREFIX}/lib - ${LIBHINT}) - mark_as_advanced(LIBCAF_LIBRARY_${UPPERCOMP}) - if ("${LIBCAF_LIBRARY_${UPPERCOMP}}" STREQUAL "LIBCAF_LIBRARY-NOTFOUND") - set(Libcaf_${comp}_FOUND false) - else () - set(LIBCAF_LIBRARIES ${LIBCAF_LIBRARIES} ${LIBCAF_LIBRARY_${UPPERCOMP}}) - endif () - endif () - endif () -endforeach () - -# let CMake check whether all requested components have been found -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Libcaf - FOUND_VAR LIBCAF_FOUND - REQUIRED_VARS LIBCAF_LIBRARIES LIBCAF_INCLUDE_DIRS - HANDLE_COMPONENTS) - -# final step to tell CMake we're done -mark_as_advanced(LIBCAF_ROOT_DIR - LIBCAF_LIBRARIES - LIBCAF_INCLUDE_DIRS) diff -Nru actor-framework-0.13.2/cmake/FindOPENCL.cmake actor-framework-0.16.3/cmake/FindOPENCL.cmake --- actor-framework-0.13.2/cmake/FindOPENCL.cmake 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/cmake/FindOPENCL.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -# - Try to find OpenCL -# Once done this will define -# -# OpenCL_FOUND - system has OpenCL -# OpenCL_INCLUDE_DIRS - the OpenCL include directory -# OpenCL_LIBRARIES - link these to use OpenCL -# -# WIN32 should work, but is untested - -IF (WIN32) - - FIND_PATH(OpenCL_INCLUDE_DIRS CL/cl.h ) - - # TODO this is only a hack assuming the 64 bit library will - # not be found on 32 bit system - FIND_LIBRARY(OpenCL_LIBRARIES opencl ) #used to say opencl64 - IF( OpenCL_LIBRARIES ) - FIND_LIBRARY(OpenCL_LIBRARIES opencl ) #used to say opencl32 - ENDIF( OpenCL_LIBRARIES ) - -ELSE (WIN32) - - FIND_LIBRARY(OpenCL_LIBRARIES OpenCL ENV LD_LIBRARY_PATH) - message("-- Found OpenCL: ${OpenCL_LIBRARIES}") - -ENDIF (WIN32) - -SET( OpenCL_FOUND "NO" ) -IF(OpenCL_LIBRARIES ) - SET( OpenCL_FOUND "YES" ) -ENDIF(OpenCL_LIBRARIES) - -MARK_AS_ADVANCED( - OpenCL_INCLUDE_DIRS - OpenCL_LIBRARIES -) - - diff -Nru actor-framework-0.13.2/cmake/jenkins.cmake actor-framework-0.16.3/cmake/jenkins.cmake --- actor-framework-0.13.2/cmake/jenkins.cmake 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/cmake/jenkins.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -set(LABEL_EXPR "$ENV{label_exp}") -if ("${LABEL_EXPR}" MATCHES "gcc") - message(STATUS "Set CXX to g++ based on label_expr content") - set(CMAKE_C_COMPILER "gcc" CACHE PATH "c++ compiler option") - set(CMAKE_CXX_COMPILER "g++" CACHE PATH "c++ compiler option") -elseif ("${LABEL_EXPR}" MATCHES "clang") - message(STATUS "Set CXX to clang++ based on label_expr content") - set(CMAKE_C_COMPILER "clang" CACHE STRING "c++ compiler option") - set(CMAKE_CXX_COMPILER "clang++" CACHE STRING "c++ compiler option") -endif() diff -Nru actor-framework-0.13.2/cmake/MSVC_v140_clang_c2.cmake actor-framework-0.16.3/cmake/MSVC_v140_clang_c2.cmake --- actor-framework-0.13.2/cmake/MSVC_v140_clang_c2.cmake 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/cmake/MSVC_v140_clang_c2.cmake 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,5 @@ +## FLAGS FOR MSVC v140_clang_c2 +set(CMAKE_CXX_FLAGS_DEBUG_INIT "/D_DEBUG /MTd /GR -Od -g2 -gdwarf-2 -std=c++1z -fms-extensions -fexceptions") +set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "/MT /GR -O1 /D NDEBUG -std=c++1z -fms-extensions -fexceptions") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "/MT /GR -O3 /D NDEBUG -std=c++1z -fms-extensions -fexceptions") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "/MT /GR -O2 /D NDEBUG -gline-tables-only -std=c++1z -fms-extensions -fexceptions") diff -Nru actor-framework-0.13.2/CMakeLists.txt actor-framework-0.16.3/CMakeLists.txt --- actor-framework-0.13.2/CMakeLists.txt 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/CMakeLists.txt 2018-12-27 20:33:32.000000000 +0000 @@ -1,31 +1,131 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.8.12) project(caf C CXX) -# silence policy CMP0042 warning by enabling RPATH explicitly +include(CheckCSourceCompiles) +include(CheckCSourceRuns) + +# Be nice to VIM users and Clang tools. +set(CMAKE_EXPORT_COMPILE_COMMANDS 1) + +# Silence policy CMP0042 warning by enabling RPATH explicitly. if(APPLE AND NOT DEFINED CMAKE_MACOSX_RPATH) set(CMAKE_MACOSX_RPATH true) endif() +# Shared libs are currently not supported on Windows. +if(WIN32 AND NOT CAF_BUILD_STATIC_ONLY) + message(STATUS "CAF currently only supports static-only builds on Windows") + set(CAF_BUILD_STATIC_ONLY yes) +endif() + +if(CAF_BUILD_STATIC_RUNTIME) + set(flags_configs + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_C_FLAGS + CMAKE_C_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_C_FLAGS_MINSIZEREL + ) + foreach(flags ${flags_configs}) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if(NOT ${flags} MATCHES "-static-libstdc\\+\\+") + set(${flags} "${${flags}} -static-libstdc++") + endif() + if(NOT ${flags} MATCHES "-static-libgcc") + set(${flags} "${${flags}} -static-libgcc") + endif() + elseif(MSVC) + if(${flags} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flags} "${${flags}}") + endif() + endif() + endforeach() +else() + set(CAF_BUILD_STATIC_RUNTIME no) +endif() + +# add helper target that simplifies re-running configure +add_custom_target(configure COMMAND ${CMAKE_CURRENT_BINARY_DIR}/config.status) + ################################################################################ -# make sure all variables are set to "no" if undefined for summary output # +# utility functions # ################################################################################ -if(NOT CAF_ENABLE_RUNTIME_CHECKS) - set(CAF_ENABLE_RUNTIME_CHECKS no) -endif() -if(NOT CAF_NO_MEM_MANAGEMENT) - set(CAF_NO_MEM_MANAGEMENT no) -endif() -if(NOT CAF_BUILD_STATIC_ONLY) - set(CAF_BUILD_STATIC_ONLY no) -endif() -if(NOT CAF_BUILD_STATIC) - set(CAF_BUILD_STATIC no) -endif() -if(NOT CAF_NO_OPENCL) - set(CAF_NO_OPENCL no) -endif() +# Appends `str` to the variable named `var` with a whitespace as separator. +# Suppresses a leading whitespace if the variable is empty and does nothing if +# `str` is empty. +function(build_string var str) + if(NOT str STREQUAL "") + if("${${var}}" STREQUAL "") + set("${var}" "${str}" PARENT_SCOPE) + else() + set("${var}" "${${var}} ${str}" PARENT_SCOPE) + endif() + endif() +endfunction(build_string) + +# Forces `var` to 'no' if the content of the variables evaluates to false. +function(pretty_no var) + if(NOT "${${var}}") + set("${var}" no PARENT_SCOPE) + endif() +endfunction(pretty_no) + +# Forces `var` to 'yes' if the content of the variables evaluates to false. +function(pretty_yes var) + if("${${var}}") + set("${var}" yes PARENT_SCOPE) + endif() +endfunction(pretty_yes) + +################################################################################ +# set prefix paths if available # +################################################################################ + +build_string("CMAKE_PREFIX_PATH" "${CAF_QT_PREFIX_PATH}") +################################################################################ +# enable ccache if required by user # +################################################################################ + +if(CAF_USE_CCACHE) + find_program(CCACHE_PROGRAM ccache) + if(CCACHE_PROGRAM) + message(STATUS "Using ccache command: ${CCACHE_PROGRAM}") + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") + else() + message(STATUS "Unable to find ccache") + endif() +endif(CAF_USE_CCACHE) + +################################################################################ +# make sure config parameters are printed with yes or no in summary # +################################################################################ + +pretty_yes("CAF_FORCE_NO_EXCEPTIONS") + +pretty_no("CAF_ENABLE_RUNTIME_CHECKS") +pretty_no("CAF_NO_MEM_MANAGEMENT") +pretty_no("CAF_NO_EXCEPTIONS") +pretty_no("CAF_BUILD_STATIC_ONLY") +pretty_no("CAF_BUILD_STATIC") +pretty_no("CAF_NO_OPENCL") +pretty_no("CAF_NO_OPENSSL") +pretty_no("CAF_NO_PYTHON") +pretty_no("CAF_NO_TOOLS") +pretty_no("CAF_NO_SUMMARY") + +if(NOT CAF_NO_IO) + set(CAF_NO_IO no) +else() + set(CAF_NO_TOOLS yes) + set(CAF_NO_PYTHON yes) +endif() ################################################################################ # get version of CAF # @@ -51,7 +151,7 @@ ################################################################################ # prohibit in-source builds -if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") +if(CMAKE_CURRENT_SOURCE_DIR STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") message(FATAL_ERROR "In-source builds are not allowed. Please use " "./configure to choose a build directory and " "initialize the build configuration.") @@ -59,14 +159,14 @@ # set module path appropriately set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # set binary output path if not defined by user -if("${EXECUTABLE_OUTPUT_PATH}" STREQUAL "") +if(EXECUTABLE_OUTPUT_PATH STREQUAL "") set(EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/bin") endif() # set library output path if not defined by user, but always set # library output path to binary output path for Xcode projects -if("${CMAKE_GENERATOR}" STREQUAL "Xcode") +if(CMAKE_GENERATOR STREQUAL "Xcode") set(LIBRARY_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}") -elseif("${LIBRARY_OUTPUT_PATH}" STREQUAL "") +elseif(LIBRARY_OUTPUT_PATH STREQUAL "") set(LIBRARY_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/lib") endif() @@ -75,8 +175,8 @@ # compiler setup # ################################################################################ -# check for g++ >= 4.7 or clang++ > = 3.2 -if(NOT WIN32 AND NOT NO_COMPILER_CHECK) +# check for g++ >= 4.8 or clang++ > = 3.2 +if(NOT WIN32 AND NOT CAF_NO_COMPILER_CHECK AND NOT CMAKE_CROSSCOMPILING) try_run(ProgramResult CompilationSucceeded "${CMAKE_CURRENT_BINARY_DIR}" @@ -84,13 +184,13 @@ RUN_OUTPUT_VARIABLE CompilerVersion) if(NOT CompilationSucceeded OR NOT ProgramResult EQUAL 0) message(FATAL_ERROR "Cannot determine compiler version") - elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") - if(CompilerVersion VERSION_GREATER 4.6) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if(CompilerVersion VERSION_GREATER 4.7) message(STATUS "Found g++ version ${CompilerVersion}") else() - message(FATAL_ERROR "g++ >= 4.7 required (found: ${CompilerVersion})") + message(FATAL_ERROR "g++ >= 4.8 required (found: ${CompilerVersion})") endif() - elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") if(CompilerVersion VERSION_GREATER 3.1) message(STATUS "Found clang++ version ${CompilerVersion}") else() @@ -102,21 +202,43 @@ endif() endif() # set optional build flags -set(EXTRA_FLAGS "") +# increase max. template depth on GCC and Clang +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" + OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") + build_string("EXTRA_FLAGS" "-ftemplate-depth=512 -ftemplate-backtrace-limit=0") +endif() +# explicitly disable obnoxious GCC warnings +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + build_string("EXTRA_FLAGS" "-Wno-missing-field-initializers") +endif() # add "-Werror" flag if --pedantic-build is used -if(CXX_WARNINGS_AS_ERROS) - set(EXTRA_FLAGS "-Werror") +if(CAF_CXX_WARNINGS_AS_ERRORS) + build_string("EXTRA_FLAGS" "-Werror") +endif() +# set compiler flags for GCOV if requested +if(CAF_ENABLE_GCOV) + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(NO_INLINE "-fno-inline") + else() + set(NO_INLINE "-fno-inline -fno-inline-small-functions -fno-default-inline") + endif() + build_string("EXTRA_FLAGS" "-fprofile-arcs -ftest-coverage ${NO_INLINE}") +endif() +# set -fno-exception if requested +if(CAF_FORCE_NO_EXCEPTIONS) + build_string("EXTRA_FLAGS" "-fno-exceptions") endif() # enable a ton of warnings if --more-clang-warnings is used -if(MORE_WARNINGS) - if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") +if(CAF_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-abstract-vbase-init -Wno-shadow " "-Wno-missing-noreturn -Wno-covered-switch-default") - elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + 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 " @@ -128,21 +250,22 @@ "-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 " + "-Wmissing-braces -Wmultichar " "-Wnarrowing -Wnoexcept -Wnon-template-friend " "-Wnon-virtual-dtor -Wnonnull -Woverflow " "-Woverlength-strings -Wparentheses " "-Wpmf-conversions -Wpointer-arith -Wreorder " - "-Wreturn-type -Wsequence-point -Wshadow " + "-Wreturn-type -Wsequence-point " "-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}") + build_string("EXTRA_FLAGS" "${WFLAGS_STR}") endif() + # add -stdlib=libc++ when using Clang if possible -if(NOT NO_AUTO_LIBCPP AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") +if(NOT CAF_NO_AUTO_LIBCPP AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CXXFLAGS_BACKUP "${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "-std=c++11 -stdlib=libc++") try_run(ProgramResult @@ -154,14 +277,14 @@ message(STATUS "Use clang with GCC' libstdc++") else() message(STATUS "Automatically added '-stdlib=libc++' flag " - "(NO_AUTO_LIBCPP not defined)") - set(EXTRA_FLAGS "${EXTRA_FLAGS} -stdlib=libc++") + "(CAF_NO_AUTO_LIBCPP not defined)") + build_string("EXTRA_FLAGS" "-stdlib=libc++") endif() # restore CXX flags set(CMAKE_CXX_FLAGS "${CXXFLAGS_BACKUP}") endif() # enable address sanitizer if requested by the user -if(ENABLE_ADDRESS_SANITIZER) +if(CAF_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") @@ -173,93 +296,97 @@ 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") + build_string("EXTRA_FLAGS" "-fsanitize=address -fno-omit-frame-pointer") endif() # restore CXX flags set(CMAKE_CXX_FLAGS "${CXXFLAGS_BACKUP}") -endif(ENABLE_ADDRESS_SANITIZER) +endif(CAF_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") + build_string("EXTRA_FLAGS" "-pthread") endif() -# -fPIC generates warnings on MinGW plus extra setup steps needed on MinGW +# -fPIC generates warnings on MinGW and Cygwin plus extra setup steps needed on MinGW if(MINGW) add_definitions(-D_WIN32_WINNT=0x0600) add_definitions(-DWIN32) include(GenerateExportHeader) - set(LD_FLAGS "ws2_32 -liphlpapi") + list(APPEND CAF_EXTRA_LDFLAGS -lws2_32 -liphlpapi -lpsapi) # build static to avoid runtime dependencies to GCC libraries - set(EXTRA_FLAGS "${EXTRA_FLAGS} -static") + build_string("EXTRA_FLAGS" "-static") +elseif(CYGWIN) + build_string("EXTRA_FLAGS" "-U__STRICT_ANSI__") else() - set(EXTRA_FLAGS "${EXTRA_FLAGS} -fPIC") + build_string("EXTRA_FLAGS" "-fPIC") +endif() +if (WIN32) + list(APPEND CAF_EXTRA_LDFLAGS ws2_32 iphlpapi) endif() # iOS support if(CAF_OSX_SYSROOT) set(CMAKE_OSX_SYSROOT "${CAF_OSX_SYSROOT}") endif() if(CAF_IOS_DEPLOYMENT_TARGET) - if("${CAF_OSX_SYSROOT}" STREQUAL "iphonesimulator") - set(EXTRA_FLAGS "${EXTRA_FLAGS} -mios-simulator-version-min=${CAF_IOS_DEPLOYMENT_TARGET}") + if(CAF_OSX_SYSROOT STREQUAL "iphonesimulator") + build_string("EXTRA_FLAGS" + "-mios-simulator-version-min=${CAF_IOS_DEPLOYMENT_TARGET}") else() - set(EXTRA_FLAGS "${EXTRA_FLAGS} -miphoneos-version-min=${CAF_IOS_DEPLOYMENT_TARGET}") + build_string("EXTRA_FLAGS" + "-miphoneos-version-min=${CAF_IOS_DEPLOYMENT_TARGET}") endif() endif() # check if the user provided CXXFLAGS, set defaults otherwise -if(CMAKE_CXX_FLAGS) - set(CMAKE_CXX_FLAGS_DEBUG "") - set(CMAKE_CXX_FLAGS_MINSIZEREL "") - set(CMAKE_CXX_FLAGS_RELEASE "") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "") -else() - set(CMAKE_CXX_FLAGS "-std=c++11 -Wextra -Wall -pedantic ${EXTRA_FLAGS}") - set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") - set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") - set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") +if(NOT CMAKE_CXX_FLAGS) + set(CMAKE_CXX_FLAGS "-std=c++11 -Wextra -Wall -pedantic ${EXTRA_FLAGS}") +endif() +if (NOT "${CMAKE_CXX_FLAGS}" MATCHES "-std=") + message(STATUS "Supplied CXXFLAGS do not contain a C++ standard, setting std to c++11") + set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") +endif() +if(NOT CMAKE_CXX_FLAGS_DEBUG) + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") +endif() +if(NOT CMAKE_CXX_FLAGS_MINSIZEREL) + set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") +endif() +if(NOT CMAKE_CXX_FLAGS_RELEASE) + set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") +endif() +if(NOT CMAKE_CXX_FLAGS_RELWITHDEBINFO) + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -fno-omit-frame-pointer") endif() # set build default build type to RelWithDebInfo if not set if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo) endif() # needed by subprojects -set(LD_FLAGS ${LD_FLAGS} ${CMAKE_LD_LIBS}) - +if (DEFINED CMAKE_LD_LIBS) + list(APPEND ${CMAKE_LD_LIBS}) +endif() ################################################################################ -# add custom definitions requested via configure script # +# setup logging # ################################################################################ -if(CAF_LOG_LEVEL) - add_definitions(-DCAF_LOG_LEVEL=${CAF_LOG_LEVEL}) -endif() - -if(CAF_ENABLE_RUNTIME_CHECKS) - add_definitions(-DCAF_ENABLE_RUNTIME_CHECKS) +# make sure log level is defined and all-uppercase +if(NOT CAF_LOG_LEVEL) + set(CAF_LOG_LEVEL "QUIET") +else() + string(TOUPPER "${CAF_LOG_LEVEL}" CAF_LOG_LEVEL) endif() -if(CAF_NO_MEM_MANAGEMENT) - add_definitions(-DCAF_NO_MEM_MANAGEMENT) +set(validLogLevels QUIET ERROR WARNING INFO DEBUG TRACE) +list(FIND validLogLevels "${CAF_LOG_LEVEL}" logLevelIndex) +if(logLevelIndex LESS 0) + MESSAGE(FATAL_ERROR "Invalid log level: \"${CAF_LOG_LEVEL}\"") endif() - ################################################################################ # setup for install target # ################################################################################ -# install includes from core -install(DIRECTORY libcaf_core/caf/ - DESTINATION include/caf FILES_MATCHING PATTERN "*.hpp") -# install CPPA compatibility headers -install(DIRECTORY libcaf_core/cppa/ - DESTINATION include/cppa FILES_MATCHING PATTERN "*.hpp") -# install includes from io -install(DIRECTORY libcaf_io/caf/ DESTINATION include/caf +# install includes from test +install(DIRECTORY libcaf_test/caf/ DESTINATION include/caf FILES_MATCHING PATTERN "*.hpp") -# install includes from opencl -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libcaf_opencl/CMakeLists.txt") - install(DIRECTORY libcaf_opencl/caf/ DESTINATION include/caf - FILES_MATCHING PATTERN "*.hpp") -endif() # process cmake_uninstall.cmake.in configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" @@ -278,194 +405,268 @@ # path to caf core & io headers set(LIBCAF_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/libcaf_core" - "${CMAKE_CURRENT_SOURCE_DIR}/libcaf_io") + "${CMAKE_CURRENT_SOURCE_DIR}/libcaf_io" + "${CMAKE_CURRENT_SOURCE_DIR}/libcaf_test") # path to caf opencl headers if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libcaf_opencl/CMakeLists.txt") set(LIBCAF_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/libcaf_opencl/" "${LIBCAF_INCLUDE_DIRS}") endif() +# enable tests if not disabled +if(NOT CAF_NO_UNIT_TESTS) + enable_testing() + macro(add_unit_tests globstr) + file(GLOB_RECURSE tests "${globstr}") + set(CAF_ALL_UNIT_TESTS ${CAF_ALL_UNIT_TESTS} ${tests}) + endmacro() +else() + macro(add_unit_tests globstr) + # do nothing (unit tests disabled) + endmacro() +endif() # all projects need the headers of the core components include_directories("${LIBCAF_INCLUDE_DIRS}") ################################################################################ -# add subprojects # +# add targets # ################################################################################ -# core library -message(STATUS "Enter subdirectory libcaf_core") -add_subdirectory(libcaf_core) -# set core lib for sub directories -if(NOT CAF_BUILD_STATIC_ONLY) - set(LIBCAF_CORE_LIBRARY libcaf_core_shared) -else() - set(LIBCAF_CORE_LIBRARY libcaf_core_static) -endif() -message(STATUS "Enter subdirectory libcaf_io") -add_subdirectory(libcaf_io) -# set io lib for sub directories -if(NOT CAF_BUILD_STATIC_ONLY) - set(LIBCAF_IO_LIBRARY libcaf_io_shared) -else() - set(LIBCAF_IO_LIBRARY libcaf_io_static) -endif() -# set opencl lib for sub directories if not told otherwise -if(NOT CAF_NO_OPENCL - AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libcaf_opencl/CMakeLists.txt") - message(STATUS "Enter subdirectory libcaf_opencl") - find_package(OPENCL REQUIRED) - add_subdirectory(libcaf_opencl) +macro(add_caf_lib name) + string(TOUPPER ${name} upper_name) + set(full_name libcaf_${name}) + set(shared_target ${full_name}_shared) + set(static_target ${full_name}_static) + add_subdirectory(${full_name}) + set(lib_varname CAF_LIBRARY_${upper_name}) + set(lib_varname_static ${lib_varname}_STATIC) if(NOT CAF_BUILD_STATIC_ONLY) - set(LIBCAF_OPENCL_LIBRARY libcaf_opencl_shared) + set(${lib_varname} ${shared_target}) + set(CAF_LIBRARIES ${CAF_LIBRARIES} ${shared_target}) else() - set(LIBCAF_OPENCL_LIBRARY libcaf_opencl_static) + set(${lib_varname} ${static_target}) + set(CAF_LIBRARIES ${CAF_LIBRARIES} ${static_target}) endif() -endif() -# tell CMake caf_io depends on caf_core -add_dependencies(libcaf_io libcaf_core) -# set LIBCAF_LIBRARIES for other subprojects -set(LIBCAF_LIBRARIES "${LIBCAF_CORE_LIBRARY}" - "${LIBCAF_IO_LIBRARY}" - "${LIBCAF_OPENCL_LIBRARY}") -# add unit tests if not being told otherwise -if(NOT CAF_NO_UNIT_TESTS) - enable_testing() - message(STATUS "Enter subdirectory unit_testing") - add_subdirectory(unit_testing) - add_dependencies(all_unit_tests libcaf_core libcaf_io) - if(NOT CAF_NO_OPENCL - AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libcaf_opencl/CMakeLists.txt") - add_subdirectory(libcaf_opencl/unit_testing) + if(CAF_BUILD_STATIC_ONLY OR CAF_BUILD_STATIC) + set(${lib_varname_static} ${static_target}) endif() -endif() -# build examples if not being told otherwise -if(NOT CAF_NO_EXAMPLES) - message(STATUS "Enter subdirectory examples") - add_subdirectory(examples) - add_dependencies(all_examples libcaf_core libcaf_io) - if(NOT CAF_NO_OPENCL - AND EXISTS "${CMAKE_CURRENT_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_CURRENT_SOURCE_DIR}/libcaf_riac/CMakeLists.txt") - message(STATUS "Enter subdirectory probe") - add_subdirectory(libcaf_riac) - add_dependencies(libcaf_riac libcaf_core libcaf_io) - if(NOT CAF_BUILD_STATIC_ONLY) - set(LIBCAF_LIBRARIES "${LIBCAF_LIBRARIES}" libcaf_riac_shared) + add_unit_tests("${full_name}/test/*.cpp") + # add headers to include directories so other subprojects can use them + include_directories("${CMAKE_CURRENT_SOURCE_DIR}/libcaf_${name}") +endmacro() + +macro(add_optional_caf_lib name) + string(TOUPPER ${name} upper_name) + set(flag_varname CAF_NO_${upper_name}) + if(NOT ${flag_varname} + AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libcaf_${name}/CMakeLists.txt") + add_caf_lib(${name}) else() - set(LIBCAF_LIBRARIES "${LIBCAF_LIBRARIES}" libcaf_riac_static) + set(${flag_name} yes) endif() - # add headers to include directories so other subprojects can use RIAC - include_directories("${LIBCAF_INCLUDE_DIRS}" - "${CMAKE_CURRENT_SOURCE_DIR}/libcaf_riac") - # add libcaf_riac to the list of caf libraries - set(CAF_HAS_RIAC yes) -else() - set(CAF_HAS_RIAC no) -endif() -# build nexus if not being told otherwise -if(NOT CAF_NO_NEXUS - AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/nexus/CMakeLists.txt") - if(NOT CAF_HAS_RIAC) - message(WARNING "cannot build nexus without RIAC submodule") - set(CAF_NO_NEXUS yes) - else() - message(STATUS "Enter subdirectory nexus") - add_subdirectory(nexus) - add_dependencies(nexus libcaf_riac) - set(CAF_NO_NEXUS no) +endmacro() + +macro(add_optional_caf_binaries name) + string(TOUPPER ${name} upper_name) + set(dependency_failed no) + # check all aditional dependency flags + foreach(flag_name ${ARGN}) + if(${flag_name}) + set(dependency_failed yes) + endif() + endforeach() + if(NOT dependency_failed) + if(NOT CAF_NO_${upper_name} + AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${name}/CMakeLists.txt") + add_subdirectory(${name}) + else() + # make sure variable is set for nicer build log + set(CAF_NO_${upper_name} yes) + endif() + else() + message(STATUS + "Disable ${name}, one of the following flags was set: ${ARGN}") + # make sure variable is set for nicer build log + set(CAF_NO_${upper_name} yes) endif() -else() - # make sure variable is set for build log - set(CAF_NO_NEXUS yes) +endmacro() + +# build core and I/O library +add_caf_lib(core) +add_optional_caf_lib(io) + +# build SSL module if OpenSSL library is available +if(NOT CAF_NO_OPENSSL) + find_package(OpenSSL) + if(OPENSSL_FOUND) + # Check OpenSSL version >= 1.0.1 + if (OPENSSL_VERSION VERSION_LESS 1.0.1) + message(STATUS + "Disable OpenSSL. Required >= 1.0.1 due to TLSv1.2 support.") + set(CAF_NO_OPENSSL yes) + else() + if(NOT CMAKE_CROSSCOMPILING) + # Check if openssl headers and library versions match + set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES}) + set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) + check_c_source_runs(" + #include + #include + int main() { + if (SSLeay() == OPENSSL_VERSION_NUMBER) { + return 0; + } + return -1; + } + " OPENSSL_CORRECT_VERSION_NUMBER) + if (NOT OPENSSL_CORRECT_VERSION_NUMBER) + message(FATAL_ERROR + "OpenSSL library version does not match headers") + endif() + endif() + include_directories(BEFORE ${OPENSSL_INCLUDE_DIR}) + add_optional_caf_lib(openssl) + endif() + else(OPENSSL_FOUND) + set(CAF_NO_OPENSSL yes) + endif(OPENSSL_FOUND) endif() -# build cash if not being told otherwise -if(NOT CAF_NO_CASH - AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cash/CMakeLists.txt") - if(NOT CAF_HAS_RIAC) - message(WARNING "cannot build cash without RIAC submodule") - set(CAF_NO_CASH yes) - else() - message(STATUS "Enter subdirectory cash") - add_subdirectory(cash) - add_dependencies(cash libcaf_riac) - set(CAF_NO_CASH no) + +# build opencl library if not told otherwise and OpenCL package was found +if(NOT CAF_NO_OPENCL) + if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.0) + find_package(OpenCL) + if(OpenCL_FOUND) + include_directories(BEFORE ${OpenCL_INCLUDE_DIRS}) + add_optional_caf_lib(opencl) + add_optional_caf_binaries(libcaf_opencl/examples) + else() + set(CAF_NO_OPENCL yes) + endif() + else() + set(CAF_NO_OPENCL yes) + message(STATUS "Could NOT find OpenCL, requires Cmake >= 3.1.") endif() -else() - # make sure variable is set for build log - set(CAF_NO_CASH yes) endif() -# build benchmarks if not being told otherwise -if(NOT CAF_NO_BENCHMARKS - AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/CMakeLists.txt") - message(STATUS "Enter subdirectory benchmarks") - add_subdirectory(benchmarks) - add_dependencies(all_benchmarks libcaf_io) -else() - # make sure variable is set for build log - set(CAF_NO_BENCHMARKS yes) + +# build Python binding if not being told otherwise +if(NOT CAF_NO_PYTHON AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libcaf_python/CMakeLists.txt") + add_subdirectory(libcaf_python) endif() +# build examples if not being told otherwise +add_optional_caf_binaries(examples) + +# build tools if not being told otherwise +add_optional_caf_binaries(tools) ################################################################################ -# LateX setup # +# unit tests setup # ################################################################################ -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/manual/variables.tex.in" - "${CMAKE_CURRENT_SOURCE_DIR}/manual/variables.tex" - @ONLY) +if(NOT CAF_NO_UNIT_TESTS) + # setup unit test binary + add_executable(caf-test + libcaf_test/src/caf-test.cpp + libcaf_test/caf/test/unit_test.hpp + libcaf_test/caf/test/unit_test_impl.hpp + ${CAF_ALL_UNIT_TESTS}) + target_link_libraries(caf-test + ${CAF_EXTRA_LDFLAGS} + ${CAF_LIBRARIES} + ${PTHREAD_LIBRARIES}) + add_custom_target(all_unit_tests) + add_dependencies(caf-test all_unit_tests) + # enumerate all test suites. + foreach(test ${CAF_ALL_UNIT_TESTS}) + file(STRINGS ${test} contents) + foreach(line ${contents}) + if ("${line}" MATCHES "CAF_SUITE (.*)") + string(REGEX REPLACE ".* CAF_SUITE (.*)" "\\1" suite ${line}) + list(APPEND suites ${suite}) + endif() + endforeach() + endforeach() + list(REMOVE_DUPLICATES suites) + # creates one CMake test per test suite. + macro (make_test suite) + string(REPLACE " " "_" test_name ${suite}) + set(caf_test ${EXECUTABLE_OUTPUT_PATH}/caf-test) + add_test(${test_name} ${caf_test} -r 300 -n -v 5 -s "${suite}" ${ARGN}) + endmacro () + list(LENGTH suites num_suites) + message(STATUS "Found ${num_suites} test suites") + foreach(suite ${suites}) + make_test("${suite}") + endforeach () +endif() + +# -- Fetch branch name and SHA if available ------------------------------------ -################################################################################ -# Doxygen setup # -################################################################################ +if(EXISTS "release.txt") + file(READ "release.txt" CAF_VESION) +else() + set(CAF_RELEASE "${CAF_VERSION}") + find_package(Git QUIET) + if(GIT_FOUND) + # retrieve current branch name for CAF + execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE gitBranchResult + OUTPUT_VARIABLE gitBranch + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + # retrieve current SHA1 hash for CAF + execute_process(COMMAND ${GIT_EXECUTABLE} log --pretty=format:%h -n 1 + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE gitShaResult + OUTPUT_VARIABLE gitSha + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(gitBranchResult EQUAL 0 AND gitShaResult EQUAL 0) + # generate semantic CAF version for manual + set(CAF_RELEASE "${CAF_VERSION}+exp.sha.${gitSha}") + # check whether we're building the manual for a stable release + if(gitBranch STREQUAL "master") + # retrieve current tag name for CAF + execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --contains ${gitSha} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE gitTagResult + OUTPUT_VARIABLE gitTag + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + # tags indicate stable releases -> use tag name as release version + if(gitTagResult EQUAL 0) + set(CAF_RELEASE "${gitTag}") + endif() + endif() + endif() + endif() +endif() + +message(STATUS "Set release version for all documentation to ${CAF_RELEASE}.") -# check for doxygen and add custom "doc" target to Makefile -find_package(Doxygen) -if(DOXYGEN_FOUND) - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in" - "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile" - @ONLY) - add_custom_target(doc "${DOXYGEN_EXECUTABLE}" - "${CMAKE_HOME_DIRECTORY}/Doxyfile" - WORKING_DIRECTORY "${CMAKE_HOME_DIRECTORY}" - COMMENT "Generating API documentation with Doxygen" - VERBATIM) -endif(DOXYGEN_FOUND) +# -- Setup for building manual and API documentation --------------------------- +# we need the examples and some headers relative to the build/doc/tex directory +file(COPY examples/ DESTINATION examples) +file(COPY libcaf_core/caf/exit_reason.hpp DESTINATION libcaf_core/caf/) +file(COPY libcaf_core/caf/sec.hpp DESTINATION libcaf_core/caf/) + +add_subdirectory(doc) ################################################################################ # Add additional project files to GUI # ################################################################################ -add_custom_target(gui_dummy SOURCES configure) +file(GLOB_RECURSE script_files "scripts/*") +add_custom_target(gui_dummy SOURCES configure ${script_files}) ################################################################################ # print summary # ################################################################################ -# set human-readable representation for log level -set(LOG_LEVEL_STR "none") -if(CAF_LOG_LEVEL) - if(${CAF_LOG_LEVEL} EQUAL 0) - set(LOG_LEVEL_STR "ERROR") - elseif(${CAF_LOG_LEVEL} EQUAL 1) - set(LOG_LEVEL_STR "WARNING") - elseif(${CAF_LOG_LEVEL} EQUAL 2) - set(LOG_LEVEL_STR "INFO") - elseif(${CAF_LOG_LEVEL} EQUAL 3) - set(LOG_LEVEL_STR "DEBUG") - elseif(${CAF_LOG_LEVEL} EQUAL 4) - set(LOG_LEVEL_STR "TRACE") - else() - set(LOG_LEVEL_STR "invalid") - endif() -endif() # little helper macro to invert a boolean macro(invertYesNo in out) if(${in}) @@ -475,46 +676,54 @@ endif() endmacro() # invert CAF_NO_* variables for nicer output +invertYesNo(CAF_NO_IO CAF_BUILD_IO) invertYesNo(CAF_NO_EXAMPLES CAF_BUILD_EXAMPLES) +invertYesNo(CAF_NO_TOOLS CAF_BUILD_TOOLS) invertYesNo(CAF_NO_UNIT_TESTS CAF_BUILD_UNIT_TESTS) -invertYesNo(CAF_NO_NEXUS CAF_BUILD_NEXUS) -invertYesNo(CAF_NO_CASH CAF_BUILD_CASH) +invertYesNo(CAF_NO_EXCEPTIONS CAF_BUILD_WITH_EXCEPTIONS) invertYesNo(CAF_NO_MEM_MANAGEMENT CAF_BUILD_MEM_MANAGEMENT) -invertYesNo(CAF_NO_BENCHMARKS CAF_BUILD_BENCHMARKS) invertYesNo(CAF_NO_OPENCL CAF_BUILD_OPENCL) +invertYesNo(CAF_NO_OPENSSL CAF_BUILD_OPENSSL) +invertYesNo(CAF_NO_PYTHON CAF_BUILD_PYTHON) # collect all compiler flags string(TOUPPER "${CMAKE_BUILD_TYPE}" UPPER_BUILD_TYPE) set(ALL_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${UPPER_BUILD_TYPE}}") +set(ALL_LD_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CAF_EXTRA_LDFLAGS}") +string(STRIP "${ALL_LD_FLAGS}" ALL_LD_FLAGS) # done -message(STATUS +if(NOT CAF_NO_SUMMARY) + message(STATUS "\n====================| Build Summary |====================" "\n" - "\nLibcaf version: ${CAF_VERSION}" + "\nCAF version: ${CAF_VERSION}" "\n" - "\nBuild type: ${CMAKE_BUILD_TYPE}" - "\nBuild static: ${CAF_BUILD_STATIC}" - "\nBulid static only: ${CAF_BUILD_STATIC_ONLY}" - "\nRuntime checks: ${CAF_ENABLE_RUNTIME_CHECKS}" - "\nLog level: ${LOG_LEVEL_STR}" - "\nWith mem. mgmt.: ${CAF_BUILD_MEM_MANAGEMENT}" + "\nBuild type: ${CMAKE_BUILD_TYPE}" + "\nBuild static: ${CAF_BUILD_STATIC}" + "\nBuild static only: ${CAF_BUILD_STATIC_ONLY}" + "\nBuild static runtime: ${CAF_BUILD_STATIC_RUNTIME}" + "\nRuntime checks: ${CAF_ENABLE_RUNTIME_CHECKS}" + "\nLog level: ${CAF_LOG_LEVEL}" + "\nWith mem. mgmt.: ${CAF_BUILD_MEM_MANAGEMENT}" + "\nWith exceptions: ${CAF_BUILD_WITH_EXCEPTIONS}" "\n" - "\nBuild examples: ${CAF_BUILD_EXAMPLES}" - "\nBuild unit tests: ${CAF_BUILD_UNIT_TESTS}" - "\nBuild riac: ${CAF_HAS_RIAC}" - "\nBuild nexus: ${CAF_BUILD_NEXUS}" - "\nBuild cash: ${CAF_BUILD_CASH}" - "\nBuild benchmarks: ${CAF_BUILD_BENCHMARKS}" - "\nBuild opencl: ${CAF_BUILD_OPENCL}" + "\nBuild I/O module: ${CAF_BUILD_IO}" + "\nBuild tools: ${CAF_BUILD_TOOLS}" + "\nBuild examples: ${CAF_BUILD_EXAMPLES}" + "\nBuild unit tests: ${CAF_BUILD_UNIT_TESTS}" + "\nBuild OpenCL: ${CAF_BUILD_OPENCL}" + "\nBuild OpenSSL: ${CAF_BUILD_OPENSSL}" + "\nBuild Python: ${CAF_BUILD_PYTHON}" "\n" - "\nCXX: ${CMAKE_CXX_COMPILER}" - "\nCXXFLAGS: ${ALL_CXX_FLAGS}" - "\nLIBRARIES: ${LD_FLAGS}" + "\nCXX: ${CMAKE_CXX_COMPILER}" + "\nCXXFLAGS: ${ALL_CXX_FLAGS}" + "\nLINKER_FLAGS (shared) ${ALL_LD_FLAGS}" "\n" - "\nSource directory: ${CMAKE_CURRENT_SOURCE_DIR}" - "\nBuild directory: ${CMAKE_CURRENT_BINARY_DIR}" - "\nExecutable path: ${EXECUTABLE_OUTPUT_PATH}" - "\nLibrary path: ${LIBRARY_OUTPUT_PATH}" - "\nInstall prefix: ${CMAKE_INSTALL_PREFIX}" - "\nGenerator: ${CMAKE_GENERATOR}" + "\nSource directory: ${CMAKE_CURRENT_SOURCE_DIR}" + "\nBuild directory: ${CMAKE_CURRENT_BINARY_DIR}" + "\nExecutable path: ${EXECUTABLE_OUTPUT_PATH}" + "\nLibrary path: ${LIBRARY_OUTPUT_PATH}" + "\nInstall prefix: ${CMAKE_INSTALL_PREFIX}" + "\nGenerator: ${CMAKE_GENERATOR}" "\n" "\n===========================================================\n") +endif() diff -Nru actor-framework-0.13.2/configure actor-framework-0.16.3/configure --- actor-framework-0.13.2/configure 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/configure 2018-12-27 20:33:32.000000000 +0000 @@ -14,19 +14,7 @@ command="$0 $*" dirname_0=`dirname $0` sourcedir=`cd $dirname_0 && pwd` -benchmark_suite_options="" -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 - --with-salsa=FILE path to SALSA Lite jar -" -fi + usage="\ Usage: $0 [OPTION]... [VAR=VALUE]... @@ -37,18 +25,30 @@ - MinSizeRel: minimal output size - Release: optimizations on, debugging off - RelWithDebInfo: release flags plus debugging + --extra-flags=STRING additional compiler flags --build-dir=DIR place build files in directory [build] --bin-dir=DIR executable directory [build/bin] --lib-dir=DIR library directory [build/lib] --with-clang=FILE path to clang++ executable --with-gcc=FILE path to g++ executable + --with-qt-prefix=PATH prefix path for Qt5 cmake modules + --with-openssl=PATH path to OpenSSL library and headers --dual-build build using both gcc and clang --build-static build as static and shared library --build-static-only build as static library only + --static-runtime build with static C++ runtime --more-warnings enables most warnings --no-compiler-check disable compiler version check --no-auto-libc++ do not automatically enable libc++ for Clang - --warnings-as-errors enables -Werror + --no-exceptions do not catch exceptions in CAF + --force-no-exceptions build CAF with '-fno-exceptions' + --warnings-as-errors build with '-Werror' + --with-ccache use ccache to improve build performance + + Optional Targets: + --with-qt-examples build Qt example(s) + --with-protobuf-examples build Google Protobuf example(s) + --with-tex-manual build the LaTeX manual Installation Directories: --prefix=PREFIX installation directory [/usr/local] @@ -56,15 +56,18 @@ Remove Standard Features (even if all dependencies are available): --no-memory-management build without memory management --no-examples build without examples - --no-qt-examples build without Qt examples - --no-protobuf-examples build without Google Protobuf examples --no-curl-examples build without libcurl examples --no-unit-tests build without unit tests - --no-opencl build without opencl - --no-nexus build without nexus - --no-cash build without cash - --no-benchmarks build without benchmarks - --no-riac build without riac + --no-opencl build without OpenCL module + --no-openssl build without OpenSSL module + --no-tools build without CAF tools such as caf-run + --no-io build without I/O module + --no-python build without python binding + --no-summary do not print configuration before building + --libs-only sets no-examples, no-tools, no-python, + and no-unit-tests + --core-only same as libs-only but also adds sets no-opencl, + no-openssl, and no-io Debugging: --with-runtime-checks build with requirement checks at runtime @@ -75,17 +78,30 @@ - DEBUG - TRACE --with-address-sanitizer build with address sanitizer if available + --with-asan alias for --with-address-sanitier + --enable-asan alias for --with-address-sanitier + --with-gcov build with gcov coverage enabled + + Convenience options: + --dev-mode sets --build-type=debug, --no-examples, + --no-tools, --with-runtime-checks, + --log-level=trace, and --enable-asan Influential Environment Variables (only on first invocation): CXX C++ compiler command - CXXFLAGS C++ compiler flags + CXXFLAGS C++ compiler flags (overrides defaults) + LDFLAGS Additional linker flags + CMAKE_GENERATOR Selects a custom generator + + Python Build Options: + --with-python-config=FILE Use python-conf binary to determine includes and libs iOS Build Options (should be used with XCode generator): --sysroot=DIR set system root for Clang - iphoneos: for iOS device - iphonesimulator: for iOS simulator --ios-min-ver=VERSION set the ios deployment target version -$benchmark_suite_options" +" # Appends a CMake cache entry definition to the CMakeCacheEntries variable. @@ -170,14 +186,21 @@ cmake $CMakeCacheEntries "$sourcedir" fi - echo "# This is the command used to configure this build" > config.status + printf "#!/bin/sh\n\n" > config.status + printf "# Switch to the source of this build directory.\n" >> config.status + printf "cd \"$sourcedir\"\n\n" >> config.status + printf "# Invoke the command to configure this build.\n" >> config.status if [ -n "$CC" ]; then - printf "CC=%s" $CC >> config.status - printf ' ' >> config.status + printf "CC=\"%s\"\n" "$CC" >> config.status fi if [ -n "$CXX" ]; then - printf "CXX=%s" $CXX >> config.status - printf ' ' >> config.status + printf "CXX=\"%s\"\n" "$CXX" >> config.status + fi + if [ -n "$CXXFLAGS" ]; then + printf "CXXFLAGS=\"%s\"\n" "$CXXFLAGS" >> config.status + fi + if [ -n "$LDFLAGS" ]; then + printf "LDFLAGS=\"%s\"\n" "$LDFLAGS" >> config.status fi echo $command >> config.status chmod u+x config.status @@ -190,8 +213,8 @@ append_cache_entry CAF_ENABLE_RUNTIME_CHECKS BOOL false # parse custom environment variable to initialize CMakeGenerator -if [ -n "$DEFAULT_CMAKE_GENERATOR" ]; then - CMakeGenerator="$DEFAULT_CMAKE_GENERATOR" +if [ -n "$CMAKE_GENERATOR" ]; then + CMakeGenerator="$CMAKE_GENERATOR" fi # Parse arguments. @@ -210,28 +233,47 @@ CMakeGenerator="$optarg" ;; --prefix=*) - append_cache_entry CMAKE_INSTALL_PREFIX PATH $optarg + append_cache_entry CMAKE_INSTALL_PREFIX PATH "$optarg" ;; --with-runtime-checks) append_cache_entry CAF_ENABLE_RUNTIME_CHECKS BOOL yes ;; --with-address-sanitizer) - append_cache_entry ENABLE_ADDRESS_SANITIZER BOOL yes + append_cache_entry CAF_ENABLE_ADDRESS_SANITIZER BOOL yes + ;; + --with-asan) + append_cache_entry CAF_ENABLE_ADDRESS_SANITIZER BOOL yes + ;; + --enable-asan) + append_cache_entry CAF_ENABLE_ADDRESS_SANITIZER BOOL yes + ;; + --with-gcov) + append_cache_entry CAF_ENABLE_GCOV BOOL yes ;; --no-memory-management) append_cache_entry CAF_NO_MEM_MANAGEMENT BOOL yes ;; --more-warnings) - append_cache_entry MORE_WARNINGS BOOL yes + append_cache_entry CAF_MORE_WARNINGS BOOL yes ;; --no-compiler-check) - append_cache_entry NO_COMPILER_CHECK BOOL yes + append_cache_entry CAF_NO_COMPILER_CHECK BOOL yes ;; --no-auto-libc++) - append_cache_entry NO_AUTO_LIBCPP BOOL yes + append_cache_entry CAF_NO_AUTO_LIBCPP BOOL yes + ;; + --no-exceptions) + append_cache_entry CAF_NO_EXCEPTIONS BOOL yes + ;; + --force-no-exceptions) + append_cache_entry CAF_NO_EXCEPTIONS BOOL yes + append_cache_entry CAF_FORCE_NO_EXCEPTIONS BOOL yes ;; --warnings-as-errors) - append_cache_entry CXX_WARNINGS_AS_ERROS BOOL yes + append_cache_entry CAF_CXX_WARNINGS_AS_ERRORS BOOL yes + ;; + --with-ccache) + append_cache_entry CAF_USE_CCACHE BOOL yes ;; --sysroot=*) append_cache_entry CAF_OSX_SYSROOT PATH "$optarg" @@ -241,37 +283,25 @@ append_cache_entry CAF_IOS_DEPLOYMENT_TARGET STRING "$optarg" ;; --with-log-level=*) - level=`echo "$optarg" | tr '[:lower:]' '[:upper:]'` - case $level in - ERROR) - append_cache_entry CAF_LOG_LEVEL STRING 0 - ;; - WARNING) - append_cache_entry CAF_LOG_LEVEL STRING 1 - ;; - INFO) - append_cache_entry CAF_LOG_LEVEL STRING 2 - ;; - DEBUG) - append_cache_entry CAF_LOG_LEVEL STRING 3 - ;; - TRACE) - append_cache_entry CAF_LOG_LEVEL STRING 4 - ;; - *) - echo "Invalid log level '$level'. Try '$0 --help' to see valid values." - exit 1 - ;; - esac + append_cache_entry CAF_LOG_LEVEL STRING "$optarg" ;; --with-clang=*) - clang=$optarg + clang="$optarg" ;; --with-gcc=*) - gcc=$optarg + gcc="$optarg" + ;; + --with-qt-prefix=*) + append_cache_entry CAF_QT_PREFIX_PATH STRING "$optarg" + ;; + --with-openssl=*) + append_cache_entry OPENSSL_ROOT_DIR PATH "$optarg" ;; --build-type=*) - append_cache_entry CMAKE_BUILD_TYPE STRING $optarg + append_cache_entry CMAKE_BUILD_TYPE STRING "$optarg" + ;; + --extra-flags=*) + append_cache_entry EXTRA_FLAGS STRING "$optarg" ;; --build-dir=*) builddir="$optarg" @@ -288,11 +318,14 @@ --no-examples) append_cache_entry CAF_NO_EXAMPLES BOOL yes ;; - --no-qt-examples) - append_cache_entry CAF_NO_QT_EXAMPLES BOOL yes + --with-qt-examples) + append_cache_entry CAF_BUILD_QT_EXAMPLES BOOL yes ;; - --no-protobuf-examples) - append_cache_entry CAF_NO_PROTOBUF_EXAMPLES BOOL yes + --with-protobuf-examples) + append_cache_entry CAF_BUILD_PROTOBUF_EXAMPLES BOOL yes + ;; + --with-tex-manual) + append_cache_entry CAF_BUILD_TEX_MANUAL BOOL yes ;; --no-curl-examples) append_cache_entry CAF_NO_CURL_EXAMPLES BOOL yes @@ -303,41 +336,50 @@ --no-opencl) append_cache_entry CAF_NO_OPENCL BOOL yes ;; + --no-openssl) + append_cache_entry CAF_NO_OPENSSL BOOL yes + ;; --build-static) append_cache_entry CAF_BUILD_STATIC BOOL yes ;; --build-static-only) append_cache_entry CAF_BUILD_STATIC_ONLY BOOL yes ;; - --with-javac=*) - append_cache_entry CAF_JAVA_COMPILER FILEPATH "$optarg" + --static-runtime) + append_cache_entry CAF_BUILD_STATIC_RUNTIME BOOL yes ;; - --with-java=*) - append_cache_entry CAF_JAVA_BIN FILEPATH "$optarg" + --with-python-config=*) + append_cache_entry CAF_PYTHON_CONFIG_BIN FILEPATH "$optarg" ;; - --with-scalac=*) - append_cache_entry CAF_SCALA_COMPILER FILEPATH "$optarg" + --no-tools) + append_cache_entry CAF_NO_TOOLS BOOL yes ;; - --with-erlc=*) - append_cache_entry CAF_ERLANG_COMPILER FILEPATH "$optarg" + --no-io) + append_cache_entry CAF_NO_IO BOOL yes ;; - --with-charmc=*) - append_cache_entry CAF_CHARM_COMPILER FILEPATH "$optarg" + --no-python) + append_cache_entry CAF_NO_PYTHON BOOL yes ;; - --with-salsa=*) - append_cache_entry CAF_SALSA_JAR FILEPATH "$optarg" + --no-summary) + append_cache_entry CAF_NO_SUMMARY BOOL yes ;; - --no-nexus) - append_cache_entry CAF_NO_NEXUS BOOL yes + --libs-only) + for var in CAF_NO_TOOLS CAF_NO_PYTHON CAF_NO_EXAMPLES CAF_NO_UNIT_TESTS; do + append_cache_entry $var BOOL yes + done ;; - --no-cash) - append_cache_entry CAF_NO_CASH BOOL yes + --core-only) + for var in CAF_NO_TOOLS CAF_NO_PYTHON CAF_NO_EXAMPLES CAF_NO_UNIT_TESTS CAF_NO_IO CAF_NO_OPENCL CAF_NO_OPENSSL ; do + append_cache_entry $var BOOL yes + done ;; - --no-benchmarks) - append_cache_entry CAF_NO_BENCHMARKS BOOL yes - ;; - --no-riac) - append_cache_entry CAF_NO_RIAC BOOL yes + --dev-mode) + append_cache_entry CMAKE_BUILD_TYPE STRING Debug + append_cache_entry CAF_NO_EXAMPLES BOOL yes + append_cache_entry CAF_NO_TOOLS BOOL yes + append_cache_entry CAF_LOG_LEVEL STRING TRACE + append_cache_entry CAF_ENABLE_RUNTIME_CHECKS BOOL yes + append_cache_entry CAF_ENABLE_ADDRESS_SANITIZER BOOL yes ;; *) echo "Invalid option '$1'. Try $0 --help to see available options." @@ -374,37 +416,3 @@ configure "$compiler" "" "$bindir" "$libdir" "$CMakeGenerator" fi - -if [ -n "$CMakeGenerator" ] && [ "$CMakeGenerator" != "Unix" ]; then - # skip Makefile-specific code below when not using make - exit 0 -fi - -printf "DIRS := %s\n\n" "$workdirs" > $sourcedir/Makefile -makefile=`cat <<'EOT' -all: - @for i in $(DIRS); do $(MAKE) -C $$i $@ || exit; done - -test: - @for i in $(DIRS); do $(MAKE) -C $$i $@ || exit; done - -install: - @for i in $(DIRS); do $(MAKE) -C $$i $@ || exit; done - -uninstall: - @for i in $(DIRS); do $(MAKE) -C $$i $@ || exit; done - -clean: - @for i in $(DIRS); do $(MAKE) -C $$i $@; done - -distclean: - rm -rf $(DIRS) Makefile - -doc: - $(MAKE) -C $(firstword $(DIRS)) $@ - -.PHONY: all test install uninstall clean distclean -EOT -` - -echo "$makefile" >> $sourcedir/Makefile diff -Nru actor-framework-0.13.2/CONTRIBUTING.md actor-framework-0.16.3/CONTRIBUTING.md --- actor-framework-0.13.2/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/CONTRIBUTING.md 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,452 @@ +This document specifies how to contribute code to CAF. + +Git Workflow +============ + +Please adhere to the following Git naming and commit message conventions. +Having a consistent work flow and style reduces friction and makes organizing +contributions a lot easier for all sides. + +Branches +-------- + +- Our main branch is `master`. It reflects the latest development changes for + the next release and should always compile. Nightly versions use the + `master`. Users looking for a production-ready state are encouraged to use + the latest release version instead. + +- Push trivial bugfixes (e.g. typos, missing includes, etc.) consisting of a + single commit directly to `master`. Otherwise, implement your changes in a + topic or bugfix branch and file a pull request on GitHub. + +- Implement new features and non-trivial changes in a *topic branch* with + naming convention `topic/short-description`. + +- Implement fixes for existing issues in a *bugfix branch* with naming + convention `issue/$num`, where `$num` is the issue ID on GitHub. + +- Simply use a fork of CAF if you are an external contributor. + +Pull Requests +------------- + +Check the following steps to prepare for a merge into `master` after completing +work in a topic or bugfix branch (or fork). + +- Squash your commits into a single one if necessary. Each commit should + represent a coherent set of changes. + +- Wait for a code review and the test results of our CI. + +- Address any review feedback and fix all issues reported by the CI. + +- A maintainer will merge the pull request when all issues are resolved. + +Commit Message Style +-------------------- + +- Summarize the changes in no more than 50 characters in the first line. + Capitalize and write in an imperative present tense, e.g., "Fix bug" as + opposed to "Fixes bug" or "Fixed bug". + +- Suppress the dot at the end of the first line. Think of it as the header of + the following description. + +- Leave the second line empty. + +- Optionally add a long description written in full sentences beginning on the + third line. Indent at 72 characters per line. + +Coding Style +============ + +When contributing source code, please adhere to the following coding style, +which is loosely based on the [Google C++ Style +Guide](https://google.github.io/styleguide/cppguide.html) and the coding +conventions used by the C++ Standard Library. + +Example for the Impatient +------------------------- + +```cpp +// libcaf_example/caf/example/my_class.hpp + +#pragma once + +#include + +// use "//" for regular comments and "///" for doxygen + +namespace caf { +namespace example { + +/// This class is only being used as style guide example. +class my_class { +public: + /// Brief description. More description. Note that CAF uses the + /// "JavaDoc-style" autobrief option, i.e., everything up until the + /// first dot is the brief description. + my_class(); + + /// Destructs `my_class`. Please use Markdown in comments. + ~my_class(); + + // suppress redundant @return if you start the brief description with "Returns" + /// Returns the name of this instance. + inline const std::string& name() const noexcept { + return name_; + } + + /// Sets the name of this instance. + inline void name(const std::string& new_name) { + name_ = new_name; + } + + /// Prints the name to `std::cout`. + void print_name() const; + + /// Does something (maybe). + void do_something(); + + /// Does something else but is guaranteed to never throw. + void do_something_else() noexcept; + +private: + std::string name_; +}; + +} // namespace example +} // namespace caf +``` + +```cpp +// libcaf_example/src/my_class.cpp + +#include "caf/example/my_class.hpp" + +#include + +namespace caf { +namespace example { + +namespace { + +constexpr const char default_name[] = "my object"; + +} // namespace + +my_class::my_class() : name_(default_name) { + // nop +} + +my_class::~my_class() { + // nop +} + +void my_class::print_name() const { + std::cout << name() << std::endl; +} + +void my_class::do_something() { + if (name() == default_name) { + std::cout << "You didn't gave me a proper name, so I " + << "refuse to do something." + << std::endl; + } else { + std::cout << "You gave me the name \"" << name() + << "\"... Do you really think I'm willing to do something " + "for you after insulting me like that?" + << std::endl; + } +} + +void my_class::do_something_else() noexcept { + // Do nothing if we don't have a name. + if (name().empty()) + return; + switch (name.front()) { + case 'a': + // handle a + break; + case 'b': + // handle b + break; + default: + handle_default(); + } +} + +} // namespace example +} // namespace caf + +``` + +General +------- + +- Use 2 spaces per indentation level. + +- Use at most 80 characters per line. + +- Never use tabs. + +- Never use C-style casts. + +- Never declare more than one variable per line. + +- Only separate functions with vertical whitespaces and use comments to + document logcial blocks inside functions. + +- Use `.hpp` as suffix for header files and `.cpp` as suffix for implementation + files. + +- Bind `*` and `&` to the *type*, e.g., `const std::string& arg`. + +- Never increase the indentation level for namespaces and access modifiers. + +- Use the order `public`, `protected`, and then `private` in classes. + +- Always use `auto` to declare a variable unless you cannot initialize it + immediately or if you actually want a type conversion. In the latter case, + provide a comment why this conversion is necessary. + +- Never use unwrapped, manual resource management such as `new` and `delete`. + +- Prefer `using T = X` over `typedef X T`. + +- Insert a whitespaces after keywords: `if (...)`, `template <...>`, + `while (...)`, etc. + +- Put opening braces on the same line: + + ```cpp + void foo() { + // ... + } + ``` + +- Use standard order for readability: C standard libraries, C++ standard + libraries, OS-specific headers (usually guarded by `ifdef`), other libraries, + and finally (your) CAF headers. Include `caf/config.hpp` before the standard + headers if you need to include platform-dependent headers. Use angle brackets + for system includes and doublequotes otherwise. + + ```cpp + // example.hpp + + #include + + #include + + #include "3rd/party.h" + + #include "caf/fwd.hpp" + ``` + + Put the implemented header always first in a `.cpp` file. + + ```cpp + // example.cpp + + #include "caf/example.hpp" // header for this .cpp file + + #include "caf/config.hpp" // needed for #ifdef guards + + #include + + #ifdef CAF_WINDOWS + #include + #else + #include + #endif + + #include "some/other/library.h" + + #include "caf/actor.hpp" + ``` + +- Put output parameters in functions before input parameters if unavoidable. + This follows the parameter order from the STL. + +- Protect single-argument constructors with `explicit` to avoid implicit + conversions. + +- Use `noexcept` whenever it makes sense and as long as it does not limit future + design space. Move construction and assignment are natural candidates for + `noexcept`. + +Naming +------ + +- All names except macros and template parameters should be + lower case and delimited by underscores. + +- Template parameter names should be written in CamelCase. + +- Types and variables should be nouns, while functions performing an action + should be "command" verbs. Classes used to implement metaprogramming + functions also should use verbs, e.g., `remove_const`. + +- Private and protected member variables use the suffix `_` while getter *and* + setter functions use the name without suffix: + + ```cpp + class person { + public: + person(std::string name) : name_(std::move(name)) { + // nop + } + + const std::string& name() const { + return name_ + } + + void name(const std::string& new_name) { + name_ = new_name; + } + + private: + std::string name_; + }; + ``` + +- Use `T` for generic, unconstrained template parameters and `x` + for generic function arguments. Suffix both with `s` for + template parameter packs and lists: + + ```cpp + template + void print(const Ts&... xs) { + // ... + } + + void print(const std::vector& xs) { + // ... + } + ``` + +Headers +------- + +- Each `.cpp` file has an associated `.hpp` file. + Exceptions to this rule are unit tests and `main.cpp` files. + +- Each class has its own pair of header and implementation + files and the relative path for the header file is derived from its full name. + For example, the header file for `caf::example::my_class` of `libcaf_example` + is located at `libcaf_example/caf/example/my_class.hpp` and the + source file at `libcaf_example/src/my_class.cpp`. + +- All header files use `#pragma once` to prevent multiple inclusion. + +- Do not `#include` when a forward declaration suffices. + +- Each library component must provide a `fwd.hpp` header providing forward + declartations for all types used in the user API. + +- Each library component should provide an `all.hpp` header that contains the + main page for the documentation and includes all headers for the user API. + +- Use `inline` for small functions (rule of thumb: 10 lines or less). + +Breaking Statements +------------------- + +- Break constructor initializers after the comma, use four spaces for + indentation, and place each initializer on its own line (unless you don't + need to break at all): + + ```cpp + my_class::my_class() + : my_base_class(some_function()), + greeting_("Hello there! This is my_class!"), + some_bool_flag_(false) { + // ok + } + other_class::other_class() : name_("tommy"), buddy_("michael") { + // ok + } + ``` + +- Break function arguments after the comma for both declaration and invocation: + + ```cpp + intptr_t channel::compare(const abstract_channel* lhs, + const abstract_channel* rhs) { + // ... + } + ``` + +- Break before tenary operators and before binary operators: + + ```cpp + if (today_is_a_sunny_day() + && it_is_not_too_hot_to_go_swimming()) { + // ... + } + ``` + +Template Metaprogramming +------------------------ + +Despite its power, template metaprogramming came to the language pretty +much by accident. Templates were never meant to be used for compile-time +algorithms and type transformations. This is why C++ punishes metaprogramming +with an insane amount of syntax noise. In CAF, we make excessive use of +templates. To keep the code readable despite all the syntax noise, we have some +extra rules for formatting metaprogramming code. + +- Break `using name = ...` statements always directly after `=` if it + does not fit in one line. + +- Consider the *semantics* of a metaprogramming function. For example, + `std::conditional` is an if-then-else construct. Hence, place the if-clause + on its own line and do the same for the two cases. + +- Use one level of indentation per "open" template and place the closing `>`, + `>::type` or `>::value` on its own line. For example: + + ```cpp + using optional_result_type = + typename std::conditional< + std::is_same::value, + bool, + optional + >::type; + // think of it as the following (not valid C++): + auto optional_result_type = + conditional { + if result_type == void + then bool + else optional + }; + ``` + +- Note that this is not necessary when simply defining a type alias. + When dealing with "ordinary" templates, indenting based on the position of + the opening `<` is ok, e.g.: + + ```cpp + using response_handle_type = response_handle; + ``` + +Preprocessor Macros +------------------- + +- Use macros if and only if you can't get the same result by using inline + functions or proper constants. + +- Macro names use the form `CAF__`. + +Comments +-------- + +- Start Doxygen comments with `///`. + +- Use Markdown instead of Doxygen formatters. + +- Use `@cmd` rather than `\cmd`. + +- Use `//` to define basic comments that should not be processed by Doxygen. + diff -Nru actor-framework-0.13.2/.cppcheck-suppressions actor-framework-0.16.3/.cppcheck-suppressions --- actor-framework-0.13.2/.cppcheck-suppressions 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/.cppcheck-suppressions 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,69 @@ +// having an explicit constructor for attachable would +// make it harder to use and its a library internal anyways +noExplicitConstructor:libcaf_core/caf/attachable.hpp + +// cppcheck complains about padding1 and padding2 not +// being initialized, which is silly (never used anywhere) +uninitMemberVar:libcaf_io/caf/io/basp/header.hpp + +// converting raw pointers to intrusive pointers is +// a common operation (e.g. getting a smart pointer to self) +noExplicitConstructor:libcaf_core/caf/intrusive_ptr.hpp +noExplicitConstructor:libcaf_core/caf/weak_intrusive_ptr.hpp + +// cppcheck complains about `node_id(const invalid_node_id_t&)`, +// which must not be explicit because `invalid_node_id_t` would +// be completely useless otherwise, the same is true for +// - `message_id(invalid_message_id_t)` +noExplicitConstructor:libcaf_core/caf/node_id.hpp +noExplicitConstructor:libcaf_core/caf/message_id.hpp + +// the ctor `duration(std::chrono::duration d)` +// is not explicit on purpose +noExplicitConstructor:libcaf_core/caf/duration.hpp + +// making this explicit only makes API worse +noExplicitConstructor:libcaf_core/caf/detail/scope_guard.hpp + +// `operator=(const ref_counted&)` does not assign `rc_` +// on purpose because this would corrupt reference counting +operatorEqVarError:libcaf_core/src/ref_counted.cpp + +// cppcheck complains about not initializing the pad members +uninitMemberVar:libcaf_core/caf/detail/double_ended_queue.hpp + +// making the policy functions static is technically possible, +// but conceptionally questionable +functionStatic:libcaf_core/caf/policy/work_stealing.hpp + +// 9 false positives +*:libcaf_core/caf/optional.hpp + +// in theory always true, but the unit test still needs to check +knownConditionTrueFalse:libcaf_core/test/optional.cpp + +// ignore warnings from any 3rd party module +*:*/third_party/* + +// 6 false positives +*:libcaf_core/caf/detail/limited_vector.hpp + +// `test_struct::test_value` is unused since this file tests `announce` +unusedStructMember:libcaf_io/test/uniform_type.cpp + +// `exit_reason::as_string` is unused in this .cpp file, but part of the API, +// same is true for other falsely reported unused functions +unusedFunction:libcaf_core/src/exit_reason.cpp +unusedFunction:libcaf_core/src/shared_spinlock.cpp +unusedFunction:libcaf_io/src/interfaces.cpp +unusedFunction:libcaf_io/src/max_msg_size.cpp + +// making only some overloads of `abstract_uniform_type_info::eq` +// static fails on MSVC +functionStatic:bcaf_core/caf/abstract_uniform_type_info.hpp + +// functions are used in a macro in opencl/smart_ptr.hpp +unusedFunction:libcaf_opencl/src/global.cpp + +// suppress false positives +unusedStructMember:libcaf_core/test/serialization.cpp diff -Nru actor-framework-0.13.2/debian/changelog actor-framework-0.16.3/debian/changelog --- actor-framework-0.13.2/debian/changelog 2015-07-28 09:16:17.000000000 +0000 +++ actor-framework-0.16.3/debian/changelog 2019-03-02 11:35:04.000000000 +0000 @@ -1,3 +1,21 @@ +actor-framework (0.16.3-0.2) unstable; urgency=medium + + * Non-maintainer upload + * Add Breaks/Replaces to libcaf-doc (Closes: #923547) + + -- Hilko Bengen Sat, 02 Mar 2019 12:35:04 +0100 + +actor-framework (0.16.3-0.1) unstable; urgency=medium + + * Non-maintainer upload + * New upstream version 0.16.3 + * Update SONAME, remove pkg-config files + * Cleanup build system, add -openssl, -doc packages + * Bump Debhelper compat level + * Bump Standards-Version + + -- Hilko Bengen Wed, 06 Feb 2019 00:40:31 +0100 + actor-framework (0.13.2-3) unstable; urgency=medium * Fix pkg-config files diff -Nru actor-framework-0.13.2/debian/compat actor-framework-0.16.3/debian/compat --- actor-framework-0.13.2/debian/compat 2015-06-24 21:48:44.000000000 +0000 +++ actor-framework-0.16.3/debian/compat 2019-02-05 23:47:14.000000000 +0000 @@ -1 +1 @@ -9 +12 diff -Nru actor-framework-0.13.2/debian/control actor-framework-0.16.3/debian/control --- actor-framework-0.13.2/debian/control 2015-07-21 08:44:43.000000000 +0000 +++ actor-framework-0.16.3/debian/control 2019-03-02 11:34:24.000000000 +0000 @@ -1,23 +1,36 @@ Source: actor-framework Priority: optional Maintainer: Robert Lemmen -Build-Depends: debhelper (>= 9), cmake, hevea, texlive-latex-recommended, texlive-latex-base, texlive-fonts-recommended -Standards-Version: 3.9.6 +Build-Depends: debhelper (>= 12~), + cmake, + libssl-dev, +# ocl-icd-opencl-dev, +# python3-pybind11, pybind11-dev, + libcurl4-openssl-dev, + hevea, + texlive-latex-base, texlive-latex-extra, + texlive-fonts-recommended, texlive-fonts-extra, + doxygen, pandoc, python-pandocfilters, graphviz, +Standards-Version: 4.3.0 Section: libs Homepage: http://www.actor-framework.org/ Package: libcaf-dev Section: libdevel Architecture: any -Depends: libcaf-core0.13.2 (= ${binary:Version}), libcaf-io0.13.2 (= ${binary:Version}) , ${misc:Depends} +Depends: libcaf-core0.16.3 (= ${binary:Version}), + libcaf-io0.16.3 (= ${binary:Version}), + libcaf-openssl0.16.3 (= ${binary:Version}), + ${misc:Depends} +Recommends: libcaf-doc Description: Implementation of the Actor Model in C++, development files The actor-framework library facilitates writing applications based on the actor model in C++. It aims to be lightweight, distributed and simple. . - This package contains documentation, examples, headers and other files - required to develop applications against the library. + This package contains headers and other files required to develop + applications against the library. -Package: libcaf-core0.13.2 +Package: libcaf-core0.16.3 Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Implementation of the Actor Model in C++, core library @@ -26,7 +39,7 @@ . This package contains the core library. -Package: libcaf-io0.13.2 +Package: libcaf-io0.16.3 Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Implementation of the Actor Model in C++, I/O library @@ -35,3 +48,24 @@ . This package contains the io library required for network transparency. +Package: libcaf-openssl0.16.3 +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Implementation of the Actor Model in C++, OpenSSL library + The actor-framework library facilitates writing applications based on the + actor model in C++. It aims to be lightweight, distributed and simple. + . + This package contains the io library required for TLS encryption + using OpenSSL. + +Package: libcaf-doc +Section: doc +Architecture: all +Breaks: libcaf-dev (<< 0.16.3) +Replaces: libcaf-dev (<< 0.16.3) +Depends: ${misc:Depends} +Description: Implementation of the Actor Model in C++, development files + The actor-framework library facilitates writing applications based on the + actor model in C++. It aims to be lightweight, distributed and simple. + . + This package contains documentation and examples for the library. diff -Nru actor-framework-0.13.2/debian/libcaf-core0.13.2.dirs actor-framework-0.16.3/debian/libcaf-core0.13.2.dirs --- actor-framework-0.13.2/debian/libcaf-core0.13.2.dirs 2015-06-24 21:48:44.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-core0.13.2.dirs 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib diff -Nru actor-framework-0.13.2/debian/libcaf-core0.13.2.install actor-framework-0.16.3/debian/libcaf-core0.13.2.install --- actor-framework-0.13.2/debian/libcaf-core0.13.2.install 2015-06-24 21:48:44.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-core0.13.2.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib/libcaf_core.so.* diff -Nru actor-framework-0.13.2/debian/libcaf-core0.16.3.dirs actor-framework-0.16.3/debian/libcaf-core0.16.3.dirs --- actor-framework-0.13.2/debian/libcaf-core0.16.3.dirs 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-core0.16.3.dirs 2019-02-05 22:31:16.000000000 +0000 @@ -0,0 +1 @@ +usr/lib diff -Nru actor-framework-0.13.2/debian/libcaf-core0.16.3.install actor-framework-0.16.3/debian/libcaf-core0.16.3.install --- actor-framework-0.13.2/debian/libcaf-core0.16.3.install 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-core0.16.3.install 2019-02-05 22:31:16.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/libcaf_core.so.* diff -Nru actor-framework-0.13.2/debian/libcaf-core.pc actor-framework-0.16.3/debian/libcaf-core.pc --- actor-framework-0.13.2/debian/libcaf-core.pc 2015-07-27 15:28:21.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-core.pc 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -prefix=/usr -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: libcaf-core -Description: Implementation of the Actor Model in C++ -Version: 0.13.2 -Libs: -L${libdir} -lcaf_core -Cflags: -I${includedir} diff -Nru actor-framework-0.13.2/debian/libcaf-dev.dirs actor-framework-0.16.3/debian/libcaf-dev.dirs --- actor-framework-0.13.2/debian/libcaf-dev.dirs 2015-06-24 21:48:45.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-dev.dirs 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -usr/include -usr/lib diff -Nru actor-framework-0.13.2/debian/libcaf-dev.docs actor-framework-0.16.3/debian/libcaf-dev.docs --- actor-framework-0.13.2/debian/libcaf-dev.docs 2015-06-24 23:22:19.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-dev.docs 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -manual/build-pdf/manual.pdf -manual/build-html/manual.html diff -Nru actor-framework-0.13.2/debian/libcaf-dev.install actor-framework-0.16.3/debian/libcaf-dev.install --- actor-framework-0.13.2/debian/libcaf-dev.install 2015-07-28 09:15:59.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-dev.install 2019-02-05 22:34:12.000000000 +0000 @@ -1,5 +1,3 @@ usr/include/* usr/lib/*.so -examples /usr/share/doc/libcaf-dev -debian/libcaf-core.pc /usr/lib/pkgconfig -debian/libcaf-io.pc /usr/lib/pkgconfig + diff -Nru actor-framework-0.13.2/debian/libcaf-doc.docs actor-framework-0.16.3/debian/libcaf-doc.docs --- actor-framework-0.13.2/debian/libcaf-doc.docs 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-doc.docs 2019-02-05 22:34:12.000000000 +0000 @@ -0,0 +1,3 @@ +obj-*/doc/html +obj-*/doc/manual.pdf +obj-*/doc/rst diff -Nru actor-framework-0.13.2/debian/libcaf-doc.install actor-framework-0.16.3/debian/libcaf-doc.install --- actor-framework-0.13.2/debian/libcaf-doc.install 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-doc.install 2019-02-05 23:38:15.000000000 +0000 @@ -0,0 +1 @@ +usr/share/doc/libcaf-doc diff -Nru actor-framework-0.13.2/debian/libcaf-io0.13.2.dirs actor-framework-0.16.3/debian/libcaf-io0.13.2.dirs --- actor-framework-0.13.2/debian/libcaf-io0.13.2.dirs 2015-06-24 21:48:44.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-io0.13.2.dirs 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib diff -Nru actor-framework-0.13.2/debian/libcaf-io0.13.2.install actor-framework-0.16.3/debian/libcaf-io0.13.2.install --- actor-framework-0.13.2/debian/libcaf-io0.13.2.install 2015-06-24 21:48:44.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-io0.13.2.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib/libcaf_io.so.* diff -Nru actor-framework-0.13.2/debian/libcaf-io0.16.3.install actor-framework-0.16.3/debian/libcaf-io0.16.3.install --- actor-framework-0.13.2/debian/libcaf-io0.16.3.install 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-io0.16.3.install 2019-02-05 22:31:16.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/libcaf_io.so.* diff -Nru actor-framework-0.13.2/debian/libcaf-io.pc actor-framework-0.16.3/debian/libcaf-io.pc --- actor-framework-0.13.2/debian/libcaf-io.pc 2015-07-27 15:28:21.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-io.pc 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -prefix=/usr -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: libcaf-io -Description: Implementation of the Actor Model in C++ -Version: 0.13.2 -Libs: -L${libdir} -lcaf_io -Requires: libcaf-core = 0.13.2 -Cflags: -I${includedir} diff -Nru actor-framework-0.13.2/debian/libcaf-openssl0.16.3.install actor-framework-0.16.3/debian/libcaf-openssl0.16.3.install --- actor-framework-0.13.2/debian/libcaf-openssl0.16.3.install 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-openssl0.16.3.install 2019-02-05 22:34:12.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/libcaf_openssl.so.* diff -Nru actor-framework-0.13.2/debian/libcaf-openssl0.16.3.lintian-overrides actor-framework-0.16.3/debian/libcaf-openssl0.16.3.lintian-overrides --- actor-framework-0.13.2/debian/libcaf-openssl0.16.3.lintian-overrides 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/debian/libcaf-openssl0.16.3.lintian-overrides 2019-02-05 22:34:12.000000000 +0000 @@ -0,0 +1 @@ +possible-gpl-code-linked-with-openssl diff -Nru actor-framework-0.13.2/debian/not-installed actor-framework-0.16.3/debian/not-installed --- actor-framework-0.13.2/debian/not-installed 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/debian/not-installed 2019-02-05 22:34:12.000000000 +0000 @@ -0,0 +1 @@ +/usr/share/caf/tools \ No newline at end of file diff -Nru actor-framework-0.13.2/debian/patches/no-cppa-dirs actor-framework-0.16.3/debian/patches/no-cppa-dirs --- actor-framework-0.13.2/debian/patches/no-cppa-dirs 2015-06-24 22:54:39.000000000 +0000 +++ actor-framework-0.16.3/debian/patches/no-cppa-dirs 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -Description: remove cppa directories meant for compatibility headers - ---- actor-framework-0.13.2.orig/CMakeLists.txt -+++ actor-framework-0.13.2/CMakeLists.txt -@@ -250,8 +250,8 @@ endif() - install(DIRECTORY libcaf_core/caf/ - DESTINATION include/caf FILES_MATCHING PATTERN "*.hpp") - # install CPPA compatibility headers --install(DIRECTORY libcaf_core/cppa/ -- DESTINATION include/cppa FILES_MATCHING PATTERN "*.hpp") -+#install(DIRECTORY libcaf_core/cppa/ -+# DESTINATION include/cppa FILES_MATCHING PATTERN "*.hpp") - # install includes from io - install(DIRECTORY libcaf_io/caf/ DESTINATION include/caf - FILES_MATCHING PATTERN "*.hpp") ---- actor-framework-0.13.2.orig/libcaf_core/CMakeLists.txt -+++ actor-framework-0.13.2/libcaf_core/CMakeLists.txt -@@ -11,8 +11,7 @@ file(GLOB LIBCAF_CORE_HDRS "caf/*.hpp" - "caf/detail/*.hpp" - "caf/policy/*.hpp" - "caf/mixin/*.hpp" -- "caf/scheduler/*.hpp" -- "cppa/*.hpp") -+ "caf/scheduler/*.hpp") - - # list cpp files excluding platform-dependent files - set (LIBCAF_CORE_SRCS ---- actor-framework-0.13.2.orig/libcaf_io/CMakeLists.txt -+++ actor-framework-0.13.2/libcaf_io/CMakeLists.txt -@@ -57,5 +57,4 @@ include_directories(. ${INCLUDE_DIRS}) - # install includes - if(NOT WIN32) - install(DIRECTORY caf/ DESTINATION include/caf FILES_MATCHING PATTERN "*.hpp") -- install(DIRECTORY cppa/ DESTINATION include/cppa FILES_MATCHING PATTERN "*.hpp") - endif() diff -Nru actor-framework-0.13.2/debian/patches/series actor-framework-0.16.3/debian/patches/series --- actor-framework-0.13.2/debian/patches/series 2015-06-24 22:54:22.000000000 +0000 +++ actor-framework-0.16.3/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -no-cppa-dirs diff -Nru actor-framework-0.13.2/debian/rules actor-framework-0.16.3/debian/rules --- actor-framework-0.13.2/debian/rules 2015-06-24 21:48:45.000000000 +0000 +++ actor-framework-0.16.3/debian/rules 2019-02-05 22:34:12.000000000 +0000 @@ -6,17 +6,20 @@ export DEB_CXXFLAGS_MAINT_APPEND = -std=c++11 -pthread override_dh_auto_configure: - ./configure --prefix=/usr --no-unit-tests + dh_auto_configure -- -DCAF_BUILD_TEX_MANUAL=1 override_dh_auto_build: - dh_auto_build - $(MAKE) -C manual + dh_auto_build -- all doxygen doc -override_dh_clean: - dh_clean - rm -f manual/variables.tex - $(MAKE) -C manual clean +override_dh_install: + mkdir -p debian/tmp/usr/share/doc/libcaf-doc + mv debian/tmp/usr/share/caf/examples \ + debian/tmp/usr/share/doc/libcaf-doc + dh_install + +override_dh_missing: + dh_missing --fail-missing %: - dh $@ + dh $@ --buildsystem=cmake diff -Nru actor-framework-0.13.2/doc/cmake/conf.py.in actor-framework-0.16.3/doc/cmake/conf.py.in --- actor-framework-0.13.2/doc/cmake/conf.py.in 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/cmake/conf.py.in 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,336 @@ +# -*- coding: utf-8 -*- +# +# CAF documentation build configuration file, created by +# sphinx-quickstart on Fri Jun 3 11:27:36 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +import sphinx_rtd_theme + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +# +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'CAF' +copyright = u'2016, Dominik Charousset' +author = u'Dominik Charousset' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = u'@CAF_VERSION@' +# The full version, including alpha/beta/rc tags. +release = u'@CAF_RELEASE@' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# +# today = '' +# +# Else, today_fmt is used as the format for a strftime call. +# +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +highlight_language = 'C++' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +# +# html_title = u'CAF v0.15' + +# A shorter title for the navigation bar. Default is the same as html_title. +# +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# +# html_logo = None + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# +# html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# +# html_last_updated_fmt = None + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# +# html_additional_pages = {} + +# If false, no module index is generated. +# +# html_domain_indices = True + +# If false, no index is generated. +# +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' +# +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'CAFdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'CAF.tex', u'CAF Documentation', + u'Dominik Charousset', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# +# latex_use_parts = False + +# If true, show page references after internal links. +# +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# +# latex_appendices = [] + +# If false, no module index is generated. +# +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'caf', u'CAF Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +# +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'CAF', u'CAF Documentation', + author, 'CAF', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +# +# texinfo_appendices = [] + +# If false, no module index is generated. +# +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# +# texinfo_no_detailmenu = False diff -Nru actor-framework-0.13.2/doc/cmake/Doxyfile.in actor-framework-0.16.3/doc/cmake/Doxyfile.in --- actor-framework-0.13.2/doc/cmake/Doxyfile.in 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/cmake/Doxyfile.in 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,1201 @@ +# Doxyfile 1.8.0 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Enable markdown support +#--------------------------------------------------------------------------- + +MARKDOWN_SUPPORT = YES + +#--------------------------------------------------------------------------- +# Project related actor_system& system, const uration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the actor_system& system, const file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = libcaf + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @CAF_VERSION@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 2 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = experimental="@attention This feature is **experimental**." + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C + +EXTENSION_MAPPING = C++ + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = NO + + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +#--------------------------------------------------------------------------- +# Build related actor_system& system, const uration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = NO + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = YES + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = YES + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# actor_system& system, const uration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# actor_system& system, const uration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = "@CMAKE_HOME_DIRECTORY@/libcaf_core/caf" \ + "@CMAKE_HOME_DIRECTORY@/libcaf_core/caf/meta" \ + "@CMAKE_HOME_DIRECTORY@/libcaf_core/caf/mixin" \ + "@CMAKE_HOME_DIRECTORY@/libcaf_core/caf/policy" \ + "@CMAKE_HOME_DIRECTORY@/libcaf_core/caf/scheduler" \ + "@CMAKE_HOME_DIRECTORY@/libcaf_io/caf/io" \ + "@CMAKE_HOME_DIRECTORY@/libcaf_io/caf/io/network" + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = examples + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = YES + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = "@CMAKE_HOME_DIRECTORY@/doc/png/" + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# actor_system& system, const uration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# actor_system& system, const uration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# actor_system& system, const uration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 1 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# Disable everything but HTML +#--------------------------------------------------------------------------- + +GENERATE_LATEX = NO + +GENERATE_RTF = NO + +GENERATE_MAN = NO + +GENERATE_XML = NO + +GENERATE_AUTOGEN_DEF = NO + +GENERATE_PERLMOD = NO + +GENERATE_DOCSET = NO + +GENERATE_QHP = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = CAF_DOCUMENTATION + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Options related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = YES diff -Nru actor-framework-0.13.2/doc/cmake/index_footer.rst.in actor-framework-0.16.3/doc/cmake/index_footer.rst.in --- actor-framework-0.13.2/doc/cmake/index_footer.rst.in 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/cmake/index_footer.rst.in 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,6 @@ +Version Information +=================== + +This version of the Manual was automatically generated from CAF commit +`@CAF_SHA@ `_. + diff -Nru actor-framework-0.13.2/doc/cmake/index_header.rst.in actor-framework-0.16.3/doc/cmake/index_header.rst.in --- actor-framework-0.13.2/doc/cmake/index_header.rst.in 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/cmake/index_header.rst.in 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,8 @@ +CAF User Manual +=============== + +**C++ Actor Framework** version @CAF_RELEASE@. + +Contents +======== + diff -Nru actor-framework-0.13.2/doc/cmake/UseLATEX.cmake actor-framework-0.16.3/doc/cmake/UseLATEX.cmake --- actor-framework-0.13.2/doc/cmake/UseLATEX.cmake 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/cmake/UseLATEX.cmake 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,1942 @@ +# File: UseLATEX.cmake +# CMAKE commands to actually use the LaTeX compiler +# Version: 2.4.8 +# Author: Kenneth Moreland +# +# Copyright 2004, 2015 Sandia Corporation. +# Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive +# license for use of this work by or on behalf of the U.S. Government. +# +# This software is released under the BSD 3-Clause License. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# The following function is defined: +# +# add_latex_document( +# [BIBFILES ] +# [INPUTS ] +# [IMAGE_DIRS] +# [IMAGES] +# [CONFIGURE] +# [DEPENDS] +# [MULTIBIB_NEWCITES] +# [USE_BIBLATEX] +# [USE_INDEX] +# [INDEX_NAMES ] +# [USE_GLOSSARY] [USE_NOMENCL] +# [FORCE_PDF] [FORCE_DVI] [FORCE_HTML] +# [TARGET_NAME] +# [EXCLUDE_FROM_ALL] +# [EXCLUDE_FROM_DEFAULTS]) +# Adds targets that compile . The latex output is placed +# in LATEX_OUTPUT_PATH or CMAKE_CURRENT_BINARY_DIR if the former is +# not set. The latex program is picky about where files are located, +# so all input files are copied from the source directory to the +# output directory. This includes the target tex file, any tex file +# listed with the INPUTS option, the bibliography files listed with +# the BIBFILES option, and any .cls, .bst, .clo, .sty, .ist, and .fd +# files found in the current source directory. Images found in the +# IMAGE_DIRS directories or listed by IMAGES are also copied to the +# output directory and converted to an appropriate format if necessary. +# Any tex files also listed with the CONFIGURE option are also processed +# with the CMake CONFIGURE_FILE command (with the @ONLY flag). Any file +# listed in CONFIGURE but not the target tex file or listed with INPUTS +# has no effect. DEPENDS can be used to specify generated files that are +# needed to compile the latex target. +# +# The following targets are made. The name prefix is based off of the +# base name of the tex file unless TARGET_NAME is specified. If +# TARGET_NAME is specified, then that name is used for the targets. +# +# name_dvi: Makes .dvi +# name_pdf: Makes .pdf using pdflatex. +# name_safepdf: Makes .pdf using ps2pdf. If using the +# default program arguments, this will ensure all fonts +# are embedded and no lossy compression has been +# performed on images. +# name_ps: Makes .ps +# name_html: Makes .html +# name_auxclean: Deletes .aux and other auxiliary files. +# This is sometimes necessary if a LaTeX error occurs +# and writes a bad aux file. Unlike the regular clean +# target, it does not delete other input files, such as +# converted images, to save time on the rebuild. +# +# Unless the EXCLUDE_FROM_ALL option is given, one of these targets +# is added to the ALL target and built by default. Which target is +# determined by the LATEX_DEFAULT_BUILD CMake variable. See the +# documentation of that variable for more details. +# +# Unless the EXCLUDE_FROM_DEFAULTS option is given, all these targets +# are added as dependencies to targets named dvi, pdf, safepdf, ps, +# html, and auxclean, respectively. +# +# USE_BIBLATEX enables the use of biblatex/biber as an alternative to +# bibtex. Bibtex remains the default if USE_BIBLATEX is not +# specified. +# +# If the argument USE_INDEX is given, then commands to build an index +# are made. If the argument INDEX_NAMES is given, an index file is +# generated for each name in this list. See the LaTeX package multind +# for more information about how to generate multiple indices. +# +# If the argument USE_GLOSSARY is given, then commands to +# build a glossary are made. If the argument MULTIBIB_NEWCITES is +# given, then additional bibtex calls are added to the build to +# support the extra auxiliary files created with the \newcite command +# in the multibib package. +# +# History: +# +# 2.4.8 Fix synctex issue with absolute paths not being converted. +# +# 2.4.7 Fix some issues with spaces in the path of the working directory where +# LaTeX is executed. +# +# 2.4.6 Fix parse issue with older versions of CMake. +# +# 2.4.5 Fix issues with files and paths containing spaces. +# +# 2.4.4 Improve error reporting message when LaTeX fails. +# +# When LaTeX fails, delete the output file, which is invalid. +# +# Add warnings for "missing characters." These usually mean that a +# non-ASCII character is in the document and will not be printed +# correctly. +# +# 2.4.3 Check for warnings from the natbib package. When using natbib, +# warnings for missing bibliography references look different. So +# far, natbib seems to be quiet unless something is important, so +# look for all natbib warnings. (We can change this later if +# necessary.) +# +# 2.4.2 Fix an issue where new versions of ImageMagick expect the order of +# options in command line execution of magick/convert. (See, for +# example, http://www.imagemagick.org/Usage/basics/#why.) +# +# 2.4.1 Add ability to dump LaTeX log file when using batch mode. Batch +# mode suppresses most output, often including error messages. To +# make sure critical error messages get displayed, show the full log +# on failures. +# +# 2.4.0 Remove "-r 600" from the default PDFTOPS_CONVERTER_FLAGS. The -r flag +# is available from the Poppler version of pdftops, but not the Xpdf +# version. +# +# Fix an issue with the flags for the different programs not being +# properly separated. +# +# Fix an issue on windows where the = character is not allowed for +# ps2pdf arguments. +# +# Change default arguments for latex and pdflatex commands. Makes the +# output more quiet and prints out the file/line where errors occur. +# (Thanks to Nikos Koukis.) +# +# After a LaTeX build, check the log file for warnings that are +# indicative of problems with the build. +# +# Remove support for latex2html. Instead, use the htlatex program. +# This is now part of TeX Live and most other distributions. It also +# behaves much more like the other LaTeX programs. Also fixed some +# nasty issues with the htlatex arguments. +# +# 2.3.2 Declare LaTeX input files as sources for targets so that they show +# up in IDEs like QtCreator. +# +# Fix issue where main tex files in subdirectories were creating +# invalid targets for building HTML. Just disable the HTML targets in +# this case. +# +# 2.3.1 Support use of magick command instead of convert command for +# ImageMagick 7. +# +# 2.3.0 Add USE_BIBLATEX option to support the biblatex package, which +# requires using the program biber as a replacement for bibtex +# (thanks to David Tracey). +# +# 2.2.1 Add STRINGS property to LATEX_DEFAULT_BUILD to make it easier to +# select the default build in the CMake GUI. +# +# 2.2.0 Add TARGET_NAME option. +# +# 2.1.1 Support for finding bmp, ppm, and other image files. +# +# 2.1.0 Fix an error where the pdf target and others were defined multiple +# times if UseLATEX.cmake was included multiple times. +# +# Added INDEX_NAMES option to support multiple indexes in a single +# document from the multind package (thanks to Dan Lipsa). +# +# 2.0.0 First major revision of UseLATEX.cmake updates to more recent features +# of CMake and some non-backward compatible changes. +# +# Changed all function and macro names to lower case. CMake's identifiers +# are case insensitive, but the convention moved from all upper case to +# all lower case somewhere around the release of CMake 2. (The original +# version of UseLATEX.cmake predates that.) +# +# Remove condition matching in if statements. They are no longer necessary +# and are even discouraged (because else clauses get confusing). +# +# Use "new" features available in CMake such as list and argument parsing. +# +# Remove some code that has been deprecated for a while. +# +# Mark variables for compiler and converter executables as advanced to +# match the more conventional CMake behavior. +# +# Changed how default builds are specified and add the ability to force +# a particular build. +# +# Made the base targets (pdf, dvi, etc.) global. add_latex_document +# always mangles its target names and these base targets depend on +# the targets with mangled names. +# +# 1.10.5 Fix for Window's convert check (thanks to Martin Baute). +# +# 1.10.4 Copy font files to binary directory for packages that come with +# their own fonts. +# +# 1.10.3 Check for Windows version of convert being used instead of +# ImageMagick's version (thanks to Martin Baute). +# +# 1.10.2 Use htlatex as a fallback when latex2html is not available (thanks +# to Tomasz Grzegurzko). +# +# 1.10.1 Make convert program mandatory only if actually used (thanks to +# Julien Schueller). +# +# 1.10.0 Added NO_DEFAULT and DEFAULT_PS options. +# Fixed issue with cleaning files for LaTeX documents originating in +# a subdirectory. +# +# 1.9.6 Fixed problem with LATEX_SMALL_IMAGES. +# Strengthened check to make sure the output directory does not contain +# the source files. +# +# 1.9.5 Add support for image types not directly supported by either latex +# or pdflatex. (Thanks to Jorge Gerardo Pena Pastor for SVG support.) +# +# 1.9.4 Fix issues with filenames containing multiple periods. +# +# 1.9.3 Hide some variables that are now cached but should not show up in +# the ccmake list of variables. +# +# 1.9.2 Changed MACRO declarations to FUNCTION declarations. The better +# FUNCTION scoping will hopefully avoid some common but subtle bugs. +# This implicitly increases the minimum CMake version to 4.6 (although +# I honestly only test it with the latest 4.8 version). +# +# Since we are updating the minimum CMake version, I'm going to start +# using the builtin LIST commands that are now available. +# +# Favor using pdftops from the Poppler package to convert from pdf to +# eps. It does a much better job than ImageMagick or ghostscript. +# +# 1.9.1 Fixed typo that caused the LATEX_SMALL_IMAGES option to fail to +# activate. +# +# 1.9.0 Add support for the multibib package (thanks to Antonio LaTorre). +# +# 1.8.2 Fix corner case when an argument name was also a variable containing +# the text of an argument. In this case, the CMake IF was matching +# the argument text with the contents of the variable with the same +# argument name. +# +# 1.8.1 Fix problem where ps2pdf was not getting the appropriate arguments. +# +# 1.8.0 Add support for synctex. +# +# 1.7.7 Support calling xindy when making glossaries. +# +# Improved make clean support. +# +# 1.7.6 Add support for the nomencl package (thanks to Myles English). +# +# 1.7.5 Fix issue with bibfiles being copied two different ways, which causes +# Problems with dependencies (thanks to Edwin van Leeuwen). +# +# 1.7.4 Added the DEFAULT_SAFEPDF option (thanks to Raymond Wan). +# +# Added warnings when image directories are not found (and were +# probably not given relative to the source directory). +# +# 1.7.3 Fix some issues with interactions between makeglossaries and bibtex +# (thanks to Mark de Wever). +# +# 1.7.2 Use ps2pdf to convert eps to pdf to get around the problem with +# ImageMagick dropping the bounding box (thanks to Lukasz Lis). +# +# 1.7.1 Fixed some dependency issues. +# +# 1.7.0 Added DEPENDS options (thanks to Theodore Papadopoulo). +# +# 1.6.1 Ported the makeglossaries command to CMake and embedded the port +# into UseLATEX.cmake. +# +# 1.6.0 Allow the use of the makeglossaries command. Thanks to Oystein +# S. Haaland for the patch. +# +# 1.5.0 Allow any type of file in the INPUTS lists, not just tex file +# (suggested by Eric Noulard). As a consequence, the ability to +# specify tex files without the .tex extension is removed. The removed +# function is of dubious value anyway. +# +# When copying input files, skip over any file that exists in the +# binary directory but does not exist in the source directory with the +# assumption that these files were added by some other mechanism. I +# find this useful when creating large documents with multiple +# chapters that I want to build separately (for speed) as I work on +# them. I use the same boilerplate as the starting point for all +# and just copy it with different configurations. This was what the +# separate ADD_LATEX_DOCUMENT method was supposed to originally be for. +# Since its external use is pretty much deprecated, I removed that +# documentation. +# +# 1.4.1 Copy .sty files along with the other class and package files. +# +# 1.4.0 Added a MANGLE_TARGET_NAMES option that will mangle the target names. +# +# Fixed problem with copying bib files that became apparent with +# CMake 2.4. +# +# 1.3.0 Added a LATEX_OUTPUT_PATH variable that allows you or the user to +# specify where the built latex documents to go. This is especially +# handy if you want to do in-source builds. +# +# Removed the ADD_LATEX_IMAGES macro and absorbed the functionality +# into ADD_LATEX_DOCUMENT. The old interface was always kind of +# clunky anyway since you had to specify the image directory in both +# places. It also made supporting LATEX_OUTPUT_PATH problematic. +# +# Added support for jpeg files. +# +# 1.2.0 Changed the configuration options yet again. Removed the NO_CONFIGURE +# Replaced it with a CONFIGURE option that lists input files for which +# configure should be run. +# +# The pdf target no longer depends on the dvi target. This allows you +# to build latex documents that require pdflatex. Also added an option +# to make the pdf target the default one. +# +# 1.1.1 Added the NO_CONFIGURE option. The @ character can be used when +# specifying table column separators. If two or more are used, then +# will incorrectly substitute them. +# +# 1.1.0 Added ability include multiple bib files. Added ability to do copy +# sub-tex files for multipart tex files. +# +# 1.0.0 If both ps and pdf type images exist, just copy the one that +# matches the current render mode. Replaced a bunch of STRING +# commands with GET_FILENAME_COMPONENT commands that were made to do +# the desired function. +# +# 0.4.0 First version posted to CMake Wiki. +# + +if(__USE_LATEX_INCLUDED) + return() +endif() +set(__USE_LATEX_INCLUDED TRUE) + +############################################################################# +# Find the location of myself while originally executing. If you do this +# inside of a macro, it will recode where the macro was invoked. +############################################################################# +set(LATEX_USE_LATEX_LOCATION ${CMAKE_CURRENT_LIST_FILE} + CACHE INTERNAL "Location of UseLATEX.cmake file." FORCE + ) + +############################################################################# +# Generic helper functions +############################################################################# + +include(CMakeParseArguments) + +function(latex_list_contains var value) + set(input_list ${ARGN}) + list(FIND input_list "${value}" index) + if(index GREATER -1) + set(${var} TRUE PARENT_SCOPE) + else() + set(${var} PARENT_SCOPE) + endif() +endfunction(latex_list_contains) + +# Match the contents of a file to a regular expression. +function(latex_file_match variable filename regexp default) + # The FILE STRINGS command would be a bit better, but I'm not totally sure + # the match will always be to a whole line, and I don't want to break things. + file(READ ${filename} file_contents) + string(REGEX MATCHALL "${regexp}" + match_result ${file_contents} + ) + if(match_result) + set(${variable} "${match_result}" PARENT_SCOPE) + else() + set(${variable} "${default}" PARENT_SCOPE) + endif() +endfunction(latex_file_match) + +# A version of GET_FILENAME_COMPONENT that treats extensions after the last +# period rather than the first. To the best of my knowledge, all filenames +# typically used by LaTeX, including image files, have small extensions +# after the last dot. +function(latex_get_filename_component varname filename type) + set(result) + if("${type}" STREQUAL "NAME_WE") + get_filename_component(name ${filename} NAME) + string(REGEX REPLACE "\\.[^.]*\$" "" result "${name}") + elseif("${type}" STREQUAL "EXT") + get_filename_component(name ${filename} NAME) + string(REGEX MATCH "\\.[^.]*\$" result "${name}") + else() + get_filename_component(result ${filename} ${type}) + endif() + set(${varname} "${result}" PARENT_SCOPE) +endfunction(latex_get_filename_component) + +############################################################################# +# Functions that perform processing during a LaTeX build. +############################################################################# +function(latex_execute_latex) + if(NOT LATEX_TARGET) + message(SEND_ERROR "Need to define LATEX_TARGET") + endif() + + if(NOT LATEX_WORKING_DIRECTORY) + message(SEND_ERROR "Need to define LATEX_WORKING_DIRECTORY") + endif() + + if(NOT LATEX_FULL_COMMAND) + message(SEND_ERROR "Need to define LATEX_FULL_COMMAND") + endif() + + if(NOT LATEX_OUTPUT_FILE) + message(SEND_ERROR "Need to define LATEX_OUTPUT_FILE") + endif() + + set(full_command_original "${LATEX_FULL_COMMAND}") + + # Chose the native method for parsing command arguments. Newer versions of + # CMake allow you to just use NATIVE_COMMAND. + if (CMAKE_VERSION VERSION_GREATER 3.8) + set(separate_arguments_mode NATIVE_COMMAND) + else() + if (WIN32) + set(separate_arguments_mode WINDOWS_COMMAND) + else() + set(separate_arguments_mode UNIX_COMMAND) + endif() + endif() + + # Preps variables for use in execute_process. + # Even though we expect LATEX_WORKING_DIRECTORY to have a single "argument," + # we also want to make sure that we strip out any escape characters that can + # foul up the WORKING_DIRECTORY argument. + separate_arguments(LATEX_FULL_COMMAND UNIX_COMMAND "${LATEX_FULL_COMMAND}") + separate_arguments(LATEX_WORKING_DIRECTORY_SEP UNIX_COMMAND "${LATEX_WORKING_DIRECTORY}") + + execute_process( + COMMAND ${LATEX_FULL_COMMAND} + WORKING_DIRECTORY "${LATEX_WORKING_DIRECTORY_SEP}" + RESULT_VARIABLE execute_result + ) + + if(NOT ${execute_result} EQUAL 0) + # LaTeX tends to write a file when a failure happens. Delete that file so + # that LaTeX will run again. + file(REMOVE "${LATEX_WORKING_DIRECTORY}/${LATEX_OUTPUT_FILE}") + + message("\n\nLaTeX command failed") + message("${full_command_original}") + message("Log output:") + file(READ "${LATEX_WORKING_DIRECTORY}/${LATEX_TARGET}.log" log_output) + message("${log_output}") + message(FATAL_ERROR + "Successfully executed LaTeX, but LaTeX returned an error.") + endif() +endfunction(latex_execute_latex) + +function(latex_makeglossaries) + # This is really a bare bones port of the makeglossaries perl script into + # CMake scripting. + message("**************************** In makeglossaries") + if(NOT LATEX_TARGET) + message(SEND_ERROR "Need to define LATEX_TARGET") + endif() + + set(aux_file ${LATEX_TARGET}.aux) + + if(NOT EXISTS ${aux_file}) + message(SEND_ERROR "${aux_file} does not exist. Run latex on your target file.") + endif() + + latex_file_match(newglossary_lines ${aux_file} + "@newglossary[ \t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}" + "@newglossary{main}{glg}{gls}{glo}" + ) + + latex_file_match(istfile_line ${aux_file} + "@istfilename[ \t]*{([^}]*)}" + "@istfilename{${LATEX_TARGET}.ist}" + ) + string(REGEX REPLACE "@istfilename[ \t]*{([^}]*)}" "\\1" + istfile ${istfile_line} + ) + + string(REGEX MATCH ".*\\.xdy" use_xindy "${istfile}") + if(use_xindy) + message("*************** Using xindy") + if(NOT XINDY_COMPILER) + message(SEND_ERROR "Need to define XINDY_COMPILER") + endif() + else() + message("*************** Using makeindex") + if(NOT MAKEINDEX_COMPILER) + message(SEND_ERROR "Need to define MAKEINDEX_COMPILER") + endif() + endif() + + foreach(newglossary ${newglossary_lines}) + string(REGEX REPLACE + "@newglossary[ \t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}" + "\\1" glossary_name ${newglossary} + ) + string(REGEX REPLACE + "@newglossary[ \t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}" + "${LATEX_TARGET}.\\2" glossary_log ${newglossary} + ) + string(REGEX REPLACE + "@newglossary[ \t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}" + "${LATEX_TARGET}.\\3" glossary_out ${newglossary} + ) + string(REGEX REPLACE + "@newglossary[ \t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}" + "${LATEX_TARGET}.\\4" glossary_in ${newglossary} + ) + + if(use_xindy) + latex_file_match(xdylanguage_line ${aux_file} + "@xdylanguage[ \t]*{${glossary_name}}{([^}]*)}" + "@xdylanguage{${glossary_name}}{english}" + ) + string(REGEX REPLACE + "@xdylanguage[ \t]*{${glossary_name}}{([^}]*)}" + "\\1" + language + ${xdylanguage_line} + ) + # What crazy person makes a LaTeX index generator that uses different + # identifiers for language than babel (or at least does not support + # the old ones)? + if(${language} STREQUAL "frenchb") + set(language "french") + elseif(${language} MATCHES "^n?germanb?$") + set(language "german") + elseif(${language} STREQUAL "magyar") + set(language "hungarian") + elseif(${language} STREQUAL "lsorbian") + set(language "lower-sorbian") + elseif(${language} STREQUAL "norsk") + set(language "norwegian") + elseif(${language} STREQUAL "portuges") + set(language "portuguese") + elseif(${language} STREQUAL "russianb") + set(language "russian") + elseif(${language} STREQUAL "slovene") + set(language "slovenian") + elseif(${language} STREQUAL "ukraineb") + set(language "ukrainian") + elseif(${language} STREQUAL "usorbian") + set(language "upper-sorbian") + endif() + if(language) + set(language_flags "-L ${language}") + else() + set(language_flags "") + endif() + + latex_file_match(codepage_line ${aux_file} + "@gls@codepage[ \t]*{${glossary_name}}{([^}]*)}" + "@gls@codepage{${glossary_name}}{utf}" + ) + string(REGEX REPLACE + "@gls@codepage[ \t]*{${glossary_name}}{([^}]*)}" + "\\1" + codepage + ${codepage_line} + ) + if(codepage) + set(codepage_flags "-C ${codepage}") + else() + # Ideally, we would check that the language is compatible with the + # default codepage, but I'm hoping that distributions will be smart + # enough to specify their own codepage. I know, it's asking a lot. + set(codepage_flags "") + endif() + + message("${XINDY_COMPILER} ${MAKEGLOSSARIES_COMPILER_ARGS} ${language_flags} ${codepage_flags} -I xindy -M ${glossary_name} -t ${glossary_log} -o ${glossary_out} ${glossary_in}" + ) + exec_program(${XINDY_COMPILER} + ARGS ${MAKEGLOSSARIES_COMPILER_ARGS} + ${language_flags} + ${codepage_flags} + -I xindy + -M ${glossary_name} + -t ${glossary_log} + -o ${glossary_out} + ${glossary_in} + OUTPUT_VARIABLE xindy_output + ) + message("${xindy_output}") + + # So, it is possible (perhaps common?) for aux files to specify a + # language and codepage that are incompatible with each other. Check + # for that condition, and if it happens run again with the default + # codepage. + if("${xindy_output}" MATCHES "^Cannot locate xindy module for language (.+) in codepage (.+)\\.$") + message("*************** Retrying xindy with default codepage.") + exec_program(${XINDY_COMPILER} + ARGS ${MAKEGLOSSARIES_COMPILER_ARGS} + ${language_flags} + -I xindy + -M ${glossary_name} + -t ${glossary_log} + -o ${glossary_out} + ${glossary_in} + ) + endif() + + else() + message("${MAKEINDEX_COMPILER} ${MAKEGLOSSARIES_COMPILER_ARGS} -s ${istfile} -t ${glossary_log} -o ${glossary_out} ${glossary_in}") + exec_program(${MAKEINDEX_COMPILER} ARGS ${MAKEGLOSSARIES_COMPILER_ARGS} + -s ${istfile} -t ${glossary_log} -o ${glossary_out} ${glossary_in} + ) + endif() + + endforeach(newglossary) +endfunction(latex_makeglossaries) + +function(latex_makenomenclature) + message("**************************** In makenomenclature") + if(NOT LATEX_TARGET) + message(SEND_ERROR "Need to define LATEX_TARGET") + endif() + + if(NOT MAKEINDEX_COMPILER) + message(SEND_ERROR "Need to define MAKEINDEX_COMPILER") + endif() + + set(nomencl_out ${LATEX_TARGET}.nls) + set(nomencl_in ${LATEX_TARGET}.nlo) + + exec_program(${MAKEINDEX_COMPILER} ARGS ${MAKENOMENCLATURE_COMPILER_ARGS} + ${nomencl_in} -s "nomencl.ist" -o ${nomencl_out} + ) +endfunction(latex_makenomenclature) + +function(latex_correct_synctex) + message("**************************** In correct SyncTeX") + if(NOT LATEX_TARGET) + message(SEND_ERROR "Need to define LATEX_TARGET") + endif() + + if(NOT GZIP) + message(SEND_ERROR "Need to define GZIP") + endif() + + if(NOT LATEX_SOURCE_DIRECTORY) + message(SEND_ERROR "Need to define LATEX_SOURCE_DIRECTORY") + endif() + + if(NOT LATEX_BINARY_DIRECTORY) + message(SEND_ERROR "Need to define LATEX_BINARY_DIRECTORY") + endif() + message("${LATEX_BINARY_DIRECTORY}") + message("${LATEX_SOURCE_DIRECTORY}") + + set(synctex_file ${LATEX_BINARY_DIRECTORY}/${LATEX_TARGET}.synctex) + set(synctex_file_gz ${synctex_file}.gz) + + if(EXISTS ${synctex_file_gz}) + + message("Making backup of synctex file.") + configure_file(${synctex_file_gz} ${synctex_file}.bak.gz COPYONLY) + + message("Uncompressing synctex file.") + exec_program(${GZIP} + ARGS --decompress ${synctex_file_gz} + ) + + message("Reading synctex file.") + file(READ ${synctex_file} synctex_data) + + message("Replacing output paths with input paths.") + foreach(extension tex cls bst clo sty ist fd) + # Relative paths + string(REGEX REPLACE + "(Input:[0-9]+:)([^/\n][^\n]\\.${extension}*)" + "\\1${LATEX_SOURCE_DIRECTORY}/\\2" + synctex_data + "${synctex_data}" + ) + + # Absolute paths + string(REGEX REPLACE + "(Input:[0-9]+:)${LATEX_BINARY_DIRECTORY}([^\n]*\\.${extension})" + "\\1${LATEX_SOURCE_DIRECTORY}\\2" + synctex_data + "${synctex_data}" + ) + endforeach(extension) + + message("Writing synctex file.") + file(WRITE ${synctex_file} "${synctex_data}") + + message("Compressing synctex file.") + exec_program(${GZIP} + ARGS ${synctex_file} + ) + + else() + + message(SEND_ERROR "File ${synctex_file_gz} not found. Perhaps synctex is not supported by your LaTeX compiler.") + + endif() + +endfunction(latex_correct_synctex) + +function(latex_check_important_warnings) + set(log_file ${LATEX_TARGET}.log) + + message("\nChecking ${log_file} for important warnings.") + if(NOT LATEX_TARGET) + message(SEND_ERROR "Need to define LATEX_TARGET") + endif() + + if(NOT EXISTS ${log_file}) + message("Could not find log file: ${log_file}") + return() + endif() + + set(found_error) + + file(READ ${log_file} log) + + # Check for undefined references + string(REGEX MATCHALL + "\n[^\n]*Reference[^\n]*undefined[^\n]*" + reference_warnings + "${log}") + if(reference_warnings) + set(found_error TRUE) + message("\nFound missing reference warnings.") + foreach(warning ${reference_warnings}) + string(STRIP "${warning}" warning_no_newline) + message("${warning_no_newline}") + endforeach(warning) + endif() + + # Check for natbib warnings + string(REGEX MATCHALL + "\nPackage natbib Warning:[^\n]*" + natbib_warnings + "${log}") + if(natbib_warnings) + set(found_error TRUE) + message("\nFound natbib package warnings.") + foreach(warning ${natbib_warnings}) + string(STRIP "${warning}" warning_no_newline) + message("${warning_no_newline}") + endforeach(warning) + endif() + + # Check for overfull + string(REGEX MATCHALL + "\nOverfull[^\n]*" + overfull_warnings + "${log}") + if(overfull_warnings) + set(found_error TRUE) + message("\nFound overfull warnings. These are indicative of layout errors.") + foreach(warning ${overfull_warnings}) + string(STRIP "${warning}" warning_no_newline) + message("${warning_no_newline}") + endforeach(warning) + endif() + + # Check for invalid characters + string(REGEX MATCHALL + "\nMissing character:[^\n]*" + invalid_character_warnings + "${log}") + if(invalid_character_warnings) + set(found_error TRUE) + message("\nFound invalid character warnings. These characters are likely not printed correctly.") + foreach(warning ${invalid_character_warnings}) + string(STRIP "${warning}" warning_no_newline) + message("${warning_no_newline}") + endforeach(warning) + endif() + + if(found_error) + latex_get_filename_component(log_file_path ${log_file} ABSOLUTE) + message("\nConsult ${log_file_path} for more information on LaTeX build.") + else() + message("No known important warnings found.") + endif(found_error) +endfunction(latex_check_important_warnings) + +############################################################################# +# Helper functions for establishing LaTeX build. +############################################################################# + +function(latex_needit VAR NAME) + if(NOT ${VAR}) + message(SEND_ERROR "I need the ${NAME} command.") + endif() +endfunction(latex_needit) + +function(latex_wantit VAR NAME) + if(NOT ${VAR}) + message(STATUS "I could not find the ${NAME} command.") + endif() +endfunction(latex_wantit) + +function(latex_setup_variables) + set(LATEX_OUTPUT_PATH "${LATEX_OUTPUT_PATH}" + CACHE PATH "If non empty, specifies the location to place LaTeX output." + ) + + find_package(LATEX) + + find_program(XINDY_COMPILER + NAME xindy + PATHS ${MIKTEX_BINARY_PATH} /usr/bin + ) + + find_package(UnixCommands) + + find_program(PDFTOPS_CONVERTER + NAMES pdftops + DOC "The pdf to ps converter program from the Poppler package." + ) + + find_program(HTLATEX_COMPILER + NAMES htlatex + PATHS ${MIKTEX_BINARY_PATH} + /usr/bin + ) + + mark_as_advanced( + LATEX_COMPILER + PDFLATEX_COMPILER + BIBTEX_COMPILER + BIBER_COMPILER + MAKEINDEX_COMPILER + XINDY_COMPILER + DVIPS_CONVERTER + PS2PDF_CONVERTER + PDFTOPS_CONVERTER + LATEX2HTML_CONVERTER + HTLATEX_COMPILER + ) + + latex_needit(LATEX_COMPILER latex) + latex_wantit(PDFLATEX_COMPILER pdflatex) + latex_wantit(HTLATEX_COMPILER htlatex) + latex_needit(BIBTEX_COMPILER bibtex) + latex_wantit(BIBER_COMPILER biber) + latex_needit(MAKEINDEX_COMPILER makeindex) + latex_wantit(DVIPS_CONVERTER dvips) + latex_wantit(PS2PDF_CONVERTER ps2pdf) + latex_wantit(PDFTOPS_CONVERTER pdftops) + + set(LATEX_COMPILER_FLAGS "-interaction=batchmode -file-line-error" + CACHE STRING "Flags passed to latex.") + set(PDFLATEX_COMPILER_FLAGS ${LATEX_COMPILER_FLAGS} + CACHE STRING "Flags passed to pdflatex.") + set(HTLATEX_COMPILER_TEX4HT_FLAGS "html" + CACHE STRING "Options for the tex4ht.sty and *.4ht style files.") + set(HTLATEX_COMPILER_TEX4HT_POSTPROCESSOR_FLAGS "" + CACHE STRING "Options for the text4ht postprocessor.") + set(HTLATEX_COMPILER_T4HT_POSTPROCESSOR_FLAGS "" + CACHE STRING "Options for the t4ht postprocessor.") + set(HTLATEX_COMPILER_LATEX_FLAGS ${LATEX_COMPILER_FLAGS} + CACHE STRING "Flags passed from htlatex to the LaTeX compiler.") + set(LATEX_SYNCTEX_FLAGS "-synctex=1" + CACHE STRING "latex/pdflatex flags used to create synctex file.") + set(BIBTEX_COMPILER_FLAGS "" + CACHE STRING "Flags passed to bibtex.") + set(BIBER_COMPILER_FLAGS "" + CACHE STRING "Flags passed to biber.") + set(MAKEINDEX_COMPILER_FLAGS "" + CACHE STRING "Flags passed to makeindex.") + set(MAKEGLOSSARIES_COMPILER_FLAGS "" + CACHE STRING "Flags passed to makeglossaries.") + set(MAKENOMENCLATURE_COMPILER_FLAGS "" + CACHE STRING "Flags passed to makenomenclature.") + set(DVIPS_CONVERTER_FLAGS "-Ppdf -G0 -t letter" + CACHE STRING "Flags passed to dvips.") + if(NOT WIN32) + set(PS2PDF_CONVERTER_FLAGS "-dMaxSubsetPct=100 -dCompatibilityLevel=1.3 -dSubsetFonts=true -dEmbedAllFonts=true -dAutoFilterColorImages=false -dAutoFilterGrayImages=false -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode -dMonoImageFilter=/FlateEncode" + CACHE STRING "Flags passed to ps2pdf.") + else() + # Most windows ports of ghostscript utilities use .bat files for ps2pdf + # commands. bat scripts interpret "=" as a special character and separate + # those arguments. To get around this, the ghostscript utilities also + # support using "#" in place of "=". + set(PS2PDF_CONVERTER_FLAGS "-dMaxSubsetPct#100 -dCompatibilityLevel#1.3 -dSubsetFonts#true -dEmbedAllFonts#true -dAutoFilterColorImages#false -dAutoFilterGrayImages#false -dColorImageFilter#/FlateEncode -dGrayImageFilter#/FlateEncode -dMonoImageFilter#/FlateEncode" + CACHE STRING "Flags passed to ps2pdf.") + endif() + set(PDFTOPS_CONVERTER_FLAGS "" + CACHE STRING "Flags passed to pdftops.") + mark_as_advanced( + LATEX_COMPILER_FLAGS + PDFLATEX_COMPILER_FLAGS + HTLATEX_COMPILER_TEX4HT_FLAGS + HTLATEX_COMPILER_TEX4HT_POSTPROCESSOR_FLAGS + HTLATEX_COMPILER_T4HT_POSTPROCESSOR_FLAGS + HTLATEX_COMPILER_LATEX_FLAGS + LATEX_SYNCTEX_FLAGS + BIBTEX_COMPILER_FLAGS + BIBER_COMPILER_FLAGS + MAKEINDEX_COMPILER_FLAGS + MAKEGLOSSARIES_COMPILER_FLAGS + MAKENOMENCLATURE_COMPILER_FLAGS + DVIPS_CONVERTER_FLAGS + PS2PDF_CONVERTER_FLAGS + PDFTOPS_CONVERTER_FLAGS + ) + + # Because it is easier to type, the flags variables are entered as + # space-separated strings much like you would in a shell. However, when + # using a CMake command to execute a program, it works better to hold the + # arguments in semicolon-separated lists (otherwise the whole string will + # be interpreted as a single argument). Use the separate_arguments to + # convert the space-separated strings to semicolon-separated lists. + separate_arguments(LATEX_COMPILER_FLAGS) + separate_arguments(PDFLATEX_COMPILER_FLAGS) + separate_arguments(HTLATEX_COMPILER_LATEX_FLAGS) + separate_arguments(LATEX_SYNCTEX_FLAGS) + separate_arguments(BIBTEX_COMPILER_FLAGS) + separate_arguments(BIBER_COMPILER_FLAGS) + separate_arguments(MAKEINDEX_COMPILER_FLAGS) + separate_arguments(MAKEGLOSSARIES_COMPILER_FLAGS) + separate_arguments(MAKENOMENCLATURE_COMPILER_FLAGS) + separate_arguments(DVIPS_CONVERTER_FLAGS) + separate_arguments(PS2PDF_CONVERTER_FLAGS) + separate_arguments(PDFTOPS_CONVERTER_FLAGS) + + # Not quite done. When you call separate_arguments on a cache variable, + # the result is written to a local variable. That local variable goes + # away when this function returns (which is before any of them are used). + # So, copy these variables with local scope to cache variables with + # global scope. + set(LATEX_COMPILER_ARGS "${LATEX_COMPILER_FLAGS}" CACHE INTERNAL "") + set(PDFLATEX_COMPILER_ARGS "${PDFLATEX_COMPILER_FLAGS}" CACHE INTERNAL "") + set(HTLATEX_COMPILER_ARGS "${HTLATEX_COMPILER_LATEX_FLAGS}" CACHE INTERNAL "") + set(LATEX_SYNCTEX_ARGS "${LATEX_SYNCTEX_FLAGS}" CACHE INTERNAL "") + set(BIBTEX_COMPILER_ARGS "${BIBTEX_COMPILER_FLAGS}" CACHE INTERNAL "") + set(BIBER_COMPILER_ARGS "${BIBER_COMPILER_FLAGS}" CACHE INTERNAL "") + set(MAKEINDEX_COMPILER_ARGS "${MAKEINDEX_COMPILER_FLAGS}" CACHE INTERNAL "") + set(MAKEGLOSSARIES_COMPILER_ARGS "${MAKEGLOSSARIES_COMPILER_FLAGS}" CACHE INTERNAL "") + set(MAKENOMENCLATURE_COMPILER_ARGS "${MAKENOMENCLATURE_COMPILER_FLAGS}" CACHE INTERNAL "") + set(DVIPS_CONVERTER_ARGS "${DVIPS_CONVERTER_FLAGS}" CACHE INTERNAL "") + set(PS2PDF_CONVERTER_ARGS "${PS2PDF_CONVERTER_FLAGS}" CACHE INTERNAL "") + set(PDFTOPS_CONVERTER_ARGS "${PDFTOPS_CONVERTER_FLAGS}" CACHE INTERNAL "") + + find_program(IMAGEMAGICK_CONVERT + NAMES magick convert + DOC "The convert program that comes with ImageMagick (available at http://www.imagemagick.org)." + ) + mark_as_advanced(IMAGEMAGICK_CONVERT) + + if(DEFINED ENV{LATEX_DEFAULT_BUILD}) + set(default_build $ENV{LATEX_DEFAULT_BUILD}) + else() + set(default_build pdf) + endif() + + set(LATEX_DEFAULT_BUILD "${default_build}" CACHE STRING + "Choose the default type of LaTeX build. Valid options are pdf, dvi, ps, safepdf, html" + ) + set_property(CACHE LATEX_DEFAULT_BUILD + PROPERTY STRINGS pdf dvi ps safepdf html + ) + + option(LATEX_USE_SYNCTEX + "If on, have LaTeX generate a synctex file, which WYSIWYG editors can use to correlate output files like dvi and pdf with the lines of LaTeX source that generates them. In addition to adding the LATEX_SYNCTEX_FLAGS to the command line, this option also adds build commands that \"corrects\" the resulting synctex file to point to the original LaTeX files rather than those generated by UseLATEX.cmake." + OFF + ) + + option(LATEX_SMALL_IMAGES + "If on, the raster images will be converted to 1/6 the original size. This is because papers usually require 600 dpi images whereas most monitors only require at most 96 dpi. Thus, smaller images make smaller files for web distribution and can make it faster to read dvi files." + OFF) + if(LATEX_SMALL_IMAGES) + set(LATEX_RASTER_SCALE 16 PARENT_SCOPE) + set(LATEX_OPPOSITE_RASTER_SCALE 100 PARENT_SCOPE) + else() + set(LATEX_RASTER_SCALE 100 PARENT_SCOPE) + set(LATEX_OPPOSITE_RASTER_SCALE 16 PARENT_SCOPE) + endif() + + # Just holds extensions for known image types. They should all be lower case. + # For historical reasons, these are all declared in the global scope. + set(LATEX_DVI_VECTOR_IMAGE_EXTENSIONS .eps CACHE INTERNAL "") + set(LATEX_DVI_RASTER_IMAGE_EXTENSIONS CACHE INTERNAL "") + set(LATEX_DVI_IMAGE_EXTENSIONS + ${LATEX_DVI_VECTOR_IMAGE_EXTENSIONS} + ${LATEX_DVI_RASTER_IMAGE_EXTENSIONS} + CACHE INTERNAL "" + ) + + set(LATEX_PDF_VECTOR_IMAGE_EXTENSIONS .pdf CACHE INTERNAL "") + set(LATEX_PDF_RASTER_IMAGE_EXTENSIONS .jpeg .jpg .png CACHE INTERNAL "") + set(LATEX_PDF_IMAGE_EXTENSIONS + ${LATEX_PDF_VECTOR_IMAGE_EXTENSIONS} + ${LATEX_PDF_RASTER_IMAGE_EXTENSIONS} + CACHE INTERNAL "" + ) + + set(LATEX_OTHER_VECTOR_IMAGE_EXTENSIONS .ai .dot .svg CACHE INTERNAL "") + set(LATEX_OTHER_RASTER_IMAGE_EXTENSIONS + .bmp .bmp2 .bmp3 .dcm .dcx .ico .gif .pict .ppm .tif .tiff + CACHE INTERNAL "") + set(LATEX_OTHER_IMAGE_EXTENSIONS + ${LATEX_OTHER_VECTOR_IMAGE_EXTENSIONS} + ${LATEX_OTHER_RASTER_IMAGE_EXTENSIONS} + CACHE INTERNAL "" + ) + + set(LATEX_VECTOR_IMAGE_EXTENSIONS + ${LATEX_DVI_VECTOR_IMAGE_EXTENSIONS} + ${LATEX_PDF_VECTOR_IMAGE_EXTENSIONS} + ${LATEX_OTHER_VECTOR_IMAGE_EXTENSIONS} + CACHE INTERNAL "" + ) + set(LATEX_RASTER_IMAGE_EXTENSIONS + ${LATEX_DVI_RASTER_IMAGE_EXTENSIONS} + ${LATEX_PDF_RASTER_IMAGE_EXTENSIONS} + ${LATEX_OTHER_RASTER_IMAGE_EXTENSIONS} + CACHE INTERNAL "" + ) + set(LATEX_IMAGE_EXTENSIONS + ${LATEX_DVI_IMAGE_EXTENSIONS} + ${LATEX_PDF_IMAGE_EXTENSIONS} + ${LATEX_OTHER_IMAGE_EXTENSIONS} + CACHE INTERNAL "" + ) +endfunction(latex_setup_variables) + +function(latex_setup_targets) + if(NOT TARGET pdf) + add_custom_target(pdf) + endif() + if(NOT TARGET dvi) + add_custom_target(dvi) + endif() + if(NOT TARGET ps) + add_custom_target(ps) + endif() + if(NOT TARGET safepdf) + add_custom_target(safepdf) + endif() + if(NOT TARGET html) + add_custom_target(html) + endif() + if(NOT TARGET auxclean) + add_custom_target(auxclean) + endif() +endfunction(latex_setup_targets) + +function(latex_get_output_path var) + set(latex_output_path) + if(LATEX_OUTPUT_PATH) + get_filename_component( + LATEX_OUTPUT_PATH_FULL "${LATEX_OUTPUT_PATH}" ABSOLUTE + ) + if("${LATEX_OUTPUT_PATH_FULL}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") + message(SEND_ERROR "You cannot set LATEX_OUTPUT_PATH to the same directory that contains LaTeX input files.") + else() + set(latex_output_path "${LATEX_OUTPUT_PATH_FULL}") + endif() + else() + if("${CMAKE_CURRENT_BINARY_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") + message(SEND_ERROR "LaTeX files must be built out of source or you must set LATEX_OUTPUT_PATH.") + else() + set(latex_output_path "${CMAKE_CURRENT_BINARY_DIR}") + endif() + endif() + set(${var} ${latex_output_path} PARENT_SCOPE) +endfunction(latex_get_output_path) + +function(latex_add_convert_command + output_path + input_path + output_extension + input_extension + flags + ) + set(require_imagemagick_convert TRUE) + set(convert_flags "") + if(${input_extension} STREQUAL ".eps" AND ${output_extension} STREQUAL ".pdf") + # ImageMagick has broken eps to pdf conversion + # use ps2pdf instead + if(PS2PDF_CONVERTER) + set(require_imagemagick_convert FALSE) + set(converter ${PS2PDF_CONVERTER}) + set(convert_flags -dEPSCrop ${PS2PDF_CONVERTER_ARGS}) + else() + message(SEND_ERROR "Using postscript files with pdflatex requires ps2pdf for conversion.") + endif() + elseif(${input_extension} STREQUAL ".pdf" AND ${output_extension} STREQUAL ".eps") + # ImageMagick can also be sketchy on pdf to eps conversion. Not good with + # color spaces and tends to unnecessarily rasterize. + # use pdftops instead + if(PDFTOPS_CONVERTER) + set(require_imagemagick_convert FALSE) + set(converter ${PDFTOPS_CONVERTER}) + set(convert_flags -eps ${PDFTOPS_CONVERTER_ARGS}) + else() + message(STATUS "Consider getting pdftops from Poppler to convert PDF images to EPS images.") + set(convert_flags ${flags}) + endif() + else() + set(convert_flags ${flags}) + endif() + + if(require_imagemagick_convert) + if(IMAGEMAGICK_CONVERT) + string(TOLOWER ${IMAGEMAGICK_CONVERT} IMAGEMAGICK_CONVERT_LOWERCASE) + if(${IMAGEMAGICK_CONVERT_LOWERCASE} MATCHES "system32[/\\\\]convert\\.exe") + message(SEND_ERROR "IMAGEMAGICK_CONVERT set to Window's convert.exe for changing file systems rather than ImageMagick's convert for changing image formats. Please make sure ImageMagick is installed (available at http://www.imagemagick.org). If you have a recent version of ImageMagick (7.0 or higher), use the magick program instead of convert for IMAGEMAGICK_CONVERT.") + else() + set(converter ${IMAGEMAGICK_CONVERT}) + # ImageMagick requires a special order of arguments where resize and + # arguments of that nature must be placed after the input image path. + add_custom_command(OUTPUT ${output_path} + COMMAND ${converter} + ARGS ${input_path} ${convert_flags} ${output_path} + DEPENDS ${input_path} + ) + endif() + else() + message(SEND_ERROR "Could not find convert program. Please download ImageMagick from http://www.imagemagick.org and install.") + endif() + else() # Not ImageMagick convert + add_custom_command(OUTPUT ${output_path} + COMMAND ${converter} + ARGS ${convert_flags} ${input_path} ${output_path} + DEPENDS ${input_path} + ) + endif() +endfunction(latex_add_convert_command) + +# Makes custom commands to convert a file to a particular type. +function(latex_convert_image + output_files_var + input_file + output_extension + convert_flags + output_extensions + other_files + ) + set(output_file_list) + set(input_dir ${CMAKE_CURRENT_SOURCE_DIR}) + latex_get_output_path(output_dir) + + latex_get_filename_component(extension "${input_file}" EXT) + + # Check input filename for potential problems with LaTeX. + latex_get_filename_component(name "${input_file}" NAME_WE) + set(suggested_name "${name}") + if(suggested_name MATCHES ".*\\..*") + string(REPLACE "." "-" suggested_name "${suggested_name}") + endif() + if(suggested_name MATCHES ".* .*") + string(REPLACE " " "-" suggested_name "${suggested_name}") + endif() + if(NOT suggested_name STREQUAL name) + message(WARNING "Some LaTeX distributions have problems with image file names with multiple extensions or spaces. Consider changing ${name}${extension} to something like ${suggested_name}${extension}.") + endif() + + string(REGEX REPLACE "\\.[^.]*\$" ${output_extension} output_file + "${input_file}") + + latex_list_contains(is_type ${extension} ${output_extensions}) + if(is_type) + if(convert_flags) + latex_add_convert_command(${output_dir}/${output_file} + ${input_dir}/${input_file} ${output_extension} ${extension} + "${convert_flags}") + set(output_file_list ${output_dir}/${output_file}) + else() + # As a shortcut, we can just copy the file. + add_custom_command(OUTPUT ${output_dir}/${input_file} + COMMAND ${CMAKE_COMMAND} + ARGS -E copy ${input_dir}/${input_file} ${output_dir}/${input_file} + DEPENDS ${input_dir}/${input_file} + ) + set(output_file_list ${output_dir}/${input_file}) + endif() + else() + set(do_convert TRUE) + # Check to see if there is another input file of the appropriate type. + foreach(valid_extension ${output_extensions}) + string(REGEX REPLACE "\\.[^.]*\$" ${output_extension} try_file + "${input_file}") + latex_list_contains(has_native_file "${try_file}" ${other_files}) + if(has_native_file) + set(do_convert FALSE) + endif() + endforeach(valid_extension) + + # If we still need to convert, do it. + if(do_convert) + latex_add_convert_command(${output_dir}/${output_file} + ${input_dir}/${input_file} ${output_extension} ${extension} + "${convert_flags}") + set(output_file_list ${output_dir}/${output_file}) + endif() + endif() + + set(${output_files_var} ${output_file_list} PARENT_SCOPE) +endfunction(latex_convert_image) + +# Adds custom commands to process the given files for dvi and pdf builds. +# Adds the output files to the given variables (does not replace). +function(latex_process_images dvi_outputs_var pdf_outputs_var) + latex_get_output_path(output_dir) + set(dvi_outputs) + set(pdf_outputs) + foreach(file ${ARGN}) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${file}") + latex_get_filename_component(extension "${file}" EXT) + set(convert_flags) + + # Check to see if we need to downsample the image. + latex_list_contains(is_raster "${extension}" + ${LATEX_RASTER_IMAGE_EXTENSIONS}) + if(LATEX_SMALL_IMAGES) + if(is_raster) + set(convert_flags -resize ${LATEX_RASTER_SCALE}%) + endif() + endif() + + # Make sure the output directory exists. + latex_get_filename_component(path "${output_dir}/${file}" PATH) + make_directory("${path}") + + latex_convert_image(output_files "${file}" .pdf "${convert_flags}" + "${LATEX_PDF_IMAGE_EXTENSIONS}" "${ARGN}") + list(APPEND pdf_outputs ${output_files}) + else() + message(WARNING "Could not find file ${CMAKE_CURRENT_SOURCE_DIR}/${file}. Are you sure you gave relative paths to IMAGES?") + endif() + endforeach(file) + + set(${dvi_outputs_var} ${dvi_outputs} PARENT_SCOPE) + set(${pdf_outputs_var} ${pdf_outputs} PARENT_SCOPE) +endfunction(latex_process_images) + +function(latex_copy_globbed_files pattern dest) + file(GLOB file_list ${pattern}) + foreach(in_file ${file_list}) + latex_get_filename_component(out_file ${in_file} NAME) + configure_file(${in_file} ${dest}/${out_file} COPYONLY) + endforeach(in_file) +endfunction(latex_copy_globbed_files) + +function(latex_copy_input_file file) + latex_get_output_path(output_dir) + + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file}) + latex_get_filename_component(path ${file} PATH) + file(MAKE_DIRECTORY ${output_dir}/${path}) + + latex_list_contains(use_config ${file} ${LATEX_CONFIGURE}) + if(use_config) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${file} + ${output_dir}/${file} + @ONLY + ) + add_custom_command(OUTPUT ${output_dir}/${file} + COMMAND ${CMAKE_COMMAND} + ARGS ${CMAKE_BINARY_DIR} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file} + ) + else() + add_custom_command(OUTPUT ${output_dir}/${file} + COMMAND ${CMAKE_COMMAND} + ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${file} ${output_dir}/${file} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file} + ) + endif() + else() + if(EXISTS ${output_dir}/${file}) + # Special case: output exists but input does not. Assume that it was + # created elsewhere and skip the input file copy. + else() + message("Could not find input file ${CMAKE_CURRENT_SOURCE_DIR}/${file}") + endif() + endif() +endfunction(latex_copy_input_file) + +############################################################################# +# Commands provided by the UseLATEX.cmake "package" +############################################################################# + +function(latex_usage command message) + message(SEND_ERROR + "${message}\n Usage: ${command}(\n [BIBFILES ...]\n [INPUTS ...]\n [IMAGE_DIRS ...]\n [IMAGES \n [CONFIGURE ...]\n [DEPENDS ...]\n [MULTIBIB_NEWCITES] \n [USE_BIBLATEX] [USE_INDEX] [USE_GLOSSARY] [USE_NOMENCL]\n [FORCE_PDF] [FORCE_DVI] [FORCE_HTML]\n [TARGET_NAME] \n [EXCLUDE_FROM_ALL]\n [EXCLUDE_FROM_DEFAULTS])" + ) +endfunction(latex_usage command message) + +# Parses arguments to add_latex_document and ADD_LATEX_TARGETS and sets the +# variables LATEX_TARGET, LATEX_IMAGE_DIR, LATEX_BIBFILES, LATEX_DEPENDS, and +# LATEX_INPUTS. +function(parse_add_latex_arguments command latex_main_input) + set(options + USE_BIBLATEX + USE_INDEX + USE_GLOSSARY + USE_NOMENCL + FORCE_PDF + FORCE_DVI + FORCE_HTML + EXCLUDE_FROM_ALL + EXCLUDE_FROM_DEFAULTS + # Deprecated options + USE_GLOSSARIES + DEFAULT_PDF + DEFAULT_SAFEPDF + DEFAULT_PS + NO_DEFAULT + MANGLE_TARGET_NAMES + ) + set(oneValueArgs + TARGET_NAME + ) + set(multiValueArgs + BIBFILES + MULTIBIB_NEWCITES + INPUTS + IMAGE_DIRS + IMAGES + CONFIGURE + DEPENDS + INDEX_NAMES + ) + cmake_parse_arguments( + LATEX "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # Handle invalid and deprecated arguments + if(LATEX_UNPARSED_ARGUMENTS) + latex_usage(${command} "Invalid or deprecated arguments: ${LATEX_UNPARSED_ARGUMENTS}") + endif() + if(LATEX_USE_GLOSSARIES) + latex_usage(${command} "USE_GLOSSARIES option removed in version 1.6.1. Use USE_GLOSSARY instead.") + endif() + if(LATEX_DEFAULT_PDF) + latex_usage(${command} "DEFAULT_PDF option removed in version 2.0. Use FORCE_PDF option or LATEX_DEFAULT_BUILD CMake variable instead.") + endif() + if(LATEX_DEFAULT_SAFEPDF) + latex_usage(${command} "DEFAULT_SAFEPDF option removed in version 2.0. Use LATEX_DEFAULT_BUILD CMake variable instead.") + endif() + if(LATEX_DEFAULT_DVI) + latex_usage(${command} "DEFAULT_DVI option removed in version 2.0. Use FORCE_DVI option or LATEX_DEFAULT_BUILD CMake variable instead.") + endif() + if(LATEX_NO_DEFAULT) + latex_usage(${command} "NO_DEFAULT option removed in version 2.0. Use EXCLUDE_FROM_ALL instead.") + endif() + if(LATEX_MANGLE_TARGET_NAMES) + latex_usage(${command} "MANGLE_TARGET_NAMES option removed in version 2.0. All LaTeX targets use mangled names now.") + endif() + + # Capture the first argument, which is the main LaTeX input. + latex_get_filename_component(latex_target ${latex_main_input} NAME_WE) + set(LATEX_MAIN_INPUT ${latex_main_input} PARENT_SCOPE) + set(LATEX_TARGET ${latex_target} PARENT_SCOPE) + + # Propagate the result variables to the caller + foreach(arg_name ${options} ${oneValueArgs} ${multiValueArgs}) + set(var_name LATEX_${arg_name}) + set(${var_name} ${${var_name}} PARENT_SCOPE) + endforeach(arg_name) +endfunction(parse_add_latex_arguments) + +function(add_latex_targets_internal) + latex_get_output_path(output_dir) + + if(LATEX_USE_SYNCTEX) + set(synctex_flags ${LATEX_SYNCTEX_ARGS}) + else() + set(synctex_flags) + endif() + + # The commands to run LaTeX. They are repeated multiple times. + set(latex_build_command + ${LATEX_COMPILER} ${LATEX_COMPILER_ARGS} ${synctex_flags} ${LATEX_MAIN_INPUT} + ) + if(LATEX_COMPILER_ARGS MATCHES ".*batchmode.*") + # Wrap command in script that dumps the log file on error. This makes sure + # errors can be seen. + set(latex_build_command + ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=execute_latex + -D LATEX_TARGET=${LATEX_TARGET} + -D LATEX_WORKING_DIRECTORY="${output_dir}" + -D LATEX_FULL_COMMAND="${latex_build_command}" + -D LATEX_OUTPUT_FILE="${LATEX_TARGET}.dvi" + -P "${LATEX_USE_LATEX_LOCATION}" + ) + endif() + set(pdflatex_build_command + ${PDFLATEX_COMPILER} ${PDFLATEX_COMPILER_ARGS} ${synctex_flags} ${LATEX_MAIN_INPUT} + ) + if(PDFLATEX_COMPILER_ARGS MATCHES ".*batchmode.*") + # Wrap command in script that dumps the log file on error. This makes sure + # errors can be seen. + set(pdflatex_build_command + ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=execute_latex + -D LATEX_TARGET=${LATEX_TARGET} + -D LATEX_WORKING_DIRECTORY="${output_dir}" + -D LATEX_FULL_COMMAND="${pdflatex_build_command}" + -D LATEX_OUTPUT_FILE="${LATEX_TARGET}.pdf" + -P "${LATEX_USE_LATEX_LOCATION}" + ) + endif() + + if(NOT LATEX_TARGET_NAME) + # Use the main filename (minus the .tex) as the target name. Remove any + # spaces since CMake cannot have spaces in its target names. + string(REPLACE " " "_" LATEX_TARGET_NAME ${LATEX_TARGET}) + endif() + + # Some LaTeX commands may need to be modified (or may not work) if the main + # tex file is in a subdirectory. Make a flag for that. + get_filename_component(LATEX_MAIN_INPUT_SUBDIR ${LATEX_MAIN_INPUT} DIRECTORY) + + # Set up target names. + set(dvi_target ${LATEX_TARGET_NAME}_dvi) + set(pdf_target ${LATEX_TARGET_NAME}_pdf) + set(ps_target ${LATEX_TARGET_NAME}_ps) + set(safepdf_target ${LATEX_TARGET_NAME}_safepdf) + set(html_target ${LATEX_TARGET_NAME}_html) + set(auxclean_target ${LATEX_TARGET_NAME}_auxclean) + + # Probably not all of these will be generated, but they could be. + # Note that the aux file is added later. + set(auxiliary_clean_files + ${output_dir}/${LATEX_TARGET}.aux + ${output_dir}/${LATEX_TARGET}.bbl + ${output_dir}/${LATEX_TARGET}.blg + ${output_dir}/${LATEX_TARGET}-blx.bib + ${output_dir}/${LATEX_TARGET}.glg + ${output_dir}/${LATEX_TARGET}.glo + ${output_dir}/${LATEX_TARGET}.gls + ${output_dir}/${LATEX_TARGET}.idx + ${output_dir}/${LATEX_TARGET}.ilg + ${output_dir}/${LATEX_TARGET}.ind + ${output_dir}/${LATEX_TARGET}.ist + ${output_dir}/${LATEX_TARGET}.log + ${output_dir}/${LATEX_TARGET}.out + ${output_dir}/${LATEX_TARGET}.toc + ${output_dir}/${LATEX_TARGET}.lof + ${output_dir}/${LATEX_TARGET}.xdy + ${output_dir}/${LATEX_TARGET}.synctex.gz + ${output_dir}/${LATEX_TARGET}.synctex.bak.gz + ${output_dir}/${LATEX_TARGET}.dvi + ${output_dir}/${LATEX_TARGET}.ps + ${output_dir}/${LATEX_TARGET}.pdf + ) + + set(image_list ${LATEX_IMAGES}) + + # For each directory in LATEX_IMAGE_DIRS, glob all the image files and + # place them in LATEX_IMAGES. + foreach(dir ${LATEX_IMAGE_DIRS}) + if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${dir}) + message(WARNING "Image directory ${CMAKE_CURRENT_SOURCE_DIR}/${dir} does not exist. Are you sure you gave relative directories to IMAGE_DIRS?") + endif() + foreach(extension ${LATEX_IMAGE_EXTENSIONS}) + file(GLOB files ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*${extension}) + foreach(file ${files}) + latex_get_filename_component(filename ${file} NAME) + list(APPEND image_list ${dir}/${filename}) + endforeach(file) + endforeach(extension) + endforeach(dir) + + latex_process_images(dvi_images pdf_images ${image_list}) + + set(make_dvi_command + ${CMAKE_COMMAND} -E chdir ${output_dir} + ${latex_build_command}) + set(make_pdf_command + ${CMAKE_COMMAND} -E chdir ${output_dir} + ${pdflatex_build_command} + ) + + set(make_dvi_depends ${LATEX_DEPENDS} ${dvi_images}) + set(make_pdf_depends ${LATEX_DEPENDS} ${pdf_images}) + foreach(input ${LATEX_MAIN_INPUT} ${LATEX_INPUTS}) + list(APPEND make_dvi_depends ${output_dir}/${input}) + list(APPEND make_pdf_depends ${output_dir}/${input}) + if(${input} MATCHES "\\.tex$") + # Dependent .tex files might have their own .aux files created. Make + # sure these get cleaned as well. This might replicate the cleaning + # of the main .aux file, which is OK. + string(REGEX REPLACE "\\.tex$" "" input_we ${input}) + list(APPEND auxiliary_clean_files + ${output_dir}/${input_we}.aux + ${output_dir}/${input}.aux + ) + endif() + endforeach(input) + + set(all_latex_sources ${LATEX_MAIN_INPUT} ${LATEX_INPUTS} ${image_list}) + + if(LATEX_USE_GLOSSARY) + foreach(dummy 0 1) # Repeat these commands twice. + set(make_dvi_command ${make_dvi_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=makeglossaries + -D LATEX_TARGET=${LATEX_TARGET} + -D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER} + -D XINDY_COMPILER=${XINDY_COMPILER} + -D MAKEGLOSSARIES_COMPILER_ARGS=${MAKEGLOSSARIES_COMPILER_ARGS} + -P ${LATEX_USE_LATEX_LOCATION} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${latex_build_command} + ) + set(make_pdf_command ${make_pdf_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=makeglossaries + -D LATEX_TARGET=${LATEX_TARGET} + -D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER} + -D XINDY_COMPILER=${XINDY_COMPILER} + -D MAKEGLOSSARIES_COMPILER_ARGS=${MAKEGLOSSARIES_COMPILER_ARGS} + -P ${LATEX_USE_LATEX_LOCATION} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${pdflatex_build_command} + ) + endforeach(dummy) + endif() + + if(LATEX_USE_NOMENCL) + foreach(dummy 0 1) # Repeat these commands twice. + set(make_dvi_command ${make_dvi_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=makenomenclature + -D LATEX_TARGET=${LATEX_TARGET} + -D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER} + -D MAKENOMENCLATURE_COMPILER_ARGS=${MAKENOMENCLATURE_COMPILER_ARGS} + -P ${LATEX_USE_LATEX_LOCATION} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${latex_build_command} + ) + set(make_pdf_command ${make_pdf_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=makenomenclature + -D LATEX_TARGET=${LATEX_TARGET} + -D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER} + -D MAKENOMENCLATURE_COMPILER_ARGS=${MAKENOMENCLATURE_COMPILER_ARGS} + -P ${LATEX_USE_LATEX_LOCATION} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${pdflatex_build_command} + ) + endforeach(dummy) + endif() + + if(LATEX_BIBFILES) + if(LATEX_USE_BIBLATEX) + if(NOT BIBER_COMPILER) + message(SEND_ERROR "I need the biber command.") + endif() + set(bib_compiler ${BIBER_COMPILER}) + set(bib_compiler_flags ${BIBER_COMPILER_ARGS}) + else() + set(bib_compiler ${BIBTEX_COMPILER}) + set(bib_compiler_flags ${BIBTEX_COMPILER_ARGS}) + endif() + if(LATEX_MULTIBIB_NEWCITES) + foreach (multibib_auxfile ${LATEX_MULTIBIB_NEWCITES}) + latex_get_filename_component(multibib_target ${multibib_auxfile} NAME_WE) + set(make_dvi_command ${make_dvi_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${bib_compiler} ${bib_compiler_flags} ${multibib_target}) + set(make_pdf_command ${make_pdf_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${bib_compiler} ${bib_compiler_flags} ${multibib_target}) + set(auxiliary_clean_files ${auxiliary_clean_files} + ${output_dir}/${multibib_target}.aux) + endforeach (multibib_auxfile ${LATEX_MULTIBIB_NEWCITES}) + else() + set(make_dvi_command ${make_dvi_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${bib_compiler} ${bib_compiler_flags} ${LATEX_TARGET}) + set(make_pdf_command ${make_pdf_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${bib_compiler} ${bib_compiler_flags} ${LATEX_TARGET}) + endif() + + foreach (bibfile ${LATEX_BIBFILES}) + list(APPEND make_dvi_depends ${output_dir}/${bibfile}) + list(APPEND make_pdf_depends ${output_dir}/${bibfile}) + endforeach (bibfile ${LATEX_BIBFILES}) + else() + if(LATEX_MULTIBIB_NEWCITES) + message(WARNING "MULTIBIB_NEWCITES has no effect without BIBFILES option.") + endif() + endif() + + if(LATEX_USE_INDEX) + if(LATEX_INDEX_NAMES) + set(INDEX_NAMES ${LATEX_INDEX_NAMES}) + else() + set(INDEX_NAMES ${LATEX_TARGET}) + endif() + foreach(idx_name ${INDEX_NAMES}) + set(make_dvi_command ${make_dvi_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${latex_build_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${MAKEINDEX_COMPILER} ${MAKEINDEX_COMPILER_ARGS} ${idx_name}.idx) + set(make_pdf_command ${make_pdf_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${pdflatex_build_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${MAKEINDEX_COMPILER} ${MAKEINDEX_COMPILER_ARGS} ${idx_name}.idx) + set(auxiliary_clean_files ${auxiliary_clean_files} + ${output_dir}/${idx_name}.idx + ${output_dir}/${idx_name}.ilg + ${output_dir}/${idx_name}.ind) + endforeach() + else() + if(LATEX_INDEX_NAMES) + message(WARNING "INDEX_NAMES has no effect without USE_INDEX option.") + endif() + endif() + + set(make_dvi_command ${make_dvi_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${latex_build_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${latex_build_command}) + set(make_pdf_command ${make_pdf_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${pdflatex_build_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${pdflatex_build_command}) + + # Need to run one more time to remove biblatex' warning + # about page breaks that have changed. + if(LATEX_USE_BIBLATEX) + set(make_dvi_command ${make_dvi_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${latex_build_command}) + set(make_pdf_command ${make_pdf_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${pdflatex_build_command}) + endif() + + if(LATEX_USE_SYNCTEX) + if(NOT GZIP) + message(SEND_ERROR "UseLATEX.cmake: USE_SYNTEX option requires gzip program. Set GZIP variable.") + endif() + set(make_dvi_command ${make_dvi_command} + COMMAND ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=correct_synctex + -D LATEX_TARGET=${LATEX_TARGET} + -D GZIP=${GZIP} + -D "LATEX_SOURCE_DIRECTORY=${CMAKE_CURRENT_SOURCE_DIR}" + -D "LATEX_BINARY_DIRECTORY=${output_dir}" + -P ${LATEX_USE_LATEX_LOCATION} + ) + set(make_pdf_command ${make_pdf_command} + COMMAND ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=correct_synctex + -D LATEX_TARGET=${LATEX_TARGET} + -D GZIP=${GZIP} + -D "LATEX_SOURCE_DIRECTORY=${CMAKE_CURRENT_SOURCE_DIR}" + -D "LATEX_BINARY_DIRECTORY=${output_dir}" + -P ${LATEX_USE_LATEX_LOCATION} + ) + endif() + + # Check LaTeX output for important warnings at end of build + set(make_dvi_command ${make_dvi_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=check_important_warnings + -D LATEX_TARGET=${LATEX_TARGET} + -P ${LATEX_USE_LATEX_LOCATION} + ) + set(make_pdf_command ${make_pdf_command} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${CMAKE_COMMAND} + -D LATEX_BUILD_COMMAND=check_important_warnings + -D LATEX_TARGET=${LATEX_TARGET} + -P ${LATEX_USE_LATEX_LOCATION} + ) + + # Capture the default build. + string(TOLOWER "${LATEX_DEFAULT_BUILD}" default_build) + + if((NOT LATEX_FORCE_PDF) AND (NOT LATEX_FORCE_DVI) AND (NOT LATEX_FORCE_HTML)) + set(no_force TRUE) + endif() + + # Add commands and targets for building pdf outputs (with pdflatex). + if(LATEX_FORCE_PDF OR no_force) + if(LATEX_FORCE_PDF) + set(default_build pdf) + endif() + + if(PDFLATEX_COMPILER) + add_custom_command(OUTPUT ${output_dir}/${LATEX_TARGET}.pdf + COMMAND ${make_pdf_command} + DEPENDS ${make_pdf_depends} + ) + add_custom_target(${pdf_target} + DEPENDS ${output_dir}/${LATEX_TARGET}.pdf + SOURCES ${all_latex_sources} + ) + if(NOT LATEX_EXCLUDE_FROM_DEFAULTS) + add_dependencies(pdf ${pdf_target}) + endif() + endif() + endif() + + # Add commands and targets for building dvi outputs. + if(LATEX_FORCE_DVI OR LATEX_FORCE_HTML OR no_force) + if(LATEX_FORCE_DVI) + if((NOT default_build STREQUAL dvi) AND + (NOT default_build STREQUAL ps) AND + (NOT default_build STREQUAL safepdf)) + set(default_build dvi) + endif() + endif() + + add_custom_command(OUTPUT ${output_dir}/${LATEX_TARGET}.dvi + COMMAND ${make_dvi_command} + DEPENDS ${make_dvi_depends} + ) + add_custom_target(${dvi_target} + DEPENDS ${output_dir}/${LATEX_TARGET}.dvi + SOURCES ${all_latex_sources} + ) + if(NOT LATEX_EXCLUDE_FROM_DEFAULTS) + add_dependencies(dvi ${dvi_target}) + endif() + + if(DVIPS_CONVERTER) + add_custom_command(OUTPUT ${output_dir}/${LATEX_TARGET}.ps + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${DVIPS_CONVERTER} ${DVIPS_CONVERTER_ARGS} -o ${LATEX_TARGET}.ps ${LATEX_TARGET}.dvi + DEPENDS ${output_dir}/${LATEX_TARGET}.dvi) + add_custom_target(${ps_target} + DEPENDS ${output_dir}/${LATEX_TARGET}.ps + SOURCES ${all_latex_sources} + ) + if(NOT LATEX_EXCLUDE_FROM_DEFAULTS) + add_dependencies(ps ${ps_target}) + endif() + if(PS2PDF_CONVERTER) + # Since both the pdf and safepdf targets have the same output, we + # cannot properly do the dependencies for both. When selecting safepdf, + # simply force a recompile every time. + add_custom_target(${safepdf_target} + ${CMAKE_COMMAND} -E chdir ${output_dir} + ${PS2PDF_CONVERTER} ${PS2PDF_CONVERTER_ARGS} ${LATEX_TARGET}.ps ${LATEX_TARGET}.pdf + DEPENDS ${ps_target} + ) + if(NOT LATEX_EXCLUDE_FROM_DEFAULTS) + add_dependencies(safepdf ${safepdf_target}) + endif() + endif() + endif() + endif() + + if(LATEX_FORCE_HTML OR no_force) + if (LATEX_FORCE_HTML) + set(default_build html) + endif() + + if(HTLATEX_COMPILER AND LATEX_MAIN_INPUT_SUBDIR) + message(STATUS + "Disabling HTML build for ${LATEX_TARGET_NAME}.tex because the main file is in subdirectory ${LATEX_MAIN_INPUT_SUBDIR}" + ) + # The code below to run HTML assumes that LATEX_TARGET.tex is in the + # current directory. I have tried to specify that LATEX_TARGET.tex is + # in a subdirectory. That makes the build targets correct, but the + # HTML build still fails (at least for htlatex) because files are not + # generated where expected. I am getting around the problem by simply + # disabling HTML in this case. If someone really cares, they can fix + # this, but make sure it runs on many platforms and build programs. + elseif(HTLATEX_COMPILER) + # htlatex places the output in a different location + set(HTML_OUTPUT "${output_dir}/${LATEX_TARGET}.html") + add_custom_command(OUTPUT ${HTML_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir} + ${HTLATEX_COMPILER} ${LATEX_MAIN_INPUT} + "${HTLATEX_COMPILER_TEX4HT_FLAGS}" + "${HTLATEX_COMPILER_TEX4HT_POSTPROCESSOR_FLAGS}" + "${HTLATEX_COMPILER_T4HT_POSTPROCESSOR_FLAGS}" + ${HTLATEX_COMPILER_ARGS} + DEPENDS + ${output_dir}/${LATEX_TARGET}.tex + ${output_dir}/${LATEX_TARGET}.dvi + VERBATIM + ) + add_custom_target(${html_target} + DEPENDS ${HTML_OUTPUT} ${dvi_target} + SOURCES ${all_latex_sources} + ) + if(NOT LATEX_EXCLUDE_FROM_DEFAULTS) + add_dependencies(html ${html_target}) + endif() + endif() + endif() + + # Set default targets. + if("${default_build}" STREQUAL "pdf") + add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${pdf_target}) + elseif("${default_build}" STREQUAL "dvi") + add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${dvi_target}) + elseif("${default_build}" STREQUAL "ps") + add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${ps_target}) + elseif("${default_build}" STREQUAL "safepdf") + add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${safepdf_target}) + elseif("${default_build}" STREQUAL "html") + add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${html_target}) + else() + message(SEND_ERROR "LATEX_DEFAULT_BUILD set to an invalid value. See the documentation for that variable.") + endif() + + if(NOT LATEX_EXCLUDE_FROM_ALL) + add_custom_target(_${LATEX_TARGET_NAME} ALL DEPENDS ${LATEX_TARGET_NAME}) + endif() + + set_directory_properties(. + ADDITIONAL_MAKE_CLEAN_FILES "${auxiliary_clean_files}" + ) + + add_custom_target(${auxclean_target} + COMMENT "Cleaning auxiliary LaTeX files." + COMMAND ${CMAKE_COMMAND} -E remove ${auxiliary_clean_files} + ) + add_dependencies(auxclean ${auxclean_target}) +endfunction(add_latex_targets_internal) + +function(add_latex_targets latex_main_input) + latex_get_output_path(output_dir) + parse_add_latex_arguments(ADD_LATEX_TARGETS ${latex_main_input} ${ARGN}) + + add_latex_targets_internal() +endfunction(add_latex_targets) + +function(add_latex_document latex_main_input) + latex_get_output_path(output_dir) + if(output_dir) + parse_add_latex_arguments(add_latex_document ${latex_main_input} ${ARGN}) + + latex_copy_input_file(${LATEX_MAIN_INPUT}) + + foreach (bib_file ${LATEX_BIBFILES}) + latex_copy_input_file(${bib_file}) + endforeach (bib_file) + + foreach (input ${LATEX_INPUTS}) + latex_copy_input_file(${input}) + endforeach(input) + + latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.cls ${output_dir}) + latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.bst ${output_dir}) + latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.clo ${output_dir}) + latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.sty ${output_dir}) + latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.ist ${output_dir}) + latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.fd ${output_dir}) + + add_latex_targets_internal() + endif() +endfunction(add_latex_document) + +############################################################################# +# Actually do stuff +############################################################################# + +if(LATEX_BUILD_COMMAND) + set(command_handled) + + if("${LATEX_BUILD_COMMAND}" STREQUAL execute_latex) + latex_execute_latex() + set(command_handled TRUE) + endif() + + if("${LATEX_BUILD_COMMAND}" STREQUAL makeglossaries) + latex_makeglossaries() + set(command_handled TRUE) + endif() + + if("${LATEX_BUILD_COMMAND}" STREQUAL makenomenclature) + latex_makenomenclature() + set(command_handled TRUE) + endif() + + if("${LATEX_BUILD_COMMAND}" STREQUAL correct_synctex) + latex_correct_synctex() + set(command_handled TRUE) + endif() + + if("${LATEX_BUILD_COMMAND}" STREQUAL check_important_warnings) + latex_check_important_warnings() + set(command_handled TRUE) + endif() + + if(NOT command_handled) + message(SEND_ERROR "Unknown command: ${LATEX_BUILD_COMMAND}") + endif() + +else() + # Must be part of the actual configure (included from CMakeLists.txt). + latex_setup_variables() + latex_setup_targets() +endif() diff -Nru actor-framework-0.13.2/doc/cmake/variables.tex.in actor-framework-0.16.3/doc/cmake/variables.tex.in --- actor-framework-0.13.2/doc/cmake/variables.tex.in 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/cmake/variables.tex.in 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,2 @@ +\newcommand{\cafrelease}{@CAF_RELEASE@} +\newcommand{\cafsha}{@CAF_SHA@} diff -Nru actor-framework-0.13.2/doc/CMakeLists.txt actor-framework-0.16.3/doc/CMakeLists.txt --- actor-framework-0.13.2/doc/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/CMakeLists.txt 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,131 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(doc NONE) + +add_custom_target(doc) + +# -- list all .tex source files ------------------------------------------------ + +set(sources + tex/Actors.tex + tex/Brokers.tex + tex/CommonPitfalls.tex + tex/ConfiguringActorApplications.tex + tex/Error.tex + tex/FAQ.tex + tex/FirstSteps.tex + tex/GroupCommunication.tex + tex/Introduction.tex + tex/ManagingGroupsOfWorkers.tex + tex/MessageHandlers.tex + tex/MessagePassing.tex + tex/Messages.tex + tex/MigrationGuides.tex + tex/NetworkTransparency.tex + tex/OpenCL.tex + tex/ReferenceCounting.tex + tex/Registry.tex + tex/RemoteSpawn.tex + tex/Scheduler.tex + tex/Streaming.tex + tex/TypeInspection.tex + tex/UsingAout.tex + tex/Utility.tex +) + +# -- process .in files ----------------------------------------------------- + +configure_file("cmake/Doxyfile.in" + "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" + @ONLY) + +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tex") + +configure_file("cmake/variables.tex.in" + "${CMAKE_CURRENT_BINARY_DIR}/tex/variables.tex" + @ONLY) + +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rst") + +configure_file("cmake/conf.py.in" + "${CMAKE_CURRENT_BINARY_DIR}/rst/conf.py" + @ONLY) + +configure_file("cmake/index_footer.rst.in" + "${CMAKE_CURRENT_BINARY_DIR}/rst/index_footer.rst" + @ONLY) + +configure_file("cmake/index_header.rst.in" + "${CMAKE_CURRENT_BINARY_DIR}/rst/index_header.rst" + @ONLY) + +# -- Doxygen setup ------------------------------------------------------------- + +find_package(Doxygen) + +if(NOT DOXYGEN_FOUND) + message(STATUS "Doxygen not found, skip building API documentation.") +else() + message(STATUS "Add optional target: doxygen.") + add_custom_target(doxygen "${DOXYGEN_EXECUTABLE}" + "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + COMMENT "Generating API documentation with Doxygen" + VERBATIM) + add_dependencies(doc doxygen) +endif() + +# -- Pandoc utility macro ------------------------------------------------------ + +macro(generate_rst texfile) + get_filename_component(rstfile_we "${texfile}" NAME_WE) + set(rstfile "${rstfile_we}.rst") + set(bin_texfile "${CMAKE_CURRENT_BINARY_DIR}/${texfile}") + add_custom_target("${rstfile}" + DEPENDS "${bin_texfile}" + COMMAND ${PANDOC_EXECUTABLE} + "--filter=${CMAKE_SOURCE_DIR}/scripts/pandoc-filter.py" + --wrap=none -f latex + -o "${CMAKE_CURRENT_BINARY_DIR}/rst/${rstfile}" + "${bin_texfile}" + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rst") + add_dependencies(rst "${rstfile}") +endmacro() + +# -- LaTeX setup --------------------------------------------------------------- + +if (CAF_BUILD_TEX_MANUAL) + find_package(LATEX) + message(STATUS "Add optional target: manual.") + include("cmake/UseLATEX.cmake") + # enable synctex for convenient editing + set(LATEX_USE_SYNCTEX yes) + # add manual.pdf as target + add_latex_document(tex/manual.tex + INPUTS ${sources} "tex/variables.tex" + IMAGE_DIRS "pdf" + FORCE_PDF + TARGET_NAME manual) + add_dependencies(doc manual) + find_program(PANDOC_EXECUTABLE pandoc) + if(NOT EXISTS ${PANDOC_EXECUTABLE}) + message(STATUS "Pandoc not found, skip generating reFormattedText version of the manual.") + else() + execute_process(COMMAND "python" "-c" + "from pandocfilters import toJSONFilter; print('ok')" + RESULT_VARIABLE has_pandocfilters + OUTPUT_QUIET + ERROR_QUIET) + if(NOT ${has_pandocfilters} EQUAL 0) + message(STATUS "Python with pandocfilters not found, skip generating reFormattedText version of the manual.") + else() + message(STATUS "Add optional target: rst.") + add_custom_target(rst) + add_dependencies(doc rst) + foreach(texfile ${sources}) + generate_rst(${texfile}) + endforeach() + endif() + endif() +endif() + Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/graffle/basp_header.graffle and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/graffle/basp_header.graffle differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/graffle/basp_overview.graffle and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/graffle/basp_overview.graffle differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/graffle/basp_sequence.graffle and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/graffle/basp_sequence.graffle differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/graffle/broker.graffle and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/graffle/broker.graffle differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/graffle/mailbox.graffle and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/graffle/mailbox.graffle differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/graffle/stream classes.graffle and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/graffle/stream classes.graffle differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/pdf/actor_types.pdf and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/pdf/actor_types.pdf differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/pdf/enable_shared_from_this.pdf and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/pdf/enable_shared_from_this.pdf differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/pdf/mailbox_element.pdf and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/pdf/mailbox_element.pdf differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/pdf/make_shared.pdf and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/pdf/make_shared.pdf differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/pdf/refcounting.pdf and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/pdf/refcounting.pdf differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/pdf/shared_ptr.pdf and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/pdf/shared_ptr.pdf differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/pdf/stealing.pdf and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/pdf/stealing.pdf differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/pdf/stream-manager.pdf and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/pdf/stream-manager.pdf differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/pdf/stream.pdf and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/pdf/stream.pdf differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/pdf/stream-roles.pdf and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/pdf/stream-roles.pdf differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/png/announce_proxy_instance.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/png/announce_proxy_instance.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/png/basp_header.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/png/basp_header.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/png/basp_overview.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/png/basp_overview.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/png/basp_sequence.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/png/basp_sequence.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/png/broker.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/png/broker.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/png/client_handshake.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/png/client_handshake.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/png/dispatch_error.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/png/dispatch_error.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/png/dispatch_message.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/png/dispatch_message.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/png/heartbeat.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/png/heartbeat.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/png/kill_proxy_instance.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/png/kill_proxy_instance.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/png/server_handshake.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/png/server_handshake.png differ diff -Nru actor-framework-0.13.2/doc/tex/Actors.tex actor-framework-0.16.3/doc/tex/Actors.tex --- actor-framework-0.13.2/doc/tex/Actors.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/Actors.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,602 @@ +\section{Actors} +\label{actor} + +Actors in CAF are a lightweight abstraction for units of computations. They +are active objects in the sense that they own their state and do not allow +others to access it. The only way to modify the state of an actor is sending +messages to it. + +CAF provides several actor implementations, each covering a particular use +case. The available implementations differ in three characteristics: (1) +dynamically or statically typed, (2) class-based or function-based, and (3) +using asynchronous event handlers or blocking receives. These three +characteristics can be combined freely, with one exception: statically typed +actors are always event-based. For example, an actor can have dynamically typed +messaging, implement a class, and use blocking receives. The common base class +for all user-defined actors is called \lstinline^local_actor^. + +Dynamically typed actors are more familiar to developers coming from Erlang or +Akka. They (usually) enable faster prototyping but require extensive unit +testing. Statically typed actors require more source code but enable the +compiler to verify communication between actors. Since CAF supports both, +developers can freely mix both kinds of actors to get the best of both worlds. +A good rule of thumb is to make use of static type checking for actors that are +visible across multiple translation units. + +Actors that utilize the blocking receive API always require an exclusive thread +of execution. Event-based actors, on the other hand, are usually scheduled +cooperatively and are very lightweight with a memory footprint of only few +hundred bytes. Developers can exclude---detach---event-based actors that +potentially starve others from the cooperative scheduling while spawning it. A +detached actor lives in its own thread of execution. + +\subsection{Environment / Actor Systems} +\label{actor-system} + +All actors live in an \lstinline^actor_system^ representing an actor +environment including scheduler~\see{scheduler}, registry~\see{registry}, and +optional components such as a middleman~\see{middleman}. A single process can +have multiple \lstinline^actor_system^ instances, but this is usually not +recommended (a use case for multiple systems is to strictly separate two or +more sets of actors by running them in different schedulers). For configuration +and fine-tuning options of actor systems see \sref{system-config}. A +distributed CAF application consists of two or more connected actor systems. We +also refer to interconnected \lstinline^actor_system^ instances as a +\emph{distributed actor system}. + +\clearpage +\subsection{Common Actor Base Types} + +The following pseudo-UML depicts the class diagram for actors in CAF. +Irrelevant member functions and classes as well as mixins are omitted for +brevity. Selected individual classes are presented in more detail in the +following sections. + +\singlefig{actor_types}% + {Actor Types in CAF}% + {actor-types} + +\clearpage +\subsubsection{Class \lstinline^local_actor^} + +The class \lstinline^local_actor^ is the root type for all user-defined actors +in CAF. It defines all common operations. However, users of the library +usually do not inherit from this class directly. Proper base classes for +user-defined actors are \lstinline^event_based_actor^ or +\lstinline^blocking_actor^. The following table also includes member function +inherited from \lstinline^monitorable_actor^ and \lstinline^abstract_actor^. + +\begin{center} +\begin{tabular}{ll} + \textbf{Types} & ~ \\ + \hline + \lstinline^mailbox_type^ & A concurrent, many-writers-single-reader queue type. \\ + \hline + ~ & ~ \\ \textbf{Constructors} & ~ \\ + \hline + \lstinline^(actor_config&)^ & Constructs the actor using a config. \\ + \hline + ~ & ~ \\ \textbf{Observers} & ~ \\ + \hline + \lstinline^actor_addr address()^ & Returns the address of this actor. \\ + \hline + \lstinline^actor_system& system()^ & Returns \lstinline^context()->system()^. \\ + \hline + \lstinline^actor_system& home_system()^ & Returns the system that spawned this actor. \\ + \hline + \lstinline^execution_unit* context()^ & Returns underlying thread or current scheduler worker. \\ + \hline + ~ & ~ \\ \textbf{Customization Points} & ~ \\ + \hline + \lstinline^on_exit()^ & Can be overridden to perform cleanup code. \\ + \hline + \lstinline^const char* name()^ & Returns a debug name for this actor type. \\ + \hline + ~ & ~ \\ \textbf{Actor Management} & ~ \\ + \hline + \lstinline^link_to(other)^ & Link to an actor \see{link}. \\ + \hline + \lstinline^unlink_from(other)^ & Remove link to an actor \see{link}. \\ + \hline + \lstinline^monitor(other)^ & Unidirectionally monitors an actor \see{monitor}. \\ + \hline + \lstinline^demonitor(other)^ & Removes a monitor from \lstinline^whom^. \\ + \hline + \lstinline^spawn(F fun, xs...)^ & Spawns a new actor from \lstinline^fun^. \\ + \hline + \lstinline^spawn(xs...)^ & Spawns a new actor of type \lstinline^T^. \\ + \hline + ~ & ~ \\ \textbf{Message Processing} & ~ \\ + \hline + \lstinline^T make_response_promise()^ & Allows an actor to delay its response message. \\ + \hline + \lstinline^T response(xs...)^ & Convenience function for creating fulfilled promises. \\ + \hline +\end{tabular} +\end{center} + +\clearpage +\subsubsection{Class \lstinline^scheduled_actor^} + +All scheduled actors inherit from \lstinline^scheduled_actor^. This includes +statically and dynamically typed event-based actors as well as brokers +\see{broker}. + +\begin{center} +\begin{tabular}{ll} + \textbf{Types} & ~ \\ + \hline + \lstinline^pointer^ & \lstinline^scheduled_actor*^ \\ + \hline + \lstinline^exception_handler^ & \lstinline^function^ \\ + \hline + \lstinline^default_handler^ & \lstinline^function (pointer, message_view&)>^ \\ + \hline + \lstinline^error_handler^ & \lstinline^function^ \\ + \hline + \lstinline^down_handler^ & \lstinline^function^ \\ + \hline + \lstinline^exit_handler^ & \lstinline^function^ \\ + \hline + ~ & ~ \\ \textbf{Constructors} & ~ \\ + \hline + \lstinline^(actor_config&)^ & Constructs the actor using a config. \\ + \hline + ~ & ~ \\ \textbf{Termination} & ~ \\ + \hline + \lstinline^quit()^ & Stops this actor with normal exit reason. \\ + \hline + \lstinline^quit(error x)^ & Stops this actor with error \lstinline^x^. \\ + \hline + ~ & ~ \\ \textbf{Special-purpose Handlers} & ~ \\ + \hline + \lstinline^set_exception_handler(F f)^ & Installs \lstinline^f^ for converting exceptions to errors \see{error}. \\ + \hline + \lstinline^set_down_handler(F f)^ & Installs \lstinline^f^ to handle down messages \see{down-message}. \\ + \hline + \lstinline^set_exit_handler(F f)^ & Installs \lstinline^f^ to handle exit messages \see{exit-message}. \\ + \hline + \lstinline^set_error_handler(F f)^ & Installs \lstinline^f^ to handle error messages (see \sref{error-message} and \sref{error}). \\ + \hline + \lstinline^set_default_handler(F f)^ & Installs \lstinline^f^ as fallback message handler \see{default-handler}. \\ + \hline +\end{tabular} +\end{center} + +\clearpage +\subsubsection{Class \lstinline^blocking_actor^} + +A blocking actor always lives in its own thread of execution. They are not as +lightweight as event-based actors and thus do not scale up to large numbers. +The primary use case for blocking actors is to use a \lstinline^scoped_actor^ +for ad-hoc communication to selected actors. Unlike scheduled actors, CAF does +\textbf{not} dispatch system messages to special-purpose handlers. A blocking +actors receives \emph{all} messages regularly through its mailbox. A blocking +actor is considered \emph{done} only after it returned from \lstinline^act^ (or +from the implementation in function-based actors). A \lstinline^scoped_actor^ +sends its exit messages as part of its destruction. + +\begin{center} +\begin{tabular}{ll} + \textbf{Constructors} & ~ \\ + \hline + \lstinline^(actor_config&)^ & Constructs the actor using a config. \\ + \hline + ~ & ~ \\ \textbf{Customization Points} & ~ \\ + \hline + \lstinline^void act()^ & Implements the behavior of the actor. \\ + \hline + ~ & ~ \\ \textbf{Termination} & ~ \\ + \hline + \lstinline^const error& fail_state()^ & Returns the current exit reason. \\ + \hline + \lstinline^fail_state(error x)^ & Sets the current exit reason. \\ + \hline + ~ & ~ \\ \textbf{Actor Management} & ~ \\ + \hline + \lstinline^wait_for(Ts... xs)^ & Blocks until all actors \lstinline^xs...^ are done. \\ + \hline + \lstinline^await_all_other_actors_done()^ & Blocks until all other actors are done. \\ + \hline + ~ & ~ \\ \textbf{Message Handling} & ~ \\ + \hline + \lstinline^receive(Ts... xs)^ & Receives a message using the callbacks \lstinline^xs...^. \\ + \hline + \lstinline^receive_for(T& begin, T end)^ & See \sref{receive-loop}. \\ + \hline + \lstinline^receive_while(F stmt)^ & See \sref{receive-loop}. \\ + \hline + \lstinline^do_receive(Ts... xs)^ & See \sref{receive-loop}. \\ + \hline +\end{tabular} +\end{center} + +\clearpage +\subsection{Messaging Interfaces} +\label{interface} + +Statically typed actors require abstract messaging interfaces to allow the +compiler to type-check actor communication. Interfaces in CAF are defined using +the variadic template \lstinline^typed_actor<...>^, which defines the proper +actor handle at the same time. Each template parameter defines one +\lstinline^input/output^ pair via +\lstinline^replies_to::with^. For inputs that do not +generate outputs, \lstinline^reacts_to^ can be used as shortcut for +\lstinline^replies_to::with^. In the same way functions cannot +be overloaded only by their return type, interfaces cannot accept one input +twice (possibly mapping it to different outputs). The example below defines a +messaging interface for a simple calculator. + +\cppexample[17-21]{message_passing/calculator} + +It is not required to create a type alias such as \lstinline^calculator_actor^, +but it makes dealing with statically typed actors much easier. Also, a central +alias definition eases refactoring later on. + +Interfaces have set semantics. This means the following two type aliases +\lstinline^i1^ and \lstinline^i2^ are equal: + +\begin{lstlisting} +using i1 = typed_actor::with, replies_to::with>; +using i2 = typed_actor::with, replies_to::with>; +\end{lstlisting} + +Further, actor handles of type \lstinline^A^ are assignable to handles of type +\lstinline^B^ as long as \lstinline^B^ is a subset of \lstinline^A^. + +For convenience, the class \lstinline^typed_actor<...>^ defines the member +types shown below to grant access to derived types. + +\begin{center} +\begin{tabular}{ll} + \textbf{Types} & ~ \\ + \hline + \lstinline^behavior_type^ & A statically typed set of message handlers. \\ + \hline + \lstinline^base^ & Base type for actors, i.e., \lstinline^typed_event_based_actor<...>^. \\ + \hline + \lstinline^pointer^ & A pointer of type \lstinline^base*^. \\ + \hline + \lstinline^stateful_base^ & See \sref{stateful-actor}. \\ + \hline + \lstinline^stateful_pointer^ & A pointer of type \lstinline^stateful_base*^. \\ + \hline + \lstinline^extend^ & Extend this typed actor with \lstinline^Ts...^. \\ + \hline + \lstinline^extend_with^ & Extend this typed actor with all cases from \lstinline^Other^. \\ + \hline +\end{tabular} +\end{center} + +\clearpage +\subsection{Spawning Actors} +\label{spawn} + +Both statically and dynamically typed actors are spawned from an +\lstinline^actor_system^ using the member function \lstinline^spawn^. The +function either takes a function as first argument or a class as first template +parameter. For example, the following functions and classes represent actors. + +\cppexample[24-29]{message_passing/calculator} + +Spawning an actor for each implementation is illustrated below. + +\cppexample[140-145]{message_passing/calculator} + +Additional arguments to \lstinline^spawn^ are passed to the constructor of a +class or used as additional function arguments, respectively. In the example +above, none of the three functions takes any argument other than the implicit +but optional \lstinline^self^ pointer. + +\subsection{Function-based Actors} +\label{function-based} + +When using a function or function object to implement an actor, the first +argument \emph{can} be used to capture a pointer to the actor itself. The type +of this pointer is usually \lstinline^event_based_actor*^ or +\lstinline^blocking_actor*^. The proper pointer type for any +\lstinline^typed_actor^ handle \lstinline^T^ can be obtained via +\lstinline^T::pointer^ \see{interface}. + +Blocking actors simply implement their behavior in the function body. The actor +is done once it returns from that function. + +Event-based actors can either return a \lstinline^behavior^ +\see{message-handler} that is used to initialize the actor or explicitly set +the initial behavior by calling \lstinline^self->become(...)^. Due to the +asynchronous, event-based nature of this kind of actor, the function usually +returns immediately after setting a behavior (message handler) for the +\emph{next} incoming message. Hence, variables on the stack will be out of +scope once a message arrives. Managing state in function-based actors can be +done either via rebinding state with \lstinline^become^, using heap-located +data referenced via \lstinline^std::shared_ptr^ or by using the ``stateful +actor'' abstraction~\see{stateful-actor}. + +The following three functions implement the prototypes shown in~\sref{spawn} +and illustrate one blocking actor and two event-based actors (statically and +dynamically typed). + +\clearpage +\cppexample[31-72]{message_passing/calculator} + +\clearpage +\subsection{Class-based Actors} +\label{class-based} + +Implementing an actor using a class requires the following: +\begin{itemize} +\item Provide a constructor taking a reference of type + \lstinline^actor_config&^ as first argument, which is forwarded to the base + class. The config is passed implicitly to the constructor when calling + \lstinline^spawn^, which also forwards any number of additional arguments + to the constructor. +\item Override \lstinline^make_behavior^ for event-based actors and + \lstinline^act^ for blocking actors. +\end{itemize} + +Implementing actors with classes works for all kinds of actors and allows +simple management of state via member variables. However, composing states via +inheritance can get quite tedious. For dynamically typed actors, composing +states is particularly hard, because the compiler cannot provide much help. For +statically typed actors, CAF also provides an API for composable +behaviors~\see{composable-behavior} that works well with inheritance. The +following three examples implement the forward declarations shown in +\sref{spawn}. + +\cppexample[74-108]{message_passing/calculator} + +\clearpage +\subsection{Stateful Actors} +\label{stateful-actor} + +The stateful actor API makes it easy to maintain state in function-based +actors. It is also safer than putting state in member variables, because the +state ceases to exist after an actor is done and is not delayed until the +destructor runs. For example, if two actors hold a reference to each other via +member variables, they produce a cycle and neither will get destroyed. Using +stateful actors instead breaks the cycle, because references are destroyed when +an actor calls \lstinline^self->quit()^ (or is killed externally). The +following example illustrates how to implement stateful actors with static +typing as well as with dynamic typing. + +\cppexample[18-44]{message_passing/cell} + +Stateful actors are spawned in the same way as any other function-based actor +\see{function-based}. + +\cppexample[49-50]{message_passing/cell} + +\clearpage +\subsection{Actors from Composable Behaviors \experimental} +\label{composable-behavior} + +When building larger systems, it is often useful to implement the behavior of +an actor in terms of other, existing behaviors. The composable behaviors in +CAF allow developers to generate a behavior class from a messaging +interface~\see{interface}. + +The base type for composable behaviors is \lstinline^composable_behavior^, +where \lstinline^T^ is a \lstinline^typed_actor<...>^. CAF maps each +\lstinline^replies_to::with^ in \lstinline^T^ to a pure virtual +member function with signature: + +\begin{lstlisting} + result operator()(param, param, param);. +\end{lstlisting} + +Note that \lstinline^operator()^ will take integral types as well as atom +constants simply by value. A \lstinline^result^ accepts either a value of +type \lstinline^T^, a \lstinline^skip_t^ \see{default-handler}, an +\lstinline^error^ \see{error}, a \lstinline^delegated^ \see{delegate}, or a +\lstinline^response_promise^ \see{promise}. A \lstinline^result^ is +constructed by returning \lstinline^unit^. + +A behavior that combines the behaviors \lstinline^X^, \lstinline^Y^, and +\lstinline^Z^ must inherit from \lstinline^composed_behavior^ instead of +inheriting from the three classes directly. The class +\lstinline^composed_behavior^ ensures that the behaviors are concatenated +correctly. In case one message handler is defined in multiple base types, the +\emph{first} type in declaration order ``wins''. For example, if \lstinline^X^ +and \lstinline^Y^ both implement the interface +\lstinline^replies_to::with^, only the handler implemented in +\lstinline^X^ is active. + +Any composable (or composed) behavior with no pure virtual member functions can +be spawned directly through an actor system by calling +\lstinline^system.spawn<...>()^, as shown below. + +\cppexample[20-52]{composition/calculator_behavior} + +\clearpage + +The second example illustrates how to use non-primitive values that are wrapped +in a \lstinline^param^ when working with composable behaviors. The purpose +of \lstinline^param^ is to provide a single interface for both constant and +non-constant access. Constant access is modeled with the implicit conversion +operator to a const reference, the member function \lstinline^get()^, and +\lstinline^operator->^. + +When acquiring mutable access to the represented value, CAF copies the value +before allowing mutable access to it if more than one reference to the value +exists. This copy-on-write optimization avoids race conditions by design, while +minimizing copy operations \see{copy-on-write}. A mutable reference is returned +from the member functions \lstinline^get_mutable()^ and \lstinline^move()^. The +latter is a convenience function for \lstinline^std::move(x.get_mutable())^. +The following example illustrates how to use \lstinline^param^ +when implementing a simple dictionary. + +\cppexample[22-44]{composition/dictionary_behavior} + +\subsection{Attaching Cleanup Code to Actors} +\label{attach} + +Users can attach cleanup code to actors. This code is executed immediately if +the actor has already exited. Otherwise, the actor will execute it as part of +its termination. The following example attaches a function object to actors for +printing a custom string on exit. + +\cppexample[46-50]{broker/simple_broker} + +It is possible to attach code to remote actors. However, the cleanup code will +run on the local machine. + +\subsection{Blocking Actors} +\label{blocking-actor} + +Blocking actors always run in a separate thread and are not scheduled by CAF. +Unlike event-based actors, blocking actors have explicit, blocking +\emph{receive} functions. Further, blocking actors do not handle system +messages automatically via special-purpose callbacks \see{special-handler}. +This gives users full control over the behavior of blocking actors. However, +blocking actors still should follow conventions of the actor system. For +example, actors should unconditionally terminate after receiving an +\lstinline^exit_msg^ with reason \lstinline^exit_reason::kill^. + +\subsubsection{Receiving Messages} + +The function \lstinline^receive^ sequentially iterates over all elements in the +mailbox beginning with the first. It takes a message handler that is applied to +the elements in the mailbox until an element was matched by the handler. An +actor calling \lstinline^receive^ is blocked until it successfully dequeued a +message from its mailbox or an optional timeout occurs. Messages that are not +matched by the behavior are automatically skipped and remain in the mailbox. + +\begin{lstlisting} +self->receive ( + [](int x) { /* ... */ } +); +\end{lstlisting} + +\subsubsection{Catch-all Receive Statements} +\label{catch-all} + +Blocking actors can use inline catch-all callbacks instead of setting a default +handler \see{default-handler}. A catch-all case must be the last callback +before the optional timeout, as shown in the example below. + +\begin{lstlisting} +self->receive( + [&](float x) { + // ... + }, + [&](const down_msg& x) { + // ... + }, + [&](const exit_msg& x) { + // ... + }, + others >> [](message_view& x) -> result { + // report unexpected message back to client + return sec::unexpected_message; + } +); +\end{lstlisting} + +\clearpage +\subsubsection{Receive Loops} +\label{receive-loop} + +Message handler passed to \lstinline^receive^ are temporary object at runtime. +Hence, calling \lstinline^receive^ inside a loop creates an unnecessary amount +of short-lived objects. CAF provides predefined receive loops to allow for +more efficient code. + +\begin{lstlisting} +// BAD +std::vector results; +for (size_t i = 0; i < 10; ++i) + receive ( + [&](int value) { + results.push_back(value); + } + ); + +// GOOD +std::vector results; +size_t i = 0; +receive_for(i, 10) ( + [&](int value) { + results.push_back(value); + } +); +\end{lstlisting} + +\begin{lstlisting} +// BAD +size_t received = 0; +while (received < 10) { + receive ( + [&](int) { + ++received; + } + ); +} ; + +// GOOD +size_t received = 0; +receive_while([&] { return received < 10; }) ( + [&](int) { + ++received; + } +); +\end{lstlisting} +\clearpage + +\begin{lstlisting} +// BAD +size_t received = 0; +do { + receive ( + [&](int) { + ++received; + } + ); +} while (received < 10); + +// GOOD +size_t received = 0; +do_receive ( + [&](int) { + ++received; + } +).until([&] { return received >= 10; }); +\end{lstlisting} + +The examples above illustrate the correct usage of the three loops +\lstinline^receive_for^, \lstinline^receive_while^ and +\lstinline^do_receive(...).until^. It is possible to nest receives and receive +loops. + +\begin{lstlisting} +bool running = true; +self->receive_while([&] { return running; }) ( + [&](int value1) { + self->receive ( + [&](float value2) { + aout(self) << value1 << " => " << value2 << endl; + } + ); + }, + // ... +); +\end{lstlisting} + +\subsubsection{Scoped Actors} +\label{scoped-actors} + +The class \lstinline^scoped_actor^ offers a simple way of communicating with +CAF actors from non-actor contexts. It overloads \lstinline^operator->^ to +return a \lstinline^blocking_actor*^. Hence, it behaves like the implicit +\lstinline^self^ pointer in functor-based actors, only that it ceases to exist +at scope end. + +\begin{lstlisting} +void test(actor_system& system) { + scoped_actor self{system}; + // spawn some actor + auto aut = self->spawn(my_actor_impl); + self->send(aut, "hi there"); + // self will be destroyed automatically here; any + // actor monitoring it will receive down messages etc. +} +\end{lstlisting} diff -Nru actor-framework-0.13.2/doc/tex/Brokers.tex actor-framework-0.16.3/doc/tex/Brokers.tex --- actor-framework-0.13.2/doc/tex/Brokers.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/Brokers.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,270 @@ +\section{Network I/O with Brokers} +\label{broker} + +When communicating to other services in the network, sometimes low-level socket +I/O is inevitable. For this reason, CAF provides \emph{brokers}. A broker is +an event-based actor running in the middleman that multiplexes socket I/O. It +can maintain any number of acceptors and connections. Since the broker runs in +the middleman, implementations should be careful to consume as little time as +possible in message handlers. Brokers should outsource any considerable amount +of work by spawning new actors or maintaining worker actors. + +\textit{Note that all UDP-related functionality is still \experimental.} + +\subsection{Spawning Brokers} + +Brokers are implemented as functions and are spawned by calling on of the three +following member functions of the middleman. + +\begin{lstlisting} +template , class... Ts> +typename infer_handle_from_fun::type +spawn_broker(F fun, Ts&&... xs); + +template , class... Ts> +expected::type> +spawn_client(F fun, const std::string& host, uint16_t port, Ts&&... xs); + +template , class... Ts> +expected::type> +spawn_server(F fun, uint16_t port, Ts&&... xs); +\end{lstlisting} + +The function \lstinline^spawn_broker^ simply spawns a broker. The convenience +function \lstinline^spawn_client^ tries to connect to given host and port over +TCP and returns a broker managing this connection on success. Finally, +\lstinline^spawn_server^ opens a local TCP port and spawns a broker managing it +on success. There are no convenience functions spawn a UDP-based client or +server. + +\subsection{Class \texttt{broker}} +\label{broker-class} + +\begin{lstlisting} +void configure_read(connection_handle hdl, receive_policy::config config); +\end{lstlisting} + +Modifies the receive policy for the connection identified by \lstinline^hdl^. +This will cause the middleman to enqueue the next \lstinline^new_data_msg^ +according to the given \lstinline^config^ created by +\lstinline^receive_policy::exactly(x)^, \lstinline^receive_policy::at_most(x)^, +or \lstinline^receive_policy::at_least(x)^ (with \lstinline^x^ denoting the +number of bytes). + +\begin{lstlisting} +void write(connection_handle hdl, size_t num_bytes, const void* buf) +void write(datagram_handle hdl, size_t num_bytes, const void* buf) +\end{lstlisting} + +Writes data to the output buffer. + +\begin{lstlisting} +void enqueue_datagram(datagram_handle hdl, std::vector buf); +\end{lstlisting} + +Enqueues a buffer to be sent as a datagram. Use of this function is encouraged +over write as it allows reuse of the buffer which can be returned to the broker +in a \lstinline^datagram_sent_msg^. + +\begin{lstlisting} +void flush(connection_handle hdl); +void flush(datagram_handle hdl); +\end{lstlisting} + +Sends the data from the output buffer. + +\begin{lstlisting} +template +actor fork(F fun, connection_handle hdl, Ts&&... xs); +\end{lstlisting} + +Spawns a new broker that takes ownership of a given connection. + +\begin{lstlisting} +size_t num_connections(); +\end{lstlisting} + +Returns the number of open connections. + +\begin{lstlisting} +void close(connection_handle hdl); +void close(accept_handle hdl); +void close(datagram_handle hdl); +\end{lstlisting} + +Closes the endpoint related to the handle. + +\begin{lstlisting} +expected> +add_tcp_doorman(uint16_t port = 0, const char* in = nullptr, + bool reuse_addr = false); +\end{lstlisting} + +Creates new doorman that accepts incoming connections on a given port and +returns the handle to the doorman and the port in use or an error. + +\begin{lstlisting} +expected +add_tcp_scribe(const std::string& host, uint16_t port); +\end{lstlisting} + +Creates a new scribe to connect to host:port and returns handle to it or an +error. + +\begin{lstlisting} +expected> +add_udp_datagram_servant(uint16_t port = 0, const char* in = nullptr, + bool reuse_addr = false); +\end{lstlisting} + +Creates a datagram servant to handle incoming datagrams on a given port. +Returns the handle to the servant and the port in use or an error. + +\begin{lstlisting} +expected +add_udp_datagram_servant(const std::string& host, uint16_t port); +\end{lstlisting} + +Creates a datagram servant to send datagrams to host:port and returns a handle +to it or an error. + +\subsection{Broker-related Message Types} + +Brokers receive system messages directly from the middleman for connection and +acceptor events. + +\textbf{Note:} brokers are \emph{required} to handle these messages immediately +regardless of their current state. Not handling the system messages from the +broker results in loss of data, because system messages are \emph{not} +delivered through the mailbox and thus cannot be skipped. + +\begin{lstlisting} +struct new_connection_msg { + accept_handle source; + connection_handle handle; +}; +\end{lstlisting} + +Indicates that \lstinline^source^ accepted a new TCP connection identified by +\lstinline^handle^. + +\begin{lstlisting} +struct new_data_msg { + connection_handle handle; + std::vector buf; +}; +\end{lstlisting} + +Contains raw bytes received from \lstinline^handle^. The amount of data +received per event is controlled with \lstinline^configure_read^ (see +\ref{broker-class}). It is worth mentioning that the buffer is re-used whenever +possible. + +\begin{lstlisting} +struct data_transferred_msg { + connection_handle handle; + uint64_t written; + uint64_t remaining; +}; +\end{lstlisting} + +This message informs the broker that the \lstinline^handle^ sent +\lstinline^written^ bytes with \lstinline^remaining^ bytes in the buffer. Note, +that these messages are not sent per default but must be explicitly enabled via +the member function \lstinline^ack_writes^. + +\begin{lstlisting} +struct connection_closed_msg { + connection_handle handle; +}; + +struct acceptor_closed_msg { + accept_handle handle; +}; +\end{lstlisting} + +A \lstinline^connection_closed_msg^ or \lstinline^acceptor_closed_msg^ informs +the broker that one of its handles is no longer valid. + +\begin{lstlisting} +struct connection_passivated_msg { + connection_handle handle; +}; + +struct acceptor_passivated_msg { + accept_handle handle; +}; +\end{lstlisting} + +A \lstinline^connection_passivated_msg^ or \lstinline^acceptor_passivated_msg^ +informs the broker that one of its handles entered passive mode and no longer +accepts new data or connections \see{trigger}. + +The following messages are related to UDP communication +(see~\sref{transport-protocols}. Since UDP is not connection oriented, there is +no equivalent to the \lstinline^new_connection_msg^ of TCP. + +\begin{lstlisting} +struct new_datagram_msg { + datagram_handle handle; + network::receive_buffer buf; +}; +\end{lstlisting} + +Contains the raw bytes from \lstinline^handle^. The buffer always has a maximum +size of 65k to receive all regular UDP messages. The amount of bytes can be +queried via the \lstinline^.size()^ member function. Similar to TCP, the buffer +is reused when possible---please do not resize it. + +\begin{lstlisting} +struct datagram_sent_msg { + datagram_handle handle; + uint64_t written; + std::vector buf; +}; +\end{lstlisting} + +This message informs the broker that the \lstinline^handle^ sent a datagram of +\lstinline^written^ bytes. It includes the buffer that held the sent message to +allow its reuse. Note, that these messages are not sent per default but must be +explicitly enabled via the member function \lstinline^ack_writes^. + +\begin{lstlisting} +struct datagram_servant_closed_msg { + std::vector handles; +}; +\end{lstlisting} + +A \lstinline^datagram_servant_closed_msg^ informs the broker that one of its +handles is no longer valid. + +\begin{lstlisting} +struct datagram_servant_passivated_msg { + datagram_handle handle; +}; +\end{lstlisting} + +A \lstinline^datagram_servant_closed_msg^ informs the broker that one of its +handles entered passive mode and no longer accepts new data \see{trigger}. + +\subsection{Manually Triggering Events \experimental} +\label{trigger} + +Brokers receive new events as \lstinline^new_connection_msg^ and +\lstinline^new_data_msg^ as soon and as often as they occur, per default. This +means a fast peer can overwhelm a broker by sending it data faster than the +broker can process it. In particular if the broker outsources work items to +other actors, because work items can accumulate in the mailboxes of the +workers. + +Calling \lstinline^self->trigger(x,y)^, where \lstinline^x^ is a connection or +acceptor handle and \lstinline^y^ is a positive integer, allows brokers to halt +activities after \lstinline^y^ additional events. Once a connection or acceptor +stops accepting new data or connections, the broker receives a +\lstinline^connection_passivated_msg^ or \lstinline^acceptor_passivated_msg^. + +Brokers can stop activities unconditionally with \lstinline^self->halt(x)^ and +resume activities unconditionally with \lstinline^self->trigger(x)^. diff -Nru actor-framework-0.13.2/doc/tex/CommonPitfalls.tex actor-framework-0.16.3/doc/tex/CommonPitfalls.tex --- actor-framework-0.13.2/doc/tex/CommonPitfalls.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/CommonPitfalls.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,71 @@ +\section{Common Pitfalls} +\label{pitfalls} + +This Section highlights common mistakes or C++ subtleties that can show up when +programming in CAF. + +\subsection{Defining Message Handlers} + +\begin{itemize} +\item C++ evaluates comma-separated expressions from left-to-right, using only + the last element as return type of the whole expression. This means that + message handlers and behaviors must \emph{not} be initialized like this: + \begin{lstlisting} + message_handler wrong = ( + [](int i) { /*...*/ }, + [](float f) { /*...*/ } + ); + \end{lstlisting} + The correct way to initialize message handlers and behaviors is to either + use the constructor or the member function \lstinline^assign^: + \begin{lstlisting} + message_handler ok1{ + [](int i) { /*...*/ }, + [](float f) { /*...*/ } + }; + + message_handler ok2; + // some place later + ok2.assign( + [](int i) { /*...*/ }, + [](float f) { /*...*/ } + ); + \end{lstlisting} +\end{itemize} + +\subsection{Event-Based API} + +\begin{itemize} +\item The member function \lstinline^become^ does not block, i.e., always + returns immediately. Thus, lambda expressions should \textit{always} capture + by value. Otherwise, all references on the stack will cause undefined + behavior if the lambda expression is executed. +\end{itemize} + +\subsection{Requests} + +\begin{itemize} +\item A handle returned by \lstinline^request^ represents \emph{exactly one} + response message. It is not possible to receive more than one response + message. +\item The handle returned by \lstinline^request^ is bound to the calling actor. + It is not possible to transfer a handle to a response to another actor. +\end{itemize} + +\clearpage + +\subsection{Sharing} + +\begin{itemize} +\item It is strongly recommended to \textbf{not} share states between actors. + In particular, no actor shall ever access member variables or member + functions of another actor. Accessing shared memory segments concurrently + can cause undefined behavior that is incredibly hard to find and debug. + However, sharing \textit{data} between actors is fine, as long as the data + is \textit{immutable} and its lifetime is guaranteed to outlive all actors. + The simplest way to meet the lifetime guarantee is by storing the data in + smart pointers such as \lstinline^std::shared_ptr^. Nevertheless, the + recommended way of sharing informations is message passing. Sending the + same message to multiple actors does not result in copying the data several + times. +\end{itemize} diff -Nru actor-framework-0.13.2/doc/tex/ConfiguringActorApplications.tex actor-framework-0.16.3/doc/tex/ConfiguringActorApplications.tex --- actor-framework-0.13.2/doc/tex/ConfiguringActorApplications.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/ConfiguringActorApplications.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,336 @@ +\section{Configuring Actor Applications} +\label{system-config} + +CAF configures applications at startup using an +\lstinline^actor_system_config^ or a user-defined subclass of that type. The +config objects allow users to add custom types, to load modules, and to +fine-tune the behavior of loaded modules with command line options or +configuration files~\see{system-config-options}. + +The following code example is a minimal CAF application with a +middleman~\see{middleman} but without any custom configuration options. + +\begin{lstlisting} +void caf_main(actor_system& system) { + // ... +} +CAF_MAIN(io::middleman) +\end{lstlisting} + +The compiler expands this example code to the following. + +\begin{lstlisting} +void caf_main(actor_system& system) { + // ... +} +int main(int argc, char** argv) { + return exec_main(caf_main, argc, argv); +} +\end{lstlisting} + +The function \lstinline^exec_main^ creates a config object, loads all modules +requested in \lstinline^CAF_MAIN^ and then calls \lstinline^caf_main^. A +minimal implementation for \lstinline^main^ performing all these steps manually +is shown in the next example for the sake of completeness. + +\begin{lstlisting} +int main(int argc, char** argv) { + actor_system_config cfg; + // read CLI options + cfg.parse(argc, argv); + // return immediately if a help text was printed + if (cfg.cli_helptext_printed) + return 0; + // load modules + cfg.load(); + // create actor system and call caf_main + actor_system system{cfg}; + caf_main(system); +} +\end{lstlisting} + +However, setting up config objects by hand is usually not necessary. CAF +automatically selects user-defined subclasses of +\lstinline^actor_system_config^ if \lstinline^caf_main^ takes a second +parameter by reference, as shown in the minimal example below. + +\begin{lstlisting} +class my_config : public actor_system_config { +public: + my_config() { + // ... + } +}; + +void caf_main(actor_system& system, const my_config& cfg) { + // ... +} + +CAF_MAIN() +\end{lstlisting} + +Users can perform additional initialization, add custom program options, etc. +simply by implementing a default constructor. + +\subsection{Loading Modules} +\label{system-config-module} + +The simplest way to load modules is to use the macro \lstinline^CAF_MAIN^ and +to pass a list of all requested modules, as shown below. + +\begin{lstlisting} +void caf_main(actor_system& system) { + // ... +} +CAF_MAIN(mod1, mod2, ...) +\end{lstlisting} + +Alternatively, users can load modules in user-defined config classes. + +\begin{lstlisting} +class my_config : public actor_system_config { +public: + my_config() { + load(); + load(); + // ... + } +}; +\end{lstlisting} + +The third option is to simply call \lstinline^x.load()^ on a config +object \emph{before} initializing an actor system with it. + +\subsection{Command Line Options and INI Configuration Files} +\label{system-config-options} + +CAF organizes program options in categories and parses CLI arguments as well +as INI files. CLI arguments override values in the INI file which override +hard-coded defaults. Users can add any number of custom program options by +implementing a subtype of \lstinline^actor_system_config^. The example below +adds three options to the ``global'' category. + +\cppexample[222-234]{remoting/distributed_calculator} + +We create a new ``global'' category in \lstinline^custom_options_}^. Each +following call to \lstinline^add^ then appends individual options to the +category. The first argument to \lstinline^add^ is the associated variable. The +second argument is the name for the parameter, optionally suffixed with a +comma-separated single-character short name. The short name is only considered +for CLI parsing and allows users to abbreviate commonly used option names. The +third and final argument to \lstinline^add^ is a help text. + +The custom \lstinline^config^ class allows end users to set the port for the +application to 42 with either \lstinline^--port=42^ (long name) or +\lstinline^-p 42^ (short name). The long option name is prefixed by the +category when using a different category than ``global''. For example, adding +the port option to the category ``foo'' means end users have to type +\lstinline^--foo.port=42^ when using the long name. Short names are unaffected +by the category, but have to be unique. + +Boolean options do not require arguments. The member variable +\lstinline^server_mode^ is set to \lstinline^true^ if the command line contains +either \lstinline^--server-mode^ or \lstinline^-s^. + +The example uses member variables for capturing user-provided settings for +simplicity. However, this is not required. For example, +\lstinline^add(...)^ allows omitting the first argument entirely. All +values of the configuration are accessible with \lstinline^get_or^. Note that +all global options can omit the \lstinline^"global."^ prefix. + +CAF adds the program options ``help'' (with short names \lstinline^-h^ and +\lstinline^-?^) as well as ``long-help'' to the ``global'' category. + +The default name for the INI file is \lstinline^caf-application.ini^. Users can +change the file name and path by passing \lstinline^--config-file=^ on +the command line. + +INI files are organized in categories. No value is allowed outside of a +category (no implicit ``global'' category). The parses uses the following +syntax: + +\begin{tabular}{p{0.3\textwidth}p{0.65\textwidth}} + \lstinline^key=true^ & is a boolean \\ + \lstinline^key=1^ & is an integer \\ + \lstinline^key=1.0^ & is an floating point number \\ + \lstinline^key=1ms^ & is an timespan \\ + \lstinline^key='foo'^ & is an atom \\ + \lstinline^key="foo"^ & is a string \\ + \lstinline^key=[0, 1, ...]^ & is as a list \\ + \lstinline^key={a=1, b=2, ...}^ & is a dictionary (map) \\ +\end{tabular} + +The following example INI file lists all standard options in CAF and their +default value. Note that some options such as \lstinline^scheduler.max-threads^ +are usually detected at runtime and thus have no hard-coded default. + +\clearpage +\iniexample{caf-application} + +\clearpage +\subsection{Adding Custom Message Types} +\label{add-custom-message-type} + +CAF requires serialization support for all of its message types +\see{type-inspection}. However, CAF also needs a mapping of unique type names +to user-defined types at runtime. This is required to deserialize arbitrary +messages from the network. + +As an introductory example, we (again) use the following POD type +\lstinline^foo^. + +\cppexample[24-27]{custom_type/custom_types_1} + +To make \lstinline^foo^ serializable, we make it inspectable +\see{type-inspection}: + +\cppexample[30-34]{custom_type/custom_types_1} + +Finally, we give \lstinline^foo^ a platform-neutral name and add it to the list +of serializable types by using a custom config class. + +\cppexample[75-78,81-84]{custom_type/custom_types_1} + +\subsection{Adding Custom Error Types} + +Adding a custom error type to the system is a convenience feature to allow +improve the string representation. Error types can be added by implementing a +render function and passing it to \lstinline^add_error_category^, as shown +in~\sref{custom-error}. + +\clearpage +\subsection{Adding Custom Actor Types \experimental} +\label{add-custom-actor-type} + +Adding actor types to the configuration allows users to spawn actors by their +name. In particular, this enables spawning of actors on a different node +\see{remote-spawn}. For our example configuration, we consider the following +simple \lstinline^calculator^ actor. + +\cppexample[33-39]{remoting/remote_spawn} + +Adding the calculator actor type to our config is achieved by calling +\lstinline^add_actor_type^. Note that adding an actor type in this way +implicitly calls \lstinline^add_message_type^ for typed actors +\see{add-custom-message-type}. This makes our \lstinline^calculator^ actor type +serializable and also enables remote nodes to spawn calculators anywhere in the +distributed actor system (assuming all nodes use the same config). + +\cppexample[99-101,106-106,110-101]{remoting/remote_spawn} + +Our final example illustrates how to spawn a \lstinline^calculator^ locally by +using its type name. Because the dynamic type name lookup can fail and the +construction arguments passed as message can mismatch, this version of +\lstinline^spawn^ returns \lstinline^expected^. + +\begin{lstlisting} +auto x = system.spawn("calculator", make_message()); +if (! x) { + std::cerr << "*** unable to spawn calculator: " + << system.render(x.error()) << std::endl; + return; +} +calculator c = std::move(*x); +\end{lstlisting} + +Adding dynamically typed actors to the config is achieved in the same way. When +spawning a dynamically typed actor in this way, the template parameter is +simply \lstinline^actor^. For example, spawning an actor "foo" which requires +one string is created with: + +\begin{lstlisting} +auto worker = system.spawn("foo", make_message("bar")); +\end{lstlisting} + +Because constructor (or function) arguments for spawning the actor are stored +in a \lstinline^message^, only actors with appropriate input types are allowed. +For example, pointer types are illegal. Hence users need to replace C-strings +with \lstinline^std::string^. + +\clearpage +\subsection{Log Output} +\label{log-output} + +Logging is disabled in CAF per default. It can be enabled by setting the +\lstinline^--with-log-level=^ option of the \lstinline^configure^ script to one +of ``error'', ``warning'', ``info'', ``debug'', or ``trace'' (from least output +to most). Alternatively, setting the CMake variable \lstinline^CAF_LOG_LEVEL^ +to 0, 1, 2, 3, or 4 (from least output to most) has the same effect. + +All logger-related configuration options listed here and in +\sref{system-config-options} are silently ignored if logging is disabled. + +\subsubsection{File Name} +\label{log-output-file-name} + +The output file is generated from the template configured by +\lstinline^logger-file-name^. This template supports the following variables. + +\begin{tabular}{|p{0.2\textwidth}|p{0.75\textwidth}|} + \hline + \textbf{Variable} & \textbf{Output} \\ + \hline + \texttt{[PID]} & The OS-specific process ID. \\ + \hline + \texttt{[TIMESTAMP]} & The UNIX timestamp on startup. \\ + \hline + \texttt{[NODE]} & The node ID of the CAF system. \\ + \hline +\end{tabular} + +\subsubsection{Console} +\label{log-output-console} + +Console output is disabled per default. Setting \lstinline^logger-console^ to +either \lstinline^"uncolored"^ or \lstinline^"colored"^ prints log events to +\lstinline^std::clog^. Using the \lstinline^"colored"^ option will print the +log events in different colors depending on the severity level. + +\subsubsection{Format Strings} +\label{log-output-format-strings} + +CAF uses log4j-like format strings for configuring printing of individual +events via \lstinline^logger-file-format^ and +\lstinline^logger-console-format^. Note that format modifiers are not supported +at the moment. The recognized field identifiers are: + +\begin{tabular}{|p{0.1\textwidth}|p{0.85\textwidth}|} + \hline + \textbf{Character} & \textbf{Output} \\ + \hline + \texttt{c} & The category/component. This name is defined by the macro \lstinline^CAF_LOG_COMPONENT^. Set this macro before including any CAF header. \\ + \hline + \texttt{C} & The full qualifier of the current function. For example, the qualifier of \lstinline^void ns::foo::bar()^ is printed as \lstinline^ns.foo^. \\ + \hline + \texttt{d} & The date in ISO 8601 format, i.e., \lstinline^"YYYY-MM-DD hh:mm:ss"^. \\ + \hline + \texttt{F} & The file name. \\ + \hline + \texttt{L} & The line number. \\ + \hline + \texttt{m} & The user-defined log message. \\ + \hline + \texttt{M} & The name of the current function. For example, the name of \lstinline^void ns::foo::bar()^ is printed as \lstinline^bar^. \\ + \hline + \texttt{n} & A newline. \\ + \hline + \texttt{p} & The priority (severity level). \\ + \hline + \texttt{r} & Elapsed time since starting the application in milliseconds. \\ + \hline + \texttt{t} & ID of the current thread. \\ + \hline + \texttt{a} & ID of the current actor (or ``actor0'' when not logging inside an actor). \\ + \hline + \texttt{\%} & A single percent sign. \\ + \hline +\end{tabular} + +\subsubsection{Filtering} +\label{log-output-filtering} + +The two configuration options \lstinline^logger-component-filter^ and +\lstinline^logger-verbosity^ reduce the amount of generated log events. The +former is a list of excluded component names and the latter can increase the +reported severity level (but not decrease it beyond the level defined at +compile time). diff -Nru actor-framework-0.13.2/doc/tex/conf.py actor-framework-0.16.3/doc/tex/conf.py --- actor-framework-0.13.2/doc/tex/conf.py 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/conf.py 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,336 @@ +# -*- coding: utf-8 -*- +# +# CAF documentation build configuration file, created by +# sphinx-quickstart on Fri Jun 3 11:27:36 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +import sphinx_rtd_theme + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +# +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'CAF' +copyright = u'2016, Dominik Charousset' +author = u'Dominik Charousset' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = u'0.16.0' +# The full version, including alpha/beta/rc tags. +release = u'0.16.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# +# today = '' +# +# Else, today_fmt is used as the format for a strftime call. +# +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +highlight_language = 'C++' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +# +# html_title = u'CAF v0.15' + +# A shorter title for the navigation bar. Default is the same as html_title. +# +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# +# html_logo = None + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# +# html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# +# html_last_updated_fmt = None + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# +# html_additional_pages = {} + +# If false, no module index is generated. +# +# html_domain_indices = True + +# If false, no index is generated. +# +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' +# +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'CAFdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'CAF.tex', u'CAF Documentation', + u'Dominik Charousset', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# +# latex_use_parts = False + +# If true, show page references after internal links. +# +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# +# latex_appendices = [] + +# If false, no module index is generated. +# +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'caf', u'CAF Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +# +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'CAF', u'CAF Documentation', + author, 'CAF', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +# +# texinfo_appendices = [] + +# If false, no module index is generated. +# +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# +# texinfo_no_detailmenu = False diff -Nru actor-framework-0.13.2/doc/tex/Error.tex actor-framework-0.16.3/doc/tex/Error.tex --- actor-framework-0.13.2/doc/tex/Error.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/Error.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,87 @@ +\section{Errors} +\label{error} + +Errors in CAF have a code and a category, similar to +\lstinline^std::error_code^ and \lstinline^std::error_condition^. Unlike its +counterparts from the C++ standard library, \lstinline^error^ is +plattform-neutral and serializable. Instead of using category singletons, CAF +stores categories as atoms~\see{atom}. Errors can also include a message to +provide additional context information. + +\subsection{Class Interface} + +\begin{center} +\begin{tabular}{ll} + \textbf{Constructors} & ~ \\ + \hline + \lstinline^(Enum x)^ & Construct error by calling \lstinline^make_error(x)^ \\ + \hline + \lstinline^(uint8_t x, atom_value y)^ & Construct error with code \lstinline^x^ and category \lstinline^y^ \\ + \hline + \lstinline^(uint8_t x, atom_value y, message z)^ & Construct error with code \lstinline^x^, category \lstinline^y^, and context \lstinline^z^ \\ + \hline + ~ & ~ \\ \textbf{Observers} & ~ \\ + \hline + \lstinline^uint8_t code()^ & Returns the error code \\ + \hline + \lstinline^atom_value category()^ & Returns the error category \\ + \hline + \lstinline^message context()^ & Returns additional context information \\ + \hline + \lstinline^explicit operator bool()^ & Returns \lstinline^code() != 0^ \\ + \hline +\end{tabular} +\end{center} + +\subsection{Add Custom Error Categories} +\label{custom-error} + +Adding custom error categories requires three steps: (1)~declare an enum class +of type \lstinline^uint8_t^ with the first value starting at 1, (2)~implement a +free function \lstinline^make_error^ that converts the enum to an +\lstinline^error^ object, (3)~add the custom category to the actor system with +a render function. The last step is optional to allow users to retrieve a +better string representation from \lstinline^system.render(x)^ than +\lstinline^to_string(x)^ can offer. Note that any error code with value 0 is +interpreted as \emph{not-an-error}. The following example adds a custom error +category by performing the first two steps. + +\cppexample[19-34]{message_passing/divider} + +The implementation of \lstinline^to_string(error)^ is unable to call string +conversions for custom error categories. Hence, +\lstinline^to_string(make_error(math_error::division_by_zero))^ returns +\lstinline^"error(1, math)"^. + +The following code adds a rendering function to the actor system to provide a +more satisfactory string conversion. + +\cppexample[50-58]{message_passing/divider} + +With the custom rendering function, +\lstinline^system.render(make_error(math_error::division_by_zero))^ returns +\lstinline^"math_error(division_by_zero)"^. + +\clearpage +\subsection{System Error Codes} +\label{sec} + +System Error Codes (SECs) use the error category \lstinline^"system"^. They +represent errors in the actor system or one of its modules and are defined as +follows. + +\sourcefile[32-117]{libcaf_core/caf/sec.hpp} + +%\clearpage +\subsection{Default Exit Reasons} +\label{exit-reason} + +CAF uses the error category \lstinline^"exit"^ for default exit reasons. These +errors are usually fail states set by the actor system itself. The two +exceptions are \lstinline^exit_reason::user_shutdown^ and +\lstinline^exit_reason::kill^. The former is used in CAF to signalize orderly, +user-requested shutdown and can be used by programmers in the same way. The +latter terminates an actor unconditionally when used in \lstinline^send_exit^, +even if the default handler for exit messages~\see{exit-message} is overridden. + +\sourcefile[29-49]{libcaf_core/caf/exit_reason.hpp} diff -Nru actor-framework-0.13.2/doc/tex/exec_pandoc.sh actor-framework-0.16.3/doc/tex/exec_pandoc.sh --- actor-framework-0.13.2/doc/tex/exec_pandoc.sh 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/exec_pandoc.sh 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,20 @@ +#!/bin/bash + +blacklist="manual.tex variables.tex colors.tex newcommands.tex" + +inBlacklist() { + for e in $blacklist; do + [[ "$e" == "$1" ]] && return 0 + done + return 1 +} + +for i in *.tex ; do + if inBlacklist $i ; then + continue + fi + out_file=$(basename $i .tex) + echo "$i => $out_file" + cat colors.tex variables.tex newcommands.tex $i | ./explode_lstinputlisting.py | pandoc --filter=$PWD/filter.py --wrap=none --listings -f latex -o ${out_file}.rst +done +sphinx-build -b html . html diff -Nru actor-framework-0.13.2/doc/tex/explode_lstinputlisting.py actor-framework-0.16.3/doc/tex/explode_lstinputlisting.py --- actor-framework-0.13.2/doc/tex/explode_lstinputlisting.py 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/explode_lstinputlisting.py 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +import sys +import re + +def parse_range(astr): + result = set() + for part in astr.split(','): + x = part.split('-') + result.update(range(int(x[0]), int(x[-1]) + 1)) + return sorted(result) + +def print_listing(line_range, fname): + print('\\begin{lstlisting}') + if not line_range: + with open(fname, 'r') as fin: + sys.stdout.write(fin.read()) + else: + with open(fname) as mfile: + for num, line in enumerate(mfile, 1): + if num in line_range: + sys.stdout.write(line) + print('\\end{lstlisting}') + +def cppexample(line_range, fname): + print_listing(line_range, '../../examples/{0}.cpp'.format(fname)) + +def iniexample(line_range, fname): + print_listing(line_range, '../../examples/{0}.ini'.format(fname)) + +def sourcefile(line_range, fname): + print_listing(line_range, '../../{0}'.format(fname)) + +rx = re.compile(r"\\(cppexample|iniexample|sourcefile)(?:\[(.+)\])?{(.+)}") + +for line in sys.stdin: + m = rx.match(line) + if not m: + sys.stdout.write(line) + else: + locals()[m.group(1)](parse_range(m.group(2)), m.group(3)) diff -Nru actor-framework-0.13.2/doc/tex/FAQ.tex actor-framework-0.16.3/doc/tex/FAQ.tex --- actor-framework-0.13.2/doc/tex/FAQ.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/FAQ.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,49 @@ +\section{Frequently Asked Questions} +\label{faq} + +This Section is a compilation of the most common questions via GitHub, chat, +and mailing list. + +\subsection{Can I Encrypt CAF Communication?} + +Yes, by using the OpenSSL module~\see{free-remoting-functions}. + +\subsection{Can I Create Messages Dynamically?} + +Yes. + +Usually, messages are created implicitly when sending messages but can also be +created explicitly using \lstinline^make_message^. In both cases, types and +number of elements are known at compile time. To allow for fully dynamic +message generation, CAF also offers \lstinline^message_builder^: + +\begin{lstlisting} +message_builder mb; +// prefix message with some atom +mb.append(strings_atom::value); +// fill message with some strings +std::vector strings{/*...*/}; +for (auto& str : strings) + mb.append(str); +// create the message +message msg = mb.to_message(); +\end{lstlisting} + +\subsection{What Debugging Tools Exist?} + +The \lstinline^scripts/^ and \lstinline^tools/^ directories contain some useful +tools to aid in development and debugging. + +\lstinline^scripts/atom.py^ converts integer atom values back into strings. + +\lstinline^scripts/demystify.py^ replaces cryptic \lstinline^typed_mpi<...>^ +templates with \lstinline^replies_to<...>::with<...>^ and +\lstinline^atom_constant<...>^ with a human-readable representation of the +actual atom. + +\lstinline^scripts/caf-prof^ is an R script that generates plots from CAF +profiler output. + +\lstinline^caf-vec^ is a (highly) experimental tool that annotates CAF logs +with vector timestamps. It gives you happens-before relations and a nice +visualization via \href{https://bestchai.bitbucket.io/shiviz/}{ShiViz}. Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/fig-png/actor_types.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/fig-png/actor_types.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/fig-png/enable_shared_from_this.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/fig-png/enable_shared_from_this.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/fig-png/mailbox_element.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/fig-png/mailbox_element.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/fig-png/make_shared.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/fig-png/make_shared.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/fig-png/refcounting.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/fig-png/refcounting.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/fig-png/shared_ptr.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/fig-png/shared_ptr.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/fig-png/stealing.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/fig-png/stealing.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/fig-png/stream-manager.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/fig-png/stream-manager.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/fig-png/stream.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/fig-png/stream.png differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/fig-png/stream-roles.png and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/fig-png/stream-roles.png differ diff -Nru actor-framework-0.13.2/doc/tex/FirstSteps.tex actor-framework-0.16.3/doc/tex/FirstSteps.tex --- actor-framework-0.13.2/doc/tex/FirstSteps.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/FirstSteps.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,55 @@ +\section{Overview} + +Compiling CAF requires CMake and a C++11-compatible compiler. To get and +compile the sources on UNIX-like systems, type the following in a terminal: + +\begin{verbatim} +git clone https://github.com/actor-framework/actor-framework +cd actor-framework +./configure +make +make install [as root, optional] +\end{verbatim} + +We recommended to run the unit tests as well: + +\begin{verbatim} +make test +\end{verbatim} + +If the output indicates an error, please submit a bug report that includes (a) +your compiler version, (b) your OS, and (c) the content of the file +\texttt{build/Testing/Temporary/LastTest.log}. + +\subsection{Features} + +\begin{itemize} + \item Lightweight, fast and efficient actor implementations + \item Network transparent messaging + \item Error handling based on Erlang's failure model + \item Pattern matching for messages as internal DSL to ease development + \item Thread-mapped actors for soft migration of existing applications + \item Publish/subscribe group communication +\end{itemize} + + +\subsection{Minimal Compiler Versions} + +\begin{itemize} + \item GCC 4.8 + \item Clang 3.4 + \item Visual Studio 2015, Update 3 +\end{itemize} + +\subsection{Supported Operating Systems} + +\begin{itemize} +\item Linux +\item Mac OS X +\item Windows (static library only) +\end{itemize} + +\clearpage +\subsection{Hello World Example} + +\cppexample{hello_world} diff -Nru actor-framework-0.13.2/doc/tex/GroupCommunication.tex actor-framework-0.16.3/doc/tex/GroupCommunication.tex --- actor-framework-0.13.2/doc/tex/GroupCommunication.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/GroupCommunication.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,64 @@ +\section{Group Communication} +\label{groups} + +CAF supports publish/subscribe-based group communication. Dynamically typed +actors can join and leave groups and send messages to groups. The following +example showcases the basic API for retrieving a group from a module by its +name, joining, and leaving. + +\begin{lstlisting} +std::string module = "local"; +std::string id = "foo"; +auto expected_grp = system.groups().get(module, id); +if (! expected_grp) { + std::cerr << "*** cannot load group: " + << system.render(expected_grp.error()) << std::endl; + return; +} +auto grp = std::move(*expected_grp); +scoped_actor self{system}; +self->join(grp); +self->send(grp, "test"); +self->receive( + [](const std::string& str) { + assert(str == "test"); + } +); +self->leave(grp); +\end{lstlisting} + +It is worth mentioning that the module \lstinline`"local"` is guaranteed to +never return an error. The example above uses the general API for retrieving +the group. However, local modules can be easier accessed by calling +\lstinline`system.groups().get_local(id)`, which returns \lstinline`group` +instead of \lstinline`expected`. + +\subsection{Anonymous Groups} +\label{anonymous-group} + +Groups created on-the-fly with \lstinline^system.groups().anonymous()^ can be +used to coordinate a set of workers. Each call to this function returns a new, +unique group instance. + +\subsection{Local Groups} +\label{local-group} + +The \lstinline^"local"^ group module creates groups for in-process +communication. For example, a group for GUI related events could be identified +by \lstinline^system.groups().get_local("GUI events")^. The group ID +\lstinline^"GUI events"^ uniquely identifies a singleton group instance of the +module \lstinline^"local"^. + +\subsection{Remote Groups} +\label{remote-group} + +Calling\lstinline^system.middleman().publish_local_groups(port, addr)^ makes +all local groups available to other nodes in the network. The first argument +denotes the port, while the second (optional) parameter can be used to +whitelist IP addresses. + +After publishing the group at one node (the server), other nodes (the clients) +can get a handle for that group by using the ``remote'' module: +\lstinline^system.groups().get("remote", "@:")^. This +implementation uses N-times unicast underneath and the group is only available +as long as the hosting server is alive. diff -Nru actor-framework-0.13.2/doc/tex/index_footer.rst actor-framework-0.16.3/doc/tex/index_footer.rst --- actor-framework-0.13.2/doc/tex/index_footer.rst 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/index_footer.rst 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,8 @@ +Version Information +=================== + +This version of the Manual was automatically generated from CAF commit +`903f801c `_ +and Manual commit +`a4604f9 `_. + diff -Nru actor-framework-0.13.2/doc/tex/index_header.rst actor-framework-0.16.3/doc/tex/index_header.rst --- actor-framework-0.13.2/doc/tex/index_header.rst 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/index_header.rst 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,8 @@ +CAF User Manual +=============== + +**C++ Actor Framework** version 0.16.0. + +Contents +======== + diff -Nru actor-framework-0.13.2/doc/tex/index.rst actor-framework-0.16.3/doc/tex/index.rst --- actor-framework-0.13.2/doc/tex/index.rst 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/index.rst 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,41 @@ +.. include:: index_header.rst + +.. toctree:: + :maxdepth: 2 + :caption: Core Library + + Introduction + FirstSteps + TypeInspection + MessageHandlers + Actors + MessagePassing + Scheduler + Registry + ReferenceCounting + Error + ConfiguringActorApplications + Messages + GroupCommunication + ManagingGroupsOfWorkers + Streaming + +.. toctree:: + :maxdepth: 2 + :caption: I/O Library + + NetworkTransparency + Brokers + RemoteSpawn + +.. toctree:: + :maxdepth: 2 + :caption: Appendix + + FAQ + Utility + CommonPitfalls + UsingAout + MigrationGuides + +.. include:: index_footer.rst diff -Nru actor-framework-0.13.2/doc/tex/Introduction.tex actor-framework-0.16.3/doc/tex/Introduction.tex --- actor-framework-0.13.2/doc/tex/Introduction.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/Introduction.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,129 @@ +\section{Introduction} + +Before diving into the API of CAF, we discuss the concepts behind it and +explain the terminology used in this manual. + +\subsection{Actor Model} + +The actor model describes concurrent entities---actors---that do not share +state and communicate only via asynchronous message passing. Decoupling +concurrently running software components via message passing avoids race +conditions by design. Actors can create---spawn---new actors and monitor each +other to build fault-tolerant, hierarchical systems. Since message passing is +network transparent, the actor model applies to both concurrency and +distribution. + +Implementing applications on top of low-level primitives such as mutexes and +semaphores has proven challenging and error-prone. In particular when trying to +implement applications that scale up to many CPU cores. Queueing, starvation, +priority inversion, and false sharing are only a few of the issues that can +decrease performance significantly in mutex-based concurrency models. In the +extreme, an application written with the standard toolkit can run slower when +adding more cores. + +The actor model has gained momentum over the last decade due to its high level +of abstraction and its ability to scale dynamically from one core to many cores +and from one node to many nodes. However, the actor model has not yet been +widely adopted in the native programming domain. With CAF, we contribute a +library for actor programming in C++ as open-source software to ease native +development of concurrent as well as distributed systems. In this regard, CAF +follows the C++ philosophy ``building the highest abstraction possible without +sacrificing performance''. + +\subsection{Terminology} + +CAF is inspired by other implementations based on the actor model such as +Erlang or Akka. It aims to provide a modern C++ API allowing for type-safe as +well as dynamically typed messaging. While there are similarities to other +implementations, we made many different design decisions that lead to slight +differences when comparing CAF to other actor frameworks. + +\subsubsection{Dynamically Typed Actor} + +A dynamically typed actor accepts any kind of message and dispatches on its +content dynamically at the receiver. This is the ``traditional'' messaging +style found in implementations like Erlang or Akka. The upside of this approach +is (usually) faster prototyping and less code. This comes at the cost of +requiring excessive testing. + +\subsubsection{Statically Typed Actor} + +CAF achieves static type-checking for actors by defining abstract messaging +interfaces. Since interfaces define both input and output types, CAF is able to +verify messaging protocols statically. The upside of this approach is much +higher robustness to code changes and fewer possible runtime errors. This comes +at an increase in required source code, as developers have to define and use +messaging interfaces. + +\subsubsection{Actor References} +\label{actor-reference} + +CAF uses reference counting for actors. The three ways to store a reference to +an actor are addresses, handles, and pointers. Note that \emph{address} does +not refer to a \emph{memory region} in this context. + +\paragraph{Address} +\label{actor-address} + +Each actor has a (network-wide) unique logical address. This identifier is +represented by \lstinline^actor_addr^, which allows to identify and monitor an +actor. Unlike other actor frameworks, CAF does \emph{not} allow users to send +messages to addresses. This limitation is due to the fact that the address does +not contain any type information. Hence, it would not be safe to send it a +message, because the receiving actor might use a statically typed interface +that does not accept the given message. Because an \lstinline^actor_addr^ fills +the role of an identifier, it has \emph{weak reference semantics} +\see{reference-counting}. + +\paragraph{Handle} +\label{actor-handle} + +An actor handle contains the address of an actor along with its type +information and is required for sending messages to actors. The distinction +between handles and addresses---which is unique to CAF when comparing it to +other actor systems---is a consequence of the design decision to enforce static +type checking for all messages. Dynamically typed actors use \lstinline^actor^ +handles, while statically typed actors use \lstinline^typed_actor<...>^ +handles. Both types have \emph{strong reference semantics} +\see{reference-counting}. + +\paragraph{Pointer} +\label{actor-pointer} + +In a few instances, CAF uses \lstinline^strong_actor_ptr^ to refer to an actor +using \emph{strong reference semantics} \see{reference-counting} without +knowing the proper handle type. Pointers must be converted to a handle via +\lstinline^actor_cast^ \see{actor-cast} prior to sending messages. A +\lstinline^strong_actor_ptr^ can be \emph{null}. + +\subsubsection{Spawning} + +``Spawning'' an actor means to create and run a new actor. + +\subsubsection{Monitor} +\label{monitor} + +A monitored actor sends a down message~\see{down-message} to all actors +monitoring it as part of its termination. This allows actors to supervise other +actors and to take actions when one of the supervised actors fails, i.e., +terminates with a non-normal exit reason. + +\subsubsection{Link} +\label{link} + +A link is a bidirectional connection between two actors. Each actor sends an +exit message~\see{exit-message} to all of its links as part of its termination. +Unlike down messages, exit messages cause the receiving actor to terminate as +well when receiving a non-normal exit reason per default. This allows +developers to create a set of actors with the guarantee that either all or no +actors are alive. Actors can override the default handler to implement error +recovery strategies. + +\subsection{Experimental Features} + +Sections that discuss experimental features are highlighted with \experimental. +The API of such features is not stable. This means even minor updates to CAF +can come with breaking changes to the API or even remove a feature completely. +However, we encourage developers to extensively test such features and to start +discussions to uncover flaws, report bugs, or tweaking the API in order to +improve a feature or streamline it to cover certain use cases. diff -Nru actor-framework-0.13.2/doc/tex/make_index_rst.py actor-framework-0.16.3/doc/tex/make_index_rst.py --- actor-framework-0.13.2/doc/tex/make_index_rst.py 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/make_index_rst.py 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +# Generates the content for an index.rst file +# from the content of a manual.tex file + +import re +import sys + +def print_header(): + sys.stdout.write(".. include:: index_header.rst\n") + +def print_footer(): + sys.stdout.write("\n.. include:: index_footer.rst\n") + +part_rx = re.compile(r"\\part{(.+)}") +include_rx = re.compile(r"\\include{(.+)}") +print_header() +for line in sys.stdin: + m = part_rx.match(line) + if m: + sys.stdout.write("\n.. toctree::\n" + " :maxdepth: 2\n" + " :caption: ") + sys.stdout.write(m.group(1)) + sys.stdout.write("\n\n") + continue + m = include_rx.match(line) + if m: + sys.stdout.write(" ") + sys.stdout.write(m.group(1)) + sys.stdout.write("\n") +print_footer() diff -Nru actor-framework-0.13.2/doc/tex/ManagingGroupsOfWorkers.tex actor-framework-0.16.3/doc/tex/ManagingGroupsOfWorkers.tex --- actor-framework-0.13.2/doc/tex/ManagingGroupsOfWorkers.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/ManagingGroupsOfWorkers.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,92 @@ +\section{Managing Groups of Workers \experimental} +\label{worker-groups} + +When managing a set of workers, a central actor often dispatches requests to a +set of workers. For this purpose, the class \lstinline^actor_pool^ implements a +lightweight abstraction for managing a set of workers using a dispatching +policy. Unlike groups, pools usually own their workers. + +Pools are created using the static member function \lstinline^make^, which +takes either one argument (the policy) or three (number of workers, factory +function for workers, and dispatching policy). After construction, one can add +new workers via messages of the form \texttt{('SYS', 'PUT', worker)}, remove +workers with \texttt{('SYS', 'DELETE', worker)}, and retrieve the set of +workers as \lstinline^vector^ via \texttt{('SYS', 'GET')}. + +An actor pool takes ownership of its workers. When forced to quit, it sends an +exit messages to all of its workers, forcing them to quit as well. The pool +also monitors all of its workers. + +Pools do not cache messages, but enqueue them directly in a workers mailbox. +Consequently, a terminating worker loses all unprocessed messages. For more +advanced caching strategies, such as reliable message delivery, users can +implement their own dispatching policies. + +\subsection{Dispatching Policies} + +A dispatching policy is a functor with the following signature: + +\begin{lstlisting} +using uplock = upgrade_lock; +using policy = std::function; +\end{lstlisting} + +The argument \lstinline^guard^ is a shared lock that can be upgraded for unique +access if the policy includes a critical section. The second argument is a +vector containing all workers managed by the pool. The argument \lstinline^ptr^ +contains the full message as received by the pool. Finally, \lstinline^host^ is +the current scheduler context that can be used to enqueue workers into the +corresponding job queue. + +The actor pool class comes with a set predefined policies, accessible via +factory functions, for convenience. + +\begin{lstlisting} +actor_pool::policy actor_pool::round_robin(); +\end{lstlisting} + +This policy forwards incoming requests in a round-robin manner to workers. +There is no guarantee that messages are consumed, i.e., work items are lost if +the worker exits before processing all of its messages. + +\begin{lstlisting} +actor_pool::policy actor_pool::broadcast(); +\end{lstlisting} + +This policy forwards \emph{each} message to \emph{all} workers. Synchronous +messages to the pool will be received by all workers, but the client will only +recognize the first arriving response message---or error---and discard +subsequent messages. Note that this is not caused by the policy itself, but a +consequence of forwarding synchronous messages to more than one actor. + +\begin{lstlisting} +actor_pool::policy actor_pool::random(); +\end{lstlisting} + +This policy forwards incoming requests to one worker from the pool chosen +uniformly at random. Analogous to \lstinline^round_robin^, this policy does not +cache or redispatch messages. + +\begin{lstlisting} +using join = function; +using split = function>&, message&)>; +template +static policy split_join(join jf, split sf = ..., T init = T()); +\end{lstlisting} + +This policy models split/join or scatter/gather work flows, where a work item +is split into as many tasks as workers are available and then the individuals +results are joined together before sending the full result back to the client. + +The join function is responsible for ``glueing'' all result messages together +to create a single result. The function is called with the result object +(initialed using \lstinline^init^) and the current result messages from a +worker. + +The first argument of a split function is a mapping from actors (workers) to +tasks (messages). The second argument is the input message. The default split +function is a broadcast dispatching, sending each worker the original request. diff -Nru actor-framework-0.13.2/doc/tex/manual.tex actor-framework-0.16.3/doc/tex/manual.tex --- actor-framework-0.13.2/doc/tex/manual.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/manual.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,218 @@ +\documentclass[% + a4paper,% % DIN A4 + oneside,% % einseitiger Druck + 12pt,% % 12pt Schriftgröße +]{article} + +\usepackage[utf8]{inputenc} + +% include required packages + +\usepackage{array} +\usepackage{capt-of} +\usepackage{color} +\usepackage{float} +\usepackage{graphicx} +\usepackage{hyperref} +\usepackage{listings} +\usepackage{multicol} +\usepackage{tabularx} +\usepackage{url} +\usepackage{xifthen} +\usepackage{xspace} + +% font setup + +\usepackage[scaled=.90]{helvet} +\usepackage{cmbright} +\usepackage{courier} +\usepackage{txfonts} + +% paragraph settings + +\parindent 0pt +\parskip 8pt + +\pretolerance=150 +\tolerance=500 +\emergencystretch=\maxdimen +\hbadness=10000 + +\pagenumbering{arabic} + +% custom colors + +\definecolor{lightgrey}{rgb}{0.9,0.9,0.9} +\definecolor{lightblue}{rgb}{0,0,1} + +\definecolor{grey}{rgb}{0.5,0.5,0.5} +\definecolor{blue}{rgb}{0,0,1} +\definecolor{violet}{rgb}{0.5,0,0.5} + +\definecolor{darkred}{rgb}{0.5,0,0} +\definecolor{darkblue}{rgb}{0,0,0.5} +\definecolor{darkgreen}{rgb}{0,0.5,0} + +\input{tex/variables} + +\title{% +\texttt{\huge{\textbf{CAF}}}\\ +~\\ +The C++ Actor Framework\\ +~\\ +~\\ +~\\ +User Manual\\ +\normalsize{Version \cafrelease}\\ +~\\ +~\\ +\tiny SHA \cafsha +\vfill} + +\author{Dominik Charousset} + +\date{\today} + +% page setup +\setlength{\voffset}{-1in} +\setlength{\hoffset}{-0.75in} +\addtolength{\textwidth}{1.5in} +\addtolength{\textheight}{2in} +\setlength{\headheight}{15pt} + +% include paragraphs in TOC +\setcounter{tocdepth}{3} + +% more compact itemize +\newenvironment{itemize*}% + {\begin{itemize}% + \setlength{\itemsep}{0pt}% + \setlength{\parskip}{0pt}}% + {\end{itemize}} + +\begin{document} +\maketitle\thispagestyle{empty} +\pagestyle{empty} +\clearpage +\tableofcontents +\clearpage +\setcounter{page}{1} +\pagestyle{plain} + +% directory layout + +\graphicspath{{pdf/}} + +% custom commands + +\newcommand{\sref}[1]{\S\,\ref{#1}} +\newcommand{\see}[1]{(see~\sref{#1})} + +\newcommand{\singlefig}[3]{ + \begin{figure}[H] + \centering + \includegraphics[width=.6\columnwidth]{#1} + \caption{#2} + \label{#3} + \end{figure} +} + +\newcommand{\experimental}{ + {\color{darkred}\textsuperscript{experimental}} +} + + +\newcommand{\cppexample}[2][]{% +\ifthenelse{\isempty{#1}}% +{\lstinputlisting{../../examples/#2.cpp}}% +{\lstinputlisting[language=C++,linerange={#1}]{../../examples/#2.cpp}}% +} + +\newcommand{\iniexample}[2][]{% +\ifthenelse{\isempty{#1}}% +{\lstinputlisting[language=ini]{../../examples/#2.ini}}% +{\lstinputlisting[language=ini,linerange={#1}]{../../examples/#2.ini}}% +} + +\newcommand{\sourcefile}[2][]{% +\ifthenelse{\isempty{#1}}% +{\lstinputlisting[language=C++]{../../#2}}% +{\lstinputlisting[language=C++,linerange={#1}]{../../#2}}% +} + +% highlight for INI file syntax + +\lstdefinelanguage{ini}{% + basicstyle=\ttfamily\footnotesize,% +% columns=fullflexible,% + morecomment=[s][\color{blue}]{[}{]},% + morecomment=[l]{;},% + morecomment=[s]{<}{>},% + morestring=[b]",% + morestring=[b]',% + commentstyle=\color{violet},% + morekeywords={},% + otherkeywords={=,false,true},% + keywordstyle=\color{blue},% + stringstyle=\color{darkgreen},% +} + +% code listings setup +\lstset{% + language=C++,% + morekeywords={constexpr,nullptr,size_t,uint32_t,assert,override,final},% + basicstyle=\ttfamily\footnotesize,% + sensitive=true,% + keywordstyle=\color{blue},% + stringstyle=\color{darkgreen},% + commentstyle=\color{violet},% + showstringspaces=false,% + tabsize=2,% + frame=leftline, + rulecolor=\color{lightblue}, + xleftmargin=20pt, +} + +\lstset{ + numberstyle=\tiny, + numbers=left, + numbersep=10pt, + xleftmargin=20pt, + %framesep=4.5mm, + %framexleftmargin=2.5mm, + framexleftmargin=5pt, + framesep=15pt, + fillcolor=\color{lightgrey}, +} + +% content +\part{Core Library} +\include{tex/Introduction} +\include{tex/FirstSteps} +\include{tex/TypeInspection} +\include{tex/MessageHandlers} +\include{tex/Actors} +\include{tex/MessagePassing} +\include{tex/Scheduler} +\include{tex/Registry} +\include{tex/ReferenceCounting} +\include{tex/Error} +\include{tex/ConfiguringActorApplications} +\include{tex/Messages} +\include{tex/GroupCommunication} +\include{tex/ManagingGroupsOfWorkers} +\include{tex/Streaming} + +\part{I/O Library} +\include{tex/NetworkTransparency} +\include{tex/Brokers} +\include{tex/RemoteSpawn} + +\part{Appendix} +\include{tex/FAQ} +\include{tex/Utility} +\include{tex/CommonPitfalls} +\include{tex/UsingAout} +\include{tex/MigrationGuides} + +\end{document} diff -Nru actor-framework-0.13.2/doc/tex/MessageHandlers.tex actor-framework-0.16.3/doc/tex/MessageHandlers.tex --- actor-framework-0.13.2/doc/tex/MessageHandlers.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/MessageHandlers.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,113 @@ +\section{Message Handlers} +\label{message-handler} + +Actors can store a set of callbacks---usually implemented as lambda +expressions---using either \lstinline^behavior^ or \lstinline^message_handler^. +The former stores an optional timeout, while the latter is composable. + +\subsection{Definition and Composition} + +As the name implies, a \lstinline^behavior^ defines the response of an actor to +messages it receives. The optional timeout allows an actor to dynamically +change its behavior when not receiving message after a certain amount of time. + +\begin{lstlisting} +message_handler x1{ + [](int i) { /*...*/ }, + [](double db) { /*...*/ }, + [](int a, int b, int c) { /*...*/ } +}; +\end{lstlisting} + +In our first example, \lstinline^x1^ models a behavior accepting messages that +consist of either exactly one \lstinline^int^, or one \lstinline^double^, or +three \lstinline^int^ values. Any other message is not matched and gets +forwarded to the default handler \see{default-handler}. + +\begin{lstlisting} +message_handler x2{ + [](double db) { /*...*/ }, + [](double db) { /* - unrachable - */ } +}; +\end{lstlisting} + +Our second example illustrates an important characteristic of the matching +mechanism. Each message is matched against the callbacks in the order they are +defined. The algorithm stops at the first match. Hence, the second callback in +\lstinline^x2^ is unreachable. + +\begin{lstlisting} +message_handler x3 = x1.or_else(x2); +message_handler x4 = x2.or_else(x1); +\end{lstlisting} + +Message handlers can be combined using \lstinline^or_else^. This composition is +not commutative, as our third examples illustrates. The resulting message +handler will first try to handle a message using the left-hand operand and will +fall back to the right-hand operand if the former did not match. Thus, +\lstinline^x3^ behaves exactly like \lstinline^x1^. This is because the second +callback in \lstinline^x1^ will consume any message with a single +\lstinline^double^ and both callbacks in \lstinline^x2^ are thus unreachable. +The handler \lstinline^x4^ will consume messages with a single +\lstinline^double^ using the first callback in \lstinline^x2^, essentially +overriding the second callback in \lstinline^x1^. + +\clearpage +\subsection{Atoms} +\label{atom} + +Defining message handlers in terms of callbacks is convenient, but requires a +simple way to annotate messages with meta data. Imagine an actor that provides +a mathematical service for integers. It receives two integers, performs a +user-defined operation and returns the result. Without additional context, the +actor cannot decide whether it should multiply or add the integers. Thus, the +operation must be encoded into the message. The Erlang programming language +introduced an approach to use non-numerical constants, so-called +\textit{atoms}, which have an unambiguous, special-purpose type and do not have +the runtime overhead of string constants. + +Atoms in CAF are mapped to integer values at compile time. This mapping is +guaranteed to be collision-free and invertible, but limits atom literals to ten +characters and prohibits special characters. Legal characters are +\lstinline^_0-9A-Za-z^ and the whitespace character. Atoms are created using +the \lstinline^constexpr^ function \lstinline^atom^, as the following example +illustrates. + +\begin{lstlisting} +atom_value a1 = atom("add"); +atom_value a2 = atom("multiply"); +\end{lstlisting} + +\textbf{Warning}: The compiler cannot enforce the restrictions at compile time, +except for a length check. The assertion \lstinline^atom("!?") != atom("?!")^ +is not true, because each invalid character translates to a whitespace +character. + +While the \lstinline^atom_value^ is computed at compile time, it is not +uniquely typed and thus cannot be used in the signature of a callback. To +accomplish this, CAF offers compile-time \emph{atom constants}. + +\begin{lstlisting} +using add_atom = atom_constant; +using multiply_atom = atom_constant; +\end{lstlisting} + +Using these constants, we can now define message passing interfaces in a +convenient way: + +\begin{lstlisting} +behavior do_math{ + [](add_atom, int a, int b) { + return a + b; + }, + [](multiply_atom, int a, int b) { + return a * b; + } +}; + +// caller side: send(math_actor, add_atom::value, 1, 2) +\end{lstlisting} + +Atom constants define a static member \lstinline^value^. Please note that this +static \lstinline^value^ member does \emph{not} have the type +\lstinline^atom_value^, unlike \lstinline^std::integral_constant^ for example. diff -Nru actor-framework-0.13.2/doc/tex/MessagePassing.tex actor-framework-0.16.3/doc/tex/MessagePassing.tex --- actor-framework-0.13.2/doc/tex/MessagePassing.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/MessagePassing.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,273 @@ +\section{Message Passing} +\label{message-passing} + +Message passing in CAF is always asynchronous. Further, CAF neither guarantees +message delivery nor message ordering in a distributed setting. CAF uses TCP +per default, but also enables nodes to send messages to other nodes without +having a direct connection. In this case, messages are forwarded by +intermediate nodes and can get lost if one of the forwarding nodes fails. +Likewise, forwarding paths can change dynamically and thus cause messages to +arrive out of order. + +The messaging layer of CAF has three primitives for sending messages: +\lstinline^send^, \lstinline^request^, and \lstinline^delegate^. The former +simply enqueues a message to the mailbox the receiver. The latter two are +discussed in more detail in \sref{request} and \sref{delegate}. + +\subsection{Structure of Mailbox Elements} +\label{mailbox-element} + +When enqueuing a message to the mailbox of an actor, CAF wraps the content of +the message into a \lstinline^mailbox_element^ (shown below) to add meta data +and processing paths. + +\singlefig{mailbox_element}{UML class diagram for \lstinline^mailbox_element^}{mailbox_element} + +The sender is stored as a \lstinline^strong_actor_ptr^ \see{actor-pointer} and +denotes the origin of the message. The message ID is either 0---invalid---or a +positive integer value that allows the sender to match a response to its +request. The \lstinline^stages^ vector stores the path of the message. Response +messages, i.e., the returned values of a message handler, are sent to +\lstinline^stages.back()^ after calling \lstinline^stages.pop_back()^. This +allows CAF to build pipelines of arbitrary size. If no more stage is left, the +response reaches the sender. Finally, \lstinline^content()^ grants access to +the type-erased tuple storing the message itself. + +Mailbox elements are created by CAF automatically and are usually invisible to +the programmer. However, understanding how messages are processed internally +helps understanding the behavior of the message passing layer. + +It is worth mentioning that CAF usually wraps the mailbox element and its +content into a single object in order to reduce the number of memory +allocations. + +\subsection{Copy on Write} +\label{copy-on-write} + +CAF allows multiple actors to implicitly share message contents, as long as no +actor performs writes. This allows groups~\see{groups} to send the same content +to all subscribed actors without any copying overhead. + +Actors copy message contents whenever other actors hold references to it and if +one or more arguments of a message handler take a mutable reference. + +\subsection{Requirements for Message Types} + +Message types in CAF must meet the following requirements: + +\begin{enumerate} +\item Serializable or inspectable \see{type-inspection} +\item Default constructible +\item Copy constructible +\end{enumerate} + +A type is serializable if it provides free function \lstinline^serialize(Serializer&, T&)^ or \lstinline^serialize(Serializer&, T&, const unsigned int)^. Accordingly, a type is inspectable if it provides a free function \lstinline^inspect(Inspector&, T&)^. + +Requirement 2 is a consequence of requirement 1, because CAF needs to be able +to create an object of a type before it can call \lstinline^serialize^ or +\lstinline^inspect^ on it. Requirement 3 allows CAF to implement Copy on +Write~\see{copy-on-write}. + +\subsection{Default and System Message Handlers} +\label{special-handler} + +CAF has three system-level message types (\lstinline^down_msg^, +\lstinline^exit_msg^, and \lstinline^error^) that all actor should handle +regardless of there current state. Consequently, event-based actors handle such +messages in special-purpose message handlers. Additionally, event-based actors +have a fallback handler for unmatched messages. Note that blocking actors have +neither of those special-purpose handlers \see{blocking-actor}. + +\subsubsection{Down Handler} +\label{down-message} + +Actors can monitor the lifetime of other actors by calling \lstinline^self->monitor(other)^. This will cause the runtime system of CAF to send a \lstinline^down_msg^ for \lstinline^other^ if it dies. Actors drop down messages unless they provide a custom handler via \lstinline^set_down_handler(f)^, where \lstinline^f^ is a function object with signature \lstinline^void (down_msg&)^ or \lstinline^void (scheduled_actor*, down_msg&)^. The latter signature allows users to implement down message handlers as free function. + +\subsubsection{Exit Handler} +\label{exit-message} + +Bidirectional monitoring with a strong lifetime coupling is established by calling \lstinline^self->link_to(other)^. This will cause the runtime to send an \lstinline^exit_msg^ if either \lstinline^this^ or \lstinline^other^ dies. Per default, actors terminate after receiving an \lstinline^exit_msg^ unless the exit reason is \lstinline^exit_reason::normal^. This mechanism propagates failure states in an actor system. Linked actors form a sub system in which an error causes all actors to fail collectively. Actors can override the default handler via \lstinline^set_exit_handler(f)^, where \lstinline^f^ is a function object with signature \lstinline^void (exit_message&)^ or \lstinline^void (scheduled_actor*, exit_message&)^. + +\subsubsection{Error Handler} +\label{error-message} + +Actors send error messages to others by returning an \lstinline^error^ \see{error} from a message handler. Similar to exit messages, error messages usually cause the receiving actor to terminate, unless a custom handler was installed via \lstinline^set_error_handler(f)^, where \lstinline^f^ is a function object with signature \lstinline^void (error&)^ or \lstinline^void (scheduled_actor*, error&)^. Additionally, \lstinline^request^ accepts an error handler as second argument to handle errors for a particular request~\see{error-response}. The default handler is used as fallback if \lstinline^request^ is used without error handler. + +\subsubsection{Default Handler} +\label{default-handler} + +The default handler is called whenever the behavior of an actor did not match +the input. Actors can change the default handler by calling +\lstinline^set_default_handler^. The expected signature of the function object +is \lstinline^result (scheduled_actor*, message_view&)^, whereas the +\lstinline^self^ pointer can again be omitted. The default handler can return a +response message or cause the runtime to \emph{skip} the input message to allow +an actor to handle it in a later state. CAF provides the following built-in +implementations: \lstinline^reflect^, \lstinline^reflect_and_quit^, +\lstinline^print_and_drop^, \lstinline^drop^, and \lstinline^skip^. The former +two are meant for debugging and testing purposes and allow an actor to simply +return an input. The next two functions drop unexpected messages with or +without printing a warning beforehand. Finally, \lstinline^skip^ leaves the +input message in the mailbox. The default is \lstinline^print_and_drop^. + +\subsection{Requests} +\label{request} + +A main feature of CAF is its ability to couple input and output types via the +type system. For example, a \lstinline^typed_actor::with>^ +essentially behaves like a function. It receives a single \lstinline^int^ as +input and responds with another \lstinline^int^. CAF embraces this functional +take on actors by simply creating response messages from the result of message +handlers. This allows CAF to match \emph{request} to \emph{response} messages +and to provide a convenient API for this style of communication. + +\subsubsection{Sending Requests and Handling Responses} +\label{handling-response} + +Actors send request messages by calling \lstinline^request(receiver, timeout, content...)^. This function returns an intermediate object that allows an actor to set a one-shot handler for the response message. Event-based actors can use either \lstinline^request(...).then^ or \lstinline^request(...).await^. The former multiplexes the one-shot handler with the regular actor behavior and handles requests as they arrive. The latter suspends the regular actor behavior until all awaited responses arrive and handles requests in LIFO order. Blocking actors always use \lstinline^request(...).receive^, which blocks until the one-shot handler was called. Actors receive a \lstinline^sec::request_timeout^ \see{sec} error message~\see{error-message} if a timeout occurs. Users can set the timeout to \lstinline^infinite^ for unbound operations. This is only recommended if the receiver is running locally. + +In our following example, we use the simple cell actors shown below as +communication endpoints. + +\cppexample[20-37]{message_passing/request} + +The first part of the example illustrates how event-based actors can use either +\lstinline^then^ or \lstinline^await^. + +\cppexample[39-51]{message_passing/request} + +\clearpage + +The second half of the example shows a blocking actor making use of +\lstinline^receive^. Note that blocking actors have no special-purpose handler +for error messages and therefore are required to pass a callback for error +messages when handling response messages. + +\cppexample[53-64]{message_passing/request} + +We spawn five cells and assign the values 0, 1, 4, 9, and 16. + +\cppexample[67-69]{message_passing/request} + +When passing the \lstinline^cells^ vector to our three different +implementations, we observe three outputs. Our \lstinline^waiting_testee^ actor +will always print: + +{\footnotesize\begin{verbatim} +cell #9 -> 16 +cell #8 -> 9 +cell #7 -> 4 +cell #6 -> 1 +cell #5 -> 0 +\end{verbatim}} + +This is because \lstinline^await^ puts the one-shots handlers onto a stack and +enforces LIFO order by re-ordering incoming response messages. + +The \lstinline^multiplexed_testee^ implementation does not print its results in +a predicable order. Response messages arrive in arbitrary order and are handled +immediately. + +Finally, the \lstinline^blocking_testee^ implementation will always print: + +{\footnotesize\begin{verbatim} +cell #5 -> 0 +cell #6 -> 1 +cell #7 -> 4 +cell #8 -> 9 +cell #9 -> 16 +\end{verbatim}} + +Both event-based approaches send all requests, install a series of one-shot +handlers, and then return from the implementing function. In contrast, the +blocking function waits for a response before sending another request. + +\clearpage +\subsubsection{Error Handling in Requests} +\label{error-response} + +Requests allow CAF to unambiguously correlate request and response messages. +This is also true if the response is an error message. Hence, CAF allows to +add an error handler as optional second parameter to \lstinline^then^ and +\lstinline^await^ (this parameter is mandatory for \lstinline^receive^). If no +such handler is defined, the default error handler \see{error-message} is used +as a fallback in scheduled actors. + +As an example, we consider a simple divider that returns an error on a division +by zero. This examples uses a custom error category~\see{error}. + +\cppexample[19-25,35-48]{message_passing/divider} + +When sending requests to the divider, we use a custom error handlers to report +errors to the user. + +\cppexample[68-77]{message_passing/divider} + +\clearpage +\subsection{Delaying Messages} +\label{delay-message} + +Messages can be delayed by using the function \lstinline^delayed_send^, as +illustrated in the following time-based loop example. + +\cppexample[56-75]{message_passing/dancing_kirby} + +\clearpage +\subsection{Delegating Messages} +\label{delegate} + +Actors can transfer responsibility for a request by using \lstinline^delegate^. +This enables the receiver of the delegated message to reply as usual---simply +by returning a value from its message handler---and the original sender of the +message will receive the response. The following diagram illustrates request +delegation from actor B to actor C. + +\begin{footnotesize} +\begin{verbatim} + A B C + | | | + | ---(request)---> | | + | | ---(delegate)--> | + | X |---\ + | | | compute + | | | result + | |<--/ + | <-------------(reply)-------------- | + | X + |---\ + | | handle + | | response + |<--/ + | + X +\end{verbatim} +\end{footnotesize} + +Returning the result of \lstinline^delegate(...)^ from a message handler, as +shown in the example below, suppresses the implicit response message and allows +the compiler to check the result type when using statically typed actors. + +\cppexample[15-42]{message_passing/delegating} + +\subsection{Response Promises} +\label{promise} + +Response promises allow an actor to send and receive other messages prior to +replying to a particular request. Actors create a response promise using +\lstinline^self->make_response_promise()^, where \lstinline^Ts^ is a +template parameter pack describing the promised return type. Dynamically typed +actors simply call \lstinline^self->make_response_promise()^. After retrieving +a promise, an actor can fulfill it by calling the member function +\lstinline^deliver(...)^, as shown in the following example. + +\cppexample[18-43]{message_passing/promises} + +\clearpage +\subsection{Message Priorities} + +By default, all messages have the default priority, i.e., +\lstinline^message_priority::normal^. Actors can send urgent messages by +setting the priority explicitly: +\lstinline^send(dst,...)^. Urgent messages are put into +a different queue of the receiver's mailbox. Hence, long wait delays can be +avoided for urgent communication. diff -Nru actor-framework-0.13.2/doc/tex/Messages.tex actor-framework-0.16.3/doc/tex/Messages.tex --- actor-framework-0.13.2/doc/tex/Messages.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/Messages.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,250 @@ +\section{Type-Erased Tuples, Messages and Message Views} +\label{message} + +Messages in CAF are stored in type-erased tuples. The actual message type +itself is usually hidden, as actors use pattern matching to decompose messages +automatically. However, the classes \lstinline^message^ and +\lstinline^message_builder^ allow more advanced use cases than only sending +data from one actor to another. + +The interface \lstinline^type_erased_tuple^ encapsulates access to arbitrary +data. This data can be stored on the heap or on the stack. A +\lstinline^message^ is a type-erased tuple that is always heap-allocated and +uses copy-on-write semantics. When dealing with "plain" type-erased tuples, +users are required to check if a tuple is referenced by others via +\lstinline^type_erased_tuple::shared^ before modifying its content. + +The convenience class \lstinline^message_view^ holds a reference to either a +stack-located \lstinline^type_erased_tuple^ or a \lstinline^message^. The +content of the data can be access via \lstinline^message_view::content^ in both +cases, which returns a \lstinline^type_erased_tuple&^. The content of the view +can be forced into a message object by calling +\lstinline^message_view::move_content_to_message^. This member function either +returns the stored message object or moves the content of a stack-allocated +tuple into a new message. + +\subsection{RTTI and Type Numbers} + +All builtin types in CAF have a non-zero 6-bit \emph{type number}. All +user-defined types are mapped to 0. When querying the run-time type information +(RTTI) for individual message or tuple elements, CAF returns a pair consisting +of an integer and a pointer to \lstinline^std::type_info^. The first value is +the 6-bit type number. If the type number is non-zero, the second value is a +pointer to the C++ type info, otherwise the second value is null. Additionally, +CAF generates 32 bit \emph{type tokens}. These tokens are \emph{type hints} +that summarizes all types in a type-erased tuple. Two type-erased tuples are of +different type if they have different type tokens (the reverse is not true). + +\clearpage +\subsection{Class \lstinline^type_erased_tuple^} + +\textbf{Note}: Calling modifiers on a shared type-erased tuple is undefined +behavior. + +\begin{center} +\begin{tabular}{ll} + \textbf{Types} & ~ \\ + \hline + \lstinline^rtti_pair^ & \lstinline^std::pair^ \\ + \hline + ~ & ~ \\ \textbf{Observers} & ~ \\ + \hline + \lstinline^bool empty()^ & Returns whether this message is empty. \\ + \hline + \lstinline^size_t size()^ & Returns the size of this message. \\ + \hline + \lstinline^rtti_pair type(size_t pos)^ & Returns run-time type information for the nth element. \\ + \hline + \lstinline^error save(serializer& x)^ & Writes the tuple to \lstinline^x^. \\ + \hline + \lstinline^error save(size_t n, serializer& x)^ & Writes the nth element to \lstinline^x^. \\ + \hline + \lstinline^const void* get(size_t n)^ & Returns a const pointer to the nth element. \\ + \hline + \lstinline^std::string stringify()^ & Returns a string representation of the tuple. \\ + \hline + \lstinline^std::string stringify(size_t n)^ & Returns a string representation of the nth element. \\ + \hline + \lstinline^bool matches(size_t n, rtti_pair)^ & Checks whether the nth element has given type. \\ + \hline + \lstinline^bool shared()^ & Checks whether more than one reference to the data exists. \\ + \hline + \lstinline^bool match_element(size_t n)^ & Checks whether element \lstinline^n^ has type \lstinline^T^. \\ + \hline + \lstinline^bool match_elements()^ & Checks whether this message has the types \lstinline^Ts...^. \\ + \hline + \lstinline^const T& get_as(size_t n)^ & Returns a const reference to the nth element. \\ + \hline + ~ & ~ \\ \textbf{Modifiers} & ~ \\ + \hline + \lstinline^void* get_mutable(size_t n)^ & Returns a mutable pointer to the nth element. \\ + \hline + \lstinline^T& get_mutable_as(size_t n)^ & Returns a mutable reference to the nth element. \\ + \hline + \lstinline^void load(deserializer& x)^ & Reads the tuple from \lstinline^x^. \\ + \hline +\end{tabular} +\end{center} + +\subsection{Class \lstinline^message^} + +The class \lstinline^message^ includes all member functions of +\lstinline^type_erased_tuple^. However, calling modifiers is always guaranteed +to be safe. A \lstinline^message^ automatically detaches its content by copying +it from the shared data on mutable access. The class further adds the following +member functions over \lstinline^type_erased_tuple^. Note that +\lstinline^apply^ only detaches the content if a callback takes mutable +references as arguments. + +\begin{center} +\begin{tabular}{ll} + \textbf{Observers} & ~ \\ + \hline + \lstinline^message drop(size_t n)^ & Creates a new message with all but the first \lstinline^n^ values. \\ + \hline + \lstinline^message drop_right(size_t n)^ & Creates a new message with all but the last \lstinline^n^ values. \\ + \hline + \lstinline^message take(size_t n)^ & Creates a new message from the first \lstinline^n^ values. \\ + \hline + \lstinline^message take_right(size_t n)^ & Creates a new message from the last \lstinline^n^ values. \\ + \hline + \lstinline^message slice(size_t p, size_t n)^ & Creates a new message from \lstinline^[p, p + n)^. \\ + \hline + \lstinline^message extract(message_handler)^ & See \sref{extract}. \\ + \hline + \lstinline^message extract_opts(...)^ & See \sref{extract-opts}. \\ + \hline + ~ & ~ \\ \textbf{Modifiers} & ~ \\ + \hline + \lstinline^optional apply(message_handler f)^ & Returns \lstinline^f(*this)^. \\ + \hline + ~ & ~ \\ \textbf{Operators} & ~ \\ + \hline + \lstinline^message operator+(message x, message y)^ & Concatenates \lstinline^x^ and \lstinline^y^. \\ + \hline + \lstinline^message& operator+=(message& x, message y)^ & Concatenates \lstinline^x^ and \lstinline^y^. \\ + \hline +\end{tabular} +\end{center} + +\clearpage +\subsection{Class \texttt{message\_builder}} + +\begin{center} +\begin{tabular}{ll} + \textbf{Constructors} & ~ \\ + \hline + \lstinline^(void)^ & Creates an empty message builder. \\ + \hline + \lstinline^(Iter first, Iter last)^ & Adds all elements from range \lstinline^[first, last)^. \\ + \hline + ~ & ~ \\ \textbf{Observers} & ~ \\ + \hline + \lstinline^bool empty()^ & Returns whether this message is empty. \\ + \hline + \lstinline^size_t size()^ & Returns the size of this message. \\ + \hline + \lstinline^message to_message( )^ & Converts the buffer to an actual message object. \\ + \hline + \lstinline^append(T val)^ & Adds \lstinline^val^ to the buffer. \\ + \hline + \lstinline^append(Iter first, Iter last)^ & Adds all elements from range \lstinline^[first, last)^. \\ + \hline + \lstinline^message extract(message_handler)^ & See \sref{extract}. \\ + \hline + \lstinline^message extract_opts(...)^ & See \sref{extract-opts}. \\ + \hline + ~ & ~ \\ \textbf{Modifiers} & ~ \\ + \hline + \lstinline^optional^ \lstinline^apply(message_handler f)^ & Returns \lstinline^f(*this)^. \\ + \hline + \lstinline^message move_to_message()^ & Transfers ownership of its data to the new message. \\ + \hline +\end{tabular} +\end{center} + +\clearpage +\subsection{Extracting} +\label{extract} + +The member function \lstinline^message::extract^ removes matched elements from +a message. x Messages are filtered by repeatedly applying a message handler to +the greatest remaining slice, whereas slices are generated in the sequence $[0, +size)$, $[0, size-1)$, $...$, $[1, size-1)$, $...$, $[size-1, size)$. Whenever +a slice is matched, it is removed from the message and the next slice starts at +the same index on the reduced message. + +For example: + +\begin{lstlisting} +auto msg = make_message(1, 2.f, 3.f, 4); +// remove float and integer pairs +auto msg2 = msg.extract({ + [](float, float) { }, + [](int, int) { } +}); +assert(msg2 == make_message(1, 4)); +\end{lstlisting} + +Step-by-step explanation: + +\begin{itemize} + \item Slice 1: \lstinline^(1, 2.f, 3.f, 4)^, no match + \item Slice 2: \lstinline^(1, 2.f, 3.f)^, no match + \item Slice 3: \lstinline^(1, 2.f)^, no match + \item Slice 4: \lstinline^(1)^, no match + \item Slice 5: \lstinline^(2.f, 3.f, 4)^, no match + \item Slice 6: \lstinline^(2.f, 3.f)^, \emph{match}; new message is \lstinline^(1, 4)^ + \item Slice 7: \lstinline^(4)^, no match +\end{itemize} + +Slice 7 is \lstinline^(4)^, i.e., does not contain the first element, because +the match on slice 6 occurred at index position 1. The function +\lstinline^extract^ iterates a message only once, from left to right. The +returned message contains the remaining, i.e., unmatched, elements. + +\clearpage +\subsection{Extracting Command Line Options} +\label{extract-opts} + +The class \lstinline^message^ also contains a convenience interface to +\lstinline^extract^ for parsing command line options: the member function +\lstinline^extract_opts^. + +\begin{lstlisting} +int main(int argc, char** argv) { + uint16_t port; + string host = "localhost"; + auto res = message_builder(argv + 1, argv + argc).extract_opts({ + {"port,p", "set port", port}, + {"host,H", "set host (default: localhost)", host}, + {"verbose,v", "enable verbose mode"} + }); + if (! res.error.empty()) { + // read invalid CLI arguments + cerr << res.error << endl; + return 1; + } + if (res.opts.count("help") > 0) { + // CLI arguments contained "-h", "--help", or "-?" (builtin); + cout << res.helptext << endl; + return 0; + } + if (! res.remainder.empty()) { + // res.remainder stors all extra arguments that weren't consumed + } + if (res.opts.count("verbose") > 0) { + // enable verbose mode + } + // ... +} + +/* +Output of ./program_name -h: + +Allowed options: + -p [--port] arg : set port + -H [--host] arg : set host (default: localhost) + -v [--verbose] : enable verbose mode +*/ +\end{lstlisting} diff -Nru actor-framework-0.13.2/doc/tex/MigrationGuides.tex actor-framework-0.16.3/doc/tex/MigrationGuides.tex --- actor-framework-0.13.2/doc/tex/MigrationGuides.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/MigrationGuides.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,183 @@ +\section{Migration Guides} + +The guides in this section document all possibly breaking changes in the +library for that last versions of CAF. + +\subsection{0.8 to 0.9} + +Version 0.9 included a lot of changes and improvements in its implementation, +but it also made breaking changes to the API. + +\paragraph{\lstinline^self^ has been removed} + +~ + +This is the biggest library change since the initial release. The major problem +with this keyword-like identifier is that it must have a single type as it's +implemented as a thread-local variable. Since there are so many different kinds +of actors (event-based or blocking, untyped or typed), \lstinline^self^ needs +to perform type erasure at some point, rendering it ultimately useless. Instead +of a thread-local pointer, you can now use the first argument in functor-based +actors to "catch" the self pointer with proper type information. + +\paragraph{\lstinline^actor_ptr^ has been replaced} + +~ + +CAF now distinguishes between handles to actors, i.e., +\lstinline^typed_actor<...>^ or simply \lstinline^actor^, and \emph{addresses} +of actors, i.e., \lstinline^actor_addr^. The reason for this change is that +each actor has a logical, (network-wide) unique address, which is used by the +networking layer of CAF. Furthermore, for monitoring or linking, the address +is all you need. However, the address is not sufficient for sending messages, +because it doesn't have any type information. The function +\lstinline^current_sender()^ now returns the \emph{address} of the sender. This +means that previously valid code such as \lstinline^send(current_sender(),...)^ +will cause a compiler error. However, the recommended way of replying to +messages is to return the result from the message handler. + +\paragraph{The API for typed actors is now similar to the API for untyped actors} + +~ + +The APIs of typed and untyped actors have been harmonized. Typed actors can now +be published in the network and also use all operations untyped actors can. + +\clearpage +\subsection{0.9 to 0.10 (\texttt{libcppa} to CAF)} + +The first release under the new name CAF is an overhaul of the entire library. +Some classes have been renamed or relocated, others have been removed. The +purpose of this refactoring was to make the library easier to grasp and to make +its API more consistent. All classes now live in the namespace \texttt{caf} and +all headers have the top level folder \texttt{caf} instead of \texttt{cppa}. +For example, \texttt{cppa/actor.hpp} becomes \texttt{caf/actor.hpp}. Further, +the convenience header to get all parts of the user API is now +\texttt{"caf/all.hpp"}. The networking has been separated from the core +library. To get the networking components, simply include +\texttt{caf/io/all.hpp} and use the namespace \lstinline^caf::io^. + +Version 0.10 still includes the header \texttt{cppa/cppa.hpp} to make the +transition process for users easier and to not break existing code right away. +The header defines the namespace \texttt{cppa} as an alias for \texttt{caf}. +Furthermore, it provides implementations or type aliases for renamed or removed +classes such as \lstinline^cow_tuple^. You won't get any warning about deprecated +headers with 0.10. However, we will add this warnings in the next library +version and remove deprecated code eventually. + +Even when using the backwards compatibility header, the new library has +breaking changes. For instance, guard expressions have been removed entirely. +The reasoning behind this decision is that we already have projections to +modify the outcome of a match. Guard expressions add little expressive power to +the library but a whole lot of code that is hard to maintain in the long run +due to its complexity. Using projections to not only perform type conversions +but also to restrict values is the more natural choice. + +\lstinline^any_tuple => message^ + +This type is only being used to pass a message from one actor to another. +Hence, \lstinline^message^ is the logical name. + +\lstinline^partial_function => message_handler^ + +Technically, it still is a partial function. However, we wanted to put +emphasize on its use case. + +\lstinline^cow_tuple => X^ + +We want to provide a streamlined, simple API. Shipping a full tuple abstraction +with the library does not fit into this philosophy. The removal of +\lstinline^cow_tuple^ implies the removal of related functions such as +\lstinline^tuple_cast^. + +\lstinline^cow_ptr => X^ + +This pointer class is an implementation detail of \lstinline^message^ and +should not live in the global namespace in the first place. It also had the +wrong name, because it is intrusive. + +\lstinline^X => message_builder^ + +This new class can be used to create messages dynamically. For example, the +content of a vector can be used to create a message using a series of +\lstinline^append^ calls. + +\begin{lstlisting} +accept_handle, connection_handle, publish, remote_actor, +max_msg_size, typed_publish, typed_remote_actor, publish_local_groups, +new_connection_msg, new_data_msg, connection_closed_msg, acceptor_closed_msg +\end{lstlisting} + +These classes concern I/O functionality and have thus been moved to +\lstinline^caf::io^ + +\subsection{0.10 to 0.11} + +Version 0.11 introduced new, optional components. The core library itself, +however, mainly received optimizations and bugfixes with one exception: the +member function \lstinline^on_exit^ is no longer virtual. You can still provide +it to define a custom exit handler, but you must not use \lstinline^override^. + +\subsection{0.11 to 0.12} + +Version 0.12 removed two features: + +\begin{itemize} +\item Type names are no longer demangled automatically. Hence, users must + explicitly pass the type name as first argument when using + \lstinline^announce^, i.e., \lstinline^announce(...)^ becomes + \lstinline^announce("my_class", ...)^. +\item Synchronous send blocks no longer support \lstinline^continue_with^. This + feature has been removed without substitution. +\end{itemize} + +\subsection{0.12 to 0.13} + +This release removes the (since 0.9 deprecated) \lstinline^cppa^ headers and +deprecates all \lstinline^*_send_tuple^ versions (simply use the function +without \lstinline^_tuple^ suffix). \lstinline^local_actor::on_exit^ once again +became virtual. + +In case you were using the old \lstinline^cppa::options_description^ API, you +can migrate to the new API based on \lstinline^extract^ \see{extract-opts}. + +Most importantly, version 0.13 slightly changes \lstinline^last_dequeued^ and +\lstinline^last_sender^. Both functions will now cause undefined behavior +(dereferencing a \lstinline^nullptr^) instead of returning dummy values when +accessed from outside a callback or after forwarding the current message. +Besides, these function names were not a good choice in the first place, since +``last'' implies accessing data received in the past. As a result, both +functions are now deprecated. Their replacements are named +\lstinline^current_message^ and \lstinline^current_sender^ \see{interface}. + +\subsection{0.13 to 0.14} + +The function \lstinline^timed_sync_send^ has been removed. It offered an +alternative way of defining message handlers, which is inconsistent with the +rest of the API. + +The policy classes \lstinline^broadcast^, \lstinline^random^, and +\lstinline^round_robin^ in \lstinline^actor_pool^ were removed and replaced by +factory functions using the same name. + +\clearpage +\subsection{0.14 to 0.15} + +Version 0.15 replaces the singleton-based architecture with +\lstinline^actor_system^. Most of the free functions in namespace +\lstinline^caf^ are now member functions of \lstinline^actor_system^ +\see{actor-system}. Likewise, most functions in namespace \lstinline^caf::io^ +are now member functions of \lstinline^middleman^ \see{middleman}. The +structure of CAF applications has changed fundamentally with a focus on +configurability. Setting and fine-tuning the scheduler, changing parameters of +the middleman, etc. is now bundled in the class +\lstinline^actor_system_config^. The new configuration mechanism is also easily +extensible. + +Patterns are now limited to the simple notation, because the advanced features +(1) are not implementable for statically typed actors, (2) are not portable to +Windows/MSVC, and (3) drastically impact compile times. Dropping this +functionality also simplifies the implementation and improves performance. + +The \lstinline^blocking_api^ flag has been removed. All variants of +\emph{spawn} now auto-detect blocking actors. diff -Nru actor-framework-0.13.2/doc/tex/NetworkTransparency.tex actor-framework-0.16.3/doc/tex/NetworkTransparency.tex --- actor-framework-0.13.2/doc/tex/NetworkTransparency.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/NetworkTransparency.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,157 @@ +\section{Middleman} +\label{middleman} + +The middleman is the main component of the I/O module and enables distribution. +It transparently manages proxy actor instances representing remote actors, +maintains connections to other nodes, and takes care of serialization of +messages. Applications install a middleman by loading +\lstinline^caf::io::middleman^ as module~\see{system-config}. Users can include +\lstinline^"caf/io/all.hpp"^ to get access to all public classes of the I/O +module. + +\subsection{Class \texttt{middleman}} + +\begin{center} +\begin{tabular}{ll} + \textbf{Remoting} & ~ \\ + \hline + \lstinline^expected open(uint16, const char*, bool)^ & See~\sref{remoting}. \\ + \hline + \lstinline^expected publish(T, uint16, const char*, bool)^ & See~\sref{remoting}. \\ + \hline + \lstinline^expected unpublish(T x, uint16)^ & See~\sref{remoting}. \\ + \hline + \lstinline^expected connect(std::string host, uint16_t port)^ & See~\sref{remoting}. \\ + \hline + \lstinline^expected remote_actor(string, uint16)^ & See~\sref{remoting}. \\ + \hline + \lstinline^expected spawn_broker(F fun, ...)^ & See~\sref{broker}. \\ + \hline + \lstinline^expected spawn_client(F, string, uint16, ...)^ & See~\sref{broker}. \\ + \hline + \lstinline^expected spawn_server(F, uint16, ...)^ & See~\sref{broker}. \\ + \hline +\end{tabular} +\end{center} + +\subsection{Publishing and Connecting} +\label{remoting} + +The member function \lstinline^publish^ binds an actor to a given port, thereby +allowing other nodes to access it over the network. + +\begin{lstlisting} +template +expected middleman::publish(T x, uint16_t port, + const char* in = nullptr, + bool reuse_addr = false); +\end{lstlisting} + +The first argument is a handle of type \lstinline^actor^ or +\lstinline^typed_actor<...>^. The second argument denotes the TCP port. The OS +will pick a random high-level port when passing 0. The third parameter +configures the listening address. Passing null will accept all incoming +connections (\lstinline^INADDR_ANY^). Finally, the flag \lstinline^reuse_addr^ +controls the behavior when binding an IP address to a port, with the same +semantics as the BSD socket flag \lstinline^SO_REUSEADDR^. For example, with +\lstinline^reuse_addr = false^, binding two sockets to 0.0.0.0:42 and +10.0.0.1:42 will fail with \texttt{EADDRINUSE} since 0.0.0.0 includes 10.0.0.1. +With \lstinline^reuse_addr = true^ binding would succeed because 10.0.0.1 and +0.0.0.0 are not literally equal addresses. + +The member function returns the bound port on success. Otherwise, an +\lstinline^error^ \see{error} is returned. + +\begin{lstlisting} +template +expected middleman::unpublish(T x, uint16_t port = 0); +\end{lstlisting} + +The member function \lstinline^unpublish^ allows actors to close a port +manually. This is performed automatically if the published actor terminates. +Passing 0 as second argument closes all ports an actor is published to, +otherwise only one specific port is closed. + +The function returns an \lstinline^error^ \see{error} if the actor was not +bound to given port. + +\clearpage +\begin{lstlisting} +template +expected middleman::remote_actor(std::string host, uint16_t port); +\end{lstlisting} + +After a server has published an actor with \lstinline^publish^, clients can +connect to the published actor by calling \lstinline^remote_actor^: + +\begin{lstlisting} +// node A +auto ping = spawn(ping); +system.middleman().publish(ping, 4242); + +// node B +auto ping = system.middleman().remote_actor("node A", 4242); +if (! ping) { + cerr << "unable to connect to node A: " + << system.render(ping.error()) << std::endl; +} else { + self->send(*ping, ping_atom::value); +} +\end{lstlisting} + +There is no difference between server and client after the connection phase. +Remote actors use the same handle types as local actors and are thus fully +transparent. + +The function pair \lstinline^open^ and \lstinline^connect^ allows users to +connect CAF instances without remote actor setup. The function +\lstinline^connect^ returns a \lstinline^node_id^ that can be used for remote +spawning (see~\sref{remote-spawn}). + +\subsection{Free Functions} +\label{free-remoting-functions} + +The following free functions in the namespace \lstinline^caf::io^ avoid calling +the middleman directly. This enables users to easily switch between +communication backends as long as the interfaces have the same signatures. For +example, the (experimental) OpenSSL binding of CAF implements the same +functions in the namespace \lstinline^caf::openssl^ to easily switch between +encrypted and unencrypted communication. + +\begin{center} +\begin{tabular}{ll} + \hline + \lstinline^expected open(actor_system&, uint16, const char*, bool)^ & See~\sref{remoting}. \\ + \hline + \lstinline^expected publish(T, uint16, const char*, bool)^ & See~\sref{remoting}. \\ + \hline + \lstinline^expected unpublish(T x, uint16)^ & See~\sref{remoting}. \\ + \hline + \lstinline^expected connect(actor_system&, std::string host, uint16_t port)^ & See~\sref{remoting}. \\ + \hline + \lstinline^expected remote_actor(actor_system&, string, uint16)^ & See~\sref{remoting}. \\ + \hline +\end{tabular} +\end{center} + +\subsection{Transport Protocols \experimental} +\label{transport-protocols} + +CAF communication uses TCP per default and thus the functions shown in the +middleman API above are related to TCP. There are two alternatives to plain +TCP: TLS via the OpenSSL module shortly discussed in +\sref{free-remoting-functions} and UDP. + +UDP is integrated in the default multiplexer and BASP broker. Set the flag +\lstinline^middleman_enable_udp^ to true to enable it +(see~\sref{system-config}). This does not require you to disable TCP. Use +\lstinline^publish_udp^ and \lstinline^remote_actor_udp^ to establish +communication. + +Communication via UDP is inherently unreliable and unordered. CAF reestablishes +order and drops messages that arrive late. Messages that are sent via datagrams +are limited to a maximum of 65.535 bytes which is used as a receive buffer size +by CAF. Note that messages that exceed the MTU are fragmented by IP and are +considered lost if a single fragment is lost. Optional reliability based on +retransmissions and messages slicing on the application layer are planned for +the future. diff -Nru actor-framework-0.13.2/doc/tex/OpenCL.tex actor-framework-0.16.3/doc/tex/OpenCL.tex --- actor-framework-0.13.2/doc/tex/OpenCL.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/OpenCL.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,25 @@ +\section{OpenCL-based Actors} + +CAF supports transparent integration of OpenCL functions. + + +\begin{lstlisting} +// opencl kernel for matrix multiplication; +// last parameter is, by convention, the output parameter +constexpr const char* kernel_source = R"__( + __kernel void matrix_mult(__global float* matrix1, + __global float* matrix2, + __global float* output) { + // we only use square matrices, hence: width == height + size_t size = get_global_size(0); // == get_global_size_(1); + size_t x = get_global_id(0); + size_t y = get_global_id(1); + float result = 0; + for (size_t idx = 0; idx < size; ++idx) + result += matrix1[idx + y * size] * matrix2[x + idx * size]; + output[x + y * size] = result; + } +)__"; +\end{lstlisting} + + diff -Nru actor-framework-0.13.2/doc/tex/ReferenceCounting.tex actor-framework-0.16.3/doc/tex/ReferenceCounting.tex --- actor-framework-0.13.2/doc/tex/ReferenceCounting.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/ReferenceCounting.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,146 @@ +\section{Reference Counting} +\label{reference-counting} + +Actors systems can span complex communication graphs that make it hard to +decide when actors are no longer needed. As a result, manually managing +lifetime of actors is merely impossible. For this reason, CAF implements a +garbage collection strategy for actors based on weak and strong reference +counts. + +\subsection{Shared Ownership in C++} + +The C++ standard library already offers \lstinline^shared_ptr^ and +\lstinline^weak_ptr^ to manage objects with complex shared ownership. The +standard implementation is a solid general purpose design that covers most use +cases. Weak and strong references to an object are stored in a \emph{control +block}. However, CAF uses a slightly different design. The reason for this is +twofold. First, we need the control block to store the identity of an actor. +Second, we wanted a design that requires less indirections, because actor +handles are used extensively copied for messaging, and this overhead adds up. + +Before discussing the approach to shared ownership in CAF, we look at the +design of shared pointers in the C++ standard library. + +\singlefig{shared_ptr}{Shared pointer design in the C++ standard library}{shared-ptr} + +The figure above depicts the default memory layout when using shared pointers. +The control block is allocated separately from the data and thus stores a +pointer to the data. This is when using manually-allocated objects, for example +\lstinline^shared_ptr iptr{new int}^. The benefit of this design is that +one can destroy \lstinline^T^ independently from its control block. While +irrelevant for small objects, it can become an issue for large objects. +Notably, the shared pointer stores two pointers internally. Otherwise, +dereferencing it would require to get the data location from the control block +first. + +\singlefig{make_shared}{Memory layout when using \lstinline^std::make_shared^}{make-shared} + +When using \lstinline^make_shared^ or \lstinline^allocate_shared^, the standard +library can store reference count and data in a single memory block as shown +above. However, \lstinline^shared_ptr^ still has to store two pointers, because +it is unaware where the data is allocated. + +\singlefig{enable_shared_from_this}{Memory layout with \lstinline^std::enable_shared_from_this^}{enable-shared-from-this} + +Finally, the design of the standard library becomes convoluted when an object +should be able to hand out a \lstinline^shared_ptr^ to itself. Classes must +inherit from \lstinline^std::enable_shared_from_this^ to navigate from an +object to its control block. This additional navigation path is required, +because \lstinline^std::shared_ptr^ needs two pointers. One to the data and one +to the control block. Programmers can still use \lstinline^make_shared^ for +such objects, in which case the object is again stored along with the control +block. + +\subsection{Smart Pointers to Actors} + +In CAF, we use a different approach than the standard library because (1) we +always allocate actors along with their control block, (2) we need additional +information in the control block, and (3) we can store only a single raw +pointer internally instead of the two raw pointers \lstinline^std::shared_ptr^ +needs. The following figure summarizes the design of smart pointers to actors. + +\singlefig{refcounting}{Shared pointer design in CAF}{actor-pointer} + +CAF uses \lstinline^strong_actor_ptr^ instead of +\lstinline^std::shared_ptr<...>^ and \lstinline^weak_actor_ptr^ instead of +\lstinline^std::weak_ptr<...>^. Unlike the counterparts from the standard +library, both smart pointer types only store a single pointer. + +Also, the control block in CAF is not a template and stores the identity of an +actor (\lstinline^actor_id^ plus \lstinline^node_id^). This allows CAF to +access this information even after an actor died. The control block fits +exactly into a single cache line (64 Bytes). This makes sure no \emph{false +sharing} occurs between an actor and other actors that have references to it. +Since the size of the control block is fixed and CAF \emph{guarantees} the +memory layout enforced by \lstinline^actor_storage^, CAF can compute the +address of an actor from the pointer to its control block by offsetting it by +64 Bytes. Likewise, an actor can compute the address of its control block. + +The smart pointer design in CAF relies on a few assumptions about actor types. +Most notably, the actor object is placed 64 Bytes after the control block. This +starting address is cast to \lstinline^abstract_actor*^. Hence, \lstinline^T*^ +must be convertible to \lstinline^abstract_actor*^ via +\lstinline^reinterpret_cast^. In practice, this means actor subclasses must not +use virtual inheritance, which is enforced in CAF with a +\lstinline^static_assert^. + +\subsection{Strong and Weak References} + +A \emph{strong} reference manipulates the \lstinline^strong refs^ counter as +shown above. An actor is destroyed if there are \emph{zero} strong references +to it. If two actors keep strong references to each other via member variable, +neither actor can ever be destroyed because they produce a cycle +\see{breaking-cycles}. Strong references are formed by +\lstinline^strong_actor_ptr^, \lstinline^actor^, and +\lstinline^typed_actor<...>^ \see{actor-reference}. + +A \emph{weak} reference manipulates the \lstinline^weak refs^ counter. This +counter keeps track of how many references to the control block exist. The +control block is destroyed if there are \emph{zero} weak references to an actor +(which cannot occur before \lstinline^strong refs^ reached \emph{zero} as +well). No cycle occurs if two actors keep weak references to each other, +because the actor objects themselves can get destroyed independently from their +control block. A weak reference is only formed by \lstinline^actor_addr^ +\see{actor-address}. + +\subsection{Converting Actor References with \texttt{actor\_cast}} +\label{actor-cast} + +The function \lstinline^actor_cast^ converts between actor pointers and +handles. The first common use case is to convert a \lstinline^strong_actor_ptr^ +to either \lstinline^actor^ or \lstinline^typed_actor<...>^ before being able +to send messages to an actor. The second common use case is to convert +\lstinline^actor_addr^ to \lstinline^strong_actor_ptr^ to upgrade a weak +reference to a strong reference. Note that casting \lstinline^actor_addr^ to a +strong actor pointer or handle can result in invalid handles. The syntax for +\lstinline^actor_cast^ resembles builtin C++ casts. For example, +\lstinline^actor_cast(x)^ converts \lstinline^x^ to an handle of type +\lstinline^actor^. + +\subsection{Breaking Cycles Manually} +\label{breaking-cycles} + +Cycles can occur only when using class-based actors when storing references to +other actors via member variable. Stateful actors \see{stateful-actor} break +cycles by destroying the state when an actor terminates, \emph{before} the +destructor of the actor itself runs. This means an actor releases all +references to others automatically after calling \lstinline^quit^. However, +class-based actors have to break cycles manually, because references to others +are not released until the destructor of an actor runs. Two actors storing +references to each other via member variable produce a cycle and neither +destructor can ever be called. + +Class-based actors can break cycles manually by overriding +\lstinline^on_exit()^ and calling \lstinline^destroy(x)^ on each +handle~\see{actor-handle}. Using a handle after destroying it is undefined +behavior, but it is safe to assign a new value to the handle. + +%TODO: Add use case for the following casting scenario. There is one +%requirement of this design: `static_cast(self)` must return +%the same pointer as `reinterpret_cast(self)` for any actor +%`self`. Otherwise, our assumption that the actor object starts exactly 64 +%Bytes after its control block would break. Luckily, this boils down to a +%single limitation in practice: User-defined actors must not use virtual +%inheritance. When trying to spawn actors that do make use of virtual +%inheritance, CAF generates a compile-time error: `"actor subtype has illegal +%memory alignment (probably due to virtual inheritance)"`. diff -Nru actor-framework-0.13.2/doc/tex/Registry.tex actor-framework-0.16.3/doc/tex/Registry.tex --- actor-framework-0.13.2/doc/tex/Registry.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/Registry.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,47 @@ +\section{Registry} +\label{registry} + +The actor registry in CAF keeps track of the number of running actors and +allows to map actors to their ID or a custom atom~\see{atom} representing a +name. The registry does \emph{not} contain all actors. Actors have to be stored +in the registry explicitly. Users can access the registry through an actor +system by calling \lstinline^system.registry()^. The registry stores actors +using \lstinline^strong_actor_ptr^ \see{actor-pointer}. + +Users can use the registry to make actors system-wide available by name. The +middleman~\see{middleman} uses the registry to keep track of all actors known +to remote nodes in order to serialize and deserialize them. Actors are removed +automatically when they terminate. + +It is worth mentioning that the registry is not synchronized between connected +actor system. Each actor system has its own, local registry in a distributed +setting. + +\begin{center} +\begin{tabular}{ll} + \textbf{Types} & ~ \\ + \hline + \lstinline^name_map^ & \lstinline^unordered_map^ \\ + \hline + ~ & ~ \\ \textbf{Observers} & ~ \\ + \hline + \lstinline^strong_actor_ptr get(actor_id)^ & Returns the actor associated to given ID. \\ + \hline + \lstinline^strong_actor_ptr get(atom_value)^ & Returns the actor associated to given name. \\ + \hline + \lstinline^name_map named_actors()^ & Returns all name mappings. \\ + \hline + \lstinline^size_t running()^ & Returns the number of currently running actors. \\ + \hline + ~ & ~ \\ \textbf{Modifiers} & ~ \\ + \hline + \lstinline^void put(actor_id, strong_actor_ptr)^ & Maps an actor to its ID. \\ + \hline + \lstinline^void erase(actor_id)^ & Removes an ID mapping from the registry. \\ + \hline + \lstinline^void put(atom_value, strong_actor_ptr)^ & Maps an actor to a name. \\ + \hline + \lstinline^void erase(atom_value)^ & Removes a name mapping from the registry. \\ + \hline +\end{tabular} +\end{center} diff -Nru actor-framework-0.13.2/doc/tex/RemoteSpawn.tex actor-framework-0.16.3/doc/tex/RemoteSpawn.tex --- actor-framework-0.13.2/doc/tex/RemoteSpawn.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/RemoteSpawn.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,18 @@ +\section{Remote Spawning of Actors \experimental} +\label{remote-spawn} + +Remote spawning is an extension of the dynamic spawn using run-time type names +\see{add-custom-actor-type}. The following example assumes a typed actor handle +named \lstinline^calculator^ with an actor implementing this messaging +interface named "calculator". + +\cppexample[125-143]{remoting/remote_spawn} + +We first connect to a CAF node with \lstinline^middleman().connect(...)^. On +success, \lstinline^connect^ returns the node ID we need for +\lstinline^remote_spawn^. This requires the server to open a port with +\lstinline^middleman().open(...)^ or \lstinline^middleman().publish(...)^. +Alternatively, we can obtain the node ID from an already existing remote actor +handle---returned from \lstinline^remote_actor^ for example---via +\lstinline^hdl->node()^. After connecting to the server, we can use +\lstinline^middleman().remote_spawn<...>(...)^ to create actors remotely. diff -Nru actor-framework-0.13.2/doc/tex/Scheduler.tex actor-framework-0.16.3/doc/tex/Scheduler.tex --- actor-framework-0.13.2/doc/tex/Scheduler.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/Scheduler.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,137 @@ +\section{Scheduler} +\label{scheduler} + +The CAF runtime maps N actors to M threads on the local machine. Applications +build with CAF scale by decomposing tasks into many independent steps that are +spawned as actors. In this way, sequential computations performed by individual +actors are small compared to the total runtime of the application, and the +attainable speedup on multi-core hardware is maximized in agreement with +Amdahl's law. + +Decomposing tasks implies that actors are often short-lived. Assigning a +dedicated thread to each actor would not scale well. Instead, CAF includes a +scheduler that dynamically assigns actors to a pre-dimensioned set of worker +threads. Actors are modeled as lightweight state machines. Whenever a +\emph{waiting} actor receives a message, it changes its state to \emph{ready} +and is scheduled for execution. CAF cannot interrupt running actors because it +is implemented in user space. Consequently, actors that use blocking system +calls such as I/O functions can suspend threads and create an imbalance or lead +to starvation. Such ``uncooperative'' actors can be explicitly detached by the +programmer by using the \lstinline^detached^ spawn option, e.g., +\lstinline^system.spawn(my_actor_fun)^. + +The performance of actor-based applications depends on the scheduling algorithm +in use and its configuration. Different application scenarios require different +trade-offs. For example, interactive applications such as shells or GUIs want +to stay responsive to user input at all times, while batch processing +applications demand only to perform a given task in the shortest possible time. + +Aside from managing actors, the scheduler bridges actor and non-actor code. For +this reason, the scheduler distinguishes between external and internal events. +An external event occurs whenever an actor is spawned from a non-actor context +or an actor receives a message from a thread that is not under the control of +the scheduler. Internal events are send and spawn operations from scheduled +actors. + +\subsection{Policies} +\label{scheduler-policy} + +The scheduler consists of a single coordinator and a set of workers. The +coordinator is needed by the public API to bridge actor and non-actor contexts, +but is not necessarily an active software entity. + +The scheduler of CAF is fully customizable by using a policy-based design. The +following class shows a \emph{concept} class that lists all required member +types and member functions. A policy provides the two data structures +\lstinline^coordinator_data^ and \lstinline^worker_data^ that add additional +data members to the coordinator and its workers respectively, e.g., work +queues. This grants developers full control over the state of the scheduler. + +\begin{lstlisting} +struct scheduler_policy { + struct coordinator_data; + struct worker_data; + void central_enqueue(Coordinator* self, resumable* job); + void external_enqueue(Worker* self, resumable* job); + void internal_enqueue(Worker* self, resumable* job); + void resume_job_later(Worker* self, resumable* job); + resumable* dequeue(Worker* self); + void before_resume(Worker* self, resumable* job); + void after_resume(Worker* self, resumable* job); + void after_completion(Worker* self, resumable* job); +}; +\end{lstlisting} + +Whenever a new work item is scheduled---usually by sending a message to an idle +actor---, one of the functions \lstinline^central_enqueue^, +\lstinline^external_enqueue^, and \lstinline^internal_enqueue^ is called. The +first function is called whenever non-actor code interacts with the actor +system. For example when spawning an actor from \lstinline^main^. Its first +argument is a pointer to the coordinator singleton and the second argument is +the new work item---usually an actor that became ready. The function +\lstinline^external_enqueue^ is never called directly by CAF. It models the +transfer of a task to a worker by the coordinator or another worker. Its first +argument is the worker receiving the new task referenced in the second +argument. The third function, \lstinline^internal_enqueue^, is called whenever +an actor interacts with other actors in the system. Its first argument is the +current worker and the second argument is the new work item. + +Actors reaching the maximum number of messages per run are re-scheduled with +\lstinline^resume_job_later^ and workers acquire new work by calling +\lstinline^dequeue^. The two functions \lstinline^before_resume^ and +\lstinline^after_resume^ allow programmers to measure individual actor runtime, +while \lstinline^after_completion^ allows to execute custom code whenever a +work item has finished execution by changing its state to \emph{done}, but +before it is destroyed. In this way, the last three functions enable developers +to gain fine-grained insight into the scheduling order and individual execution +times. + +\subsection{Work Stealing} +\label{work-stealing} + +The default policy in CAF is work stealing. The key idea of this algorithm is +to remove the bottleneck of a single, global work queue. The original +algorithm was developed for fully strict computations by Blumofe et al in 1994. +It schedules any number of tasks to \lstinline^P^ workers, where \lstinline^P^ +is the number of processors available. + +\singlefig{stealing}{Stealing of work items}{fig-stealing} + +Each worker dequeues work items from an individual queue until it is drained. +Once this happens, the worker becomes a \emph{thief}. It picks one of the other +workers---usually at random---as a \emph{victim} and tries to \emph{steal} a +work item. As a consequence, tasks (actors) are bound to workers by default and +only migrate between threads as a result of stealing. This strategy minimizes +communication between threads and maximizes cache locality. Work stealing has +become the algorithm of choice for many frameworks. For example, Java's +Fork-Join (which is used by Akka), Intel's Threading Building Blocks, several +OpenMP implementations, etc. + +CAF uses a double-ended queue for its workers, which is synchronized with two +spinlocks. One downside of a decentralized algorithm such as work stealing is, +that idle states are hard to detect. Did only one worker run out of work items +or all? Since each worker has only local knowledge, it cannot decide when it +could safely suspend itself. Likewise, workers cannot resume if new job items +arrived at one or more workers. For this reason, CAF uses three polling +intervals. Once a worker runs out of work items, it tries to steal items from +others. First, it uses the \emph{aggressive} polling interval. It falls back to +a \emph{moderate} interval after a predefined number of trials. After another +predefined number of trials, it will finally use a \emph{relaxed} interval. + +Per default, the \emph{aggressive} strategy performs 100 steal attempts with no +sleep interval in between. The \emph{moderate} strategy tries to steal 500 +times with 50 microseconds sleep between two steal attempts. Finally, the +\emph{relaxed} strategy runs indefinitely but sleeps for 10 milliseconds +between two attempts. These defaults can be overridden via system config at +startup~\see{system-config}. + +\subsection{Work Sharing} +\label{work-sharing} + +Work sharing is an alternative scheduler policy in CAF that uses a single, +global work queue. This policy uses a mutex and a condition variable on the +central queue. Thus, the policy supports only limited concurrency but does not +need to poll. Using this policy can be a good fit for low-end devices where +power consumption is an important metric. + +% TODO: profiling section Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/src/actor_types.graffle and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/src/actor_types.graffle differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/src/mailbox_element.graffle and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/src/mailbox_element.graffle differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/src/refcounting.graffle and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/src/refcounting.graffle differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/src/stealing.graffle and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/src/stealing.graffle differ Binary files /tmp/tmpL70g2q/vDV4hzRc3o/actor-framework-0.13.2/doc/tex/src/stream-manager.graffle and /tmp/tmpL70g2q/0H5JtflFG1/actor-framework-0.16.3/doc/tex/src/stream-manager.graffle differ diff -Nru actor-framework-0.13.2/doc/tex/Streaming.tex actor-framework-0.16.3/doc/tex/Streaming.tex --- actor-framework-0.13.2/doc/tex/Streaming.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/Streaming.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,100 @@ +\section{Streaming\experimental} +\label{streaming} + +Streams in CAF describe data flow between actors. We are not aiming to provide +functionality similar to Apache projects like Spark, Flink or Storm. Likewise, +we have different goals than APIs such as RxJava, Reactive Streams, etc. +Streams complement asynchronous messages, request/response communication and +publish/subscribe in CAF. In a sense, actor streams in CAF are a building +block that users could leverage for building feature-complete stream +computation engines or reactive high-level Big Data APIs. + +A stream establishes a logical channel between two or more actors for +exchanging a potentially unbound sequence of values. This channel uses demand +signaling to guarantee that senders cannot overload receivers. + +\singlefig{stream}{Streaming Concept}{stream} + +Streams are directed and data flows only \emph{downstream}, i.e., from sender +(source) to receiver (sink). Establishing a stream requires a handshake in +order to initialize required state and signal initial demand. + +\singlefig{stream-roles}{Streaming Roles}{stream-roles} + +CAF distinguishes between three roles in a stream: (1) a \emph{source} creates +streams and generates data, (2) a \emph{stage} transforms or filters data, and +(3) a \emph{sink} terminates streams by consuming data. + +We usually draw streams as pipelines for simplicity. However, sources can have +any number of outputs (downstream actors). Likewise, sinks can have any number +of inputs (upstream actors) and stages can multiplex N inputs to M outputs. +Hence, streaming topologies in CAF support arbitrary complexity with forks and +joins. + +\subsection{Stream Managers} + +Streaming-related messages are handled separately. Under the hood, actors +delegate to \emph{stream managers} that in turn allow customization of their +behavior with \emph{drivers} and \emph{downstream managers}. + +\singlefig{stream-manager}{Internals of Stream Managers}{fig-stream-manager} + +Users usually can skip implementing driver classes and instead use the +lambda-based interface showcased in the following sections. Drivers implement +the streaming logic by taking inputs from upstream actors and pushing data to +the downstream manager. A source has no input buffer. Hence, drivers only +provide a \emph{generator} function that downstream managers call according to +demand. + +A downstream manager is responsible for dispatching data to downstream actors. +The default implementation broadcasts data, i.e., all downstream actors receive +the same data. The downstream manager can also perform any sort multi- or +anycast. For example, a load-balancer would use an anycast policy to dispatch +data to the next available worker. + +\clearpage + +\subsection{Defining Sources} + +\cppexample[17-52]{streaming/integer_stream} + +The simplest way to defining a source is to use the \lstinline^make_source^ +function and pass it three arguments: \emph{initializer} for the state, +\emph{generator} for producing values, and \emph{predicate} for signaling the +end of the stream. + +\clearpage + +\subsection{Defining Stages} + +\cppexample[54-87]{streaming/integer_stream} + +The function \lstinline^make_stage^ also takes three lambdas but additionally +the received input stream handshake as first argument. Instead of a predicate, +\lstinline^make_stage^ only takes a finalizer, since the stage does not produce +data on its own and a stream terminates if no more sources exist. + +\clearpage + +\subsection{Defining Sinks} + +\cppexample[89-120]{streaming/integer_stream} + +The function \lstinline^make_sink^ is similar to \lstinline^make_stage^, except +that is does not produce outputs. + +\clearpage + +\subsection{Initiating Streams} + +\cppexample[133-139]{streaming/integer_stream} + +In our example, we always have a source \lstinline^int_source^ and a sink +\lstinline^int_sink^ with an optional stage \lstinline^int_selector^. Sending +\lstinline^open_atom^ to the source initiates the stream and the source will +respond with a stream handshake. + +Using the actor composition in CAF (\lstinline^snk * src^ reads \emph{sink +after source}) allows us to redirect the stream handshake we send in +\lstinline^caf_main^ to the sink (or to the stage and then from the stage to +the sink). diff -Nru actor-framework-0.13.2/doc/tex/TypeInspection.tex actor-framework-0.16.3/doc/tex/TypeInspection.tex --- actor-framework-0.13.2/doc/tex/TypeInspection.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/TypeInspection.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,132 @@ +\section{Type Inspection (Serialization and String Conversion)} +\label{type-inspection} + +CAF is designed with distributed systems in mind. Hence, all message types +must be serializable and need a platform-neutral, unique name that is +configured at startup \see{add-custom-message-type}. Using a message type that +is not serializable causes a compiler error \see{unsafe-message-type}. CAF +serializes individual elements of a message by using the inspection API. This +API allows users to provide code for serialization as well as string conversion +with a single free function. The signature for a class \lstinline^my_class^ is +always as follows: + +\begin{lstlisting} +template +typename Inspector::result_type inspect(Inspector& f, my_class& x) { + return f(...); +} +\end{lstlisting} + +The function \lstinline^inspect^ passes meta information and data fields to the +variadic call operator of the inspector. The following example illustrates an +implementation for \lstinline^inspect^ for a simple POD struct. + +\cppexample[23-33]{custom_type/custom_types_1} + +The inspector recursively inspects all data fields and has builtin support for +(1) \lstinline^std::tuple^, (2) \lstinline^std::pair^, (3) C arrays, (4) any +container type with \lstinline^x.size()^, \lstinline^x.empty()^, +\lstinline^x.begin()^ and \lstinline^x.end()^. + +We consciously made the inspect API as generic as possible to allow for +extensibility. This allows users to use CAF's types in other contexts, to +implement parsers, etc. + +\subsection{Inspector Concept} + +The following concept class shows the requirements for inspectors. The +placeholder \lstinline^T^ represents any user-defined type. For example, +\lstinline^error^ when performing I/O operations or some integer type when +implementing a hash function. + +\begin{lstlisting} +Inspector { + using result_type = T; + + if (inspector only requires read access to the state of T) + static constexpr bool reads_state = true; + else + static constexpr bool writes_state = true; + + template + result_type operator()(Ts&&...); +} +\end{lstlisting} + +A saving \lstinline^Inspector^ is required to handle constant lvalue and rvalue +references. A loading \lstinline^Inspector^ must only accept mutable lvalue +references to data fields, but still allow for constant lvalue references and +rvalue references to annotations. + +\subsection{Annotations} + +Annotations allow users to fine-tune the behavior of inspectors by providing +addition meta information about a type. All annotations live in the namespace +\lstinline^caf::meta^ and derive from \lstinline^caf::meta::annotation^. An +inspector can query whether a type \lstinline^T^ is an annotation with +\lstinline^caf::meta::is_annotation::value^. Annotations are passed to the +call operator of the inspector along with data fields. The following list shows +all annotations supported by CAF: + +\begin{itemize} +\item \lstinline^type_name(n)^: Display type name as \lstinline^n^ in + human-friendly output (position before data fields). +\item \lstinline^hex_formatted()^: Format the following data field in hex + format. +\item \lstinline^omittable()^: Omit the following data field in human-friendly + output. +\item \lstinline^omittable_if_empty()^: Omit the following data field if it is + empty in human-friendly output. +\item \lstinline^omittable_if_none()^: Omit the following data field if it + equals \lstinline^none^ in human-friendly output. +\item \lstinline^save_callback(f)^: Call \lstinline^f^ when serializing + (position after data fields). +\item \lstinline^load_callback(f)^: Call \lstinline^f^ after deserializing all + data fields (position after data fields). +\end{itemize} + +\subsection{Backwards and Third-party Compatibility} + +CAF evaluates common free function other than \lstinline^inspect^ in order to +simplify users to integrate CAF into existing code bases. + +Serializers and deserializers call user-defined \lstinline^serialize^ +functions. Both types support \lstinline^operator&^ as well as +\lstinline^operator()^ for individual data fields. A \lstinline^serialize^ +function has priority over \lstinline^inspect^. + +When converting a user-defined type to a string, CAF calls user-defined +\lstinline^to_string^ functions and prefers those over \lstinline^inspect^. + +\subsection{Whitelisting Unsafe Message Types} +\label{unsafe-message-type} + +Message types that are not serializable cause compile time errors when used in +actor communication. When using CAF for concurrency only, this errors can be +suppressed by whitelisting types with +\lstinline^CAF_ALLOW_UNSAFE_MESSAGE_TYPE^. The macro is defined as follows. + +% TODO: expand example here\cppexample[linerange={50-54}]{../../libcaf_core/caf/allowed_unsafe_message_type.hpp} + +\clearpage +\subsection{Splitting Save and Load Operations} + +If loading and storing cannot be implemented in a single function, users can +query whether the inspector is loading or storing. For example, consider the +following class \lstinline^foo^ with getter and setter functions and no public +access to its members. + +\cppexample[20-49]{custom_type/custom_types_3} + +\clearpage +Since there is no access to the data fields \lstinline^a_^ and \lstinline^b_^ +(and assuming no changes to \lstinline^foo^ are possible), we need to split our +implementation of \lstinline^inspect^ as shown below. + +\cppexample[76-103]{custom_type/custom_types_3} + +The purpose of the scope guard in the example above is to write the content of +the temporaries back to \lstinline^foo^ at scope exit automatically. Storing +the result of \lstinline^f(...)^ in a temporary first and then writing the +changes to \lstinline^foo^ is not possible, because \lstinline^f(...)^ can +return \lstinline^void^. diff -Nru actor-framework-0.13.2/doc/tex/UsingAout.tex actor-framework-0.16.3/doc/tex/UsingAout.tex --- actor-framework-0.13.2/doc/tex/UsingAout.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/UsingAout.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,17 @@ +\section{Using \texttt{aout} -- A Concurrency-safe Wrapper for \texttt{cout}} + +When using \lstinline^cout^ from multiple actors, output often appears +interleaved. Moreover, using \lstinline^cout^ from multiple actors -- and thus +from multiple threads -- in parallel should be avoided regardless, since the +standard does not guarantee a thread-safe implementation. + +By replacing \texttt{std::cout} with \texttt{caf::aout}, actors can achieve a +concurrency-safe text output. The header \lstinline^caf/all.hpp^ also defines +overloads for \texttt{std::endl} and \texttt{std::flush} for \lstinline^aout^, +but does not support the full range of ostream operations (yet). Each write +operation to \texttt{aout} sends a message to a `hidden' actor. This actor only +prints lines, unless output is forced using \lstinline^flush^. The example +below illustrates printing of lines of text from multiple actors (in random +order). + +\cppexample{aout} diff -Nru actor-framework-0.13.2/doc/tex/Utility.tex actor-framework-0.16.3/doc/tex/Utility.tex --- actor-framework-0.13.2/doc/tex/Utility.tex 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/doc/tex/Utility.tex 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,70 @@ +\section{Utility} +\label{utility} + +CAF includes a few utility classes that are likely to be part of C++ +eventually (or already are in newer versions of the standard). However, until +these classes are part of the standard library on all supported compilers, we +unfortunately have to maintain our own implementations. + +\subsection{Class \lstinline^optional^} +\label{optional} + +Represents a value that may or may not exist. + +\begin{center} +\begin{tabular}{ll} + \textbf{Constructors} & ~ \\ + \hline + \lstinline^(T value)^ & Constructs an object with a value. \\ + \hline + \lstinline^(none_t = none)^ & Constructs an object without a value. \\ + \hline + ~ & ~ \\ \textbf{Observers} & ~ \\ + \hline + \lstinline^explicit operator bool()^ & Checks whether the object contains a value. \\ + \hline + \lstinline^T* operator->()^ & Accesses the contained value. \\ + \hline + \lstinline^T& operator*()^ & Accesses the contained value. \\ + \hline +\end{tabular} +\end{center} + +\subsection{Class \lstinline^expected^} + +Represents the result of a computation that \emph{should} return a value. If no +value could be produced, the \lstinline^expected^ contains an +\lstinline^error^ \see{error}. + +\begin{center} +\begin{tabular}{ll} + \textbf{Constructors} & ~ \\ + \hline + \lstinline^(T value)^ & Constructs an object with a value. \\ + \hline + \lstinline^(error err)^ & Constructs an object with an error. \\ + \hline + ~ & ~ \\ \textbf{Observers} & ~ \\ + \hline + \lstinline^explicit operator bool()^ & Checks whether the object contains a value. \\ + \hline + \lstinline^T* operator->()^ & Accesses the contained value. \\ + \hline + \lstinline^T& operator*()^ & Accesses the contained value. \\ + \hline + \lstinline^error& error()^ & Accesses the contained error. \\ + \hline +\end{tabular} +\end{center} + + +\subsection{Constant \lstinline^unit^} + +The constant \lstinline^unit^ of type \lstinline^unit_t^ is the equivalent of +\lstinline^void^ and can be used to initialize \lstinline^optional^ and +\lstinline^expected^. + +\subsection{Constant \lstinline^none^} + +The constant \lstinline^none^ of type \lstinline^none_t^ can be used to +initialize an \lstinline^optional^ to represent ``nothing''. diff -Nru actor-framework-0.13.2/Doxyfile.in actor-framework-0.16.3/Doxyfile.in --- actor-framework-0.13.2/Doxyfile.in 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/Doxyfile.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,1466 +0,0 @@ -# Doxyfile 1.8.0 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Enable markdown support -#--------------------------------------------------------------------------- - -MARKDOWN_SUPPORT = YES - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = libcaf - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = @CAF_VERSION@ - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, -# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, -# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, -# Spanish, Swedish, and Ukrainian. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 2 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it parses. -# With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this tag. -# The format is ext=language, where ext is a file extension, and language is one of -# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, -# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), -# use: inc=Fortran f=C - -EXTENSION_MAPPING = C++ - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = YES - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen to replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = NO - - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = YES - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = NO - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = NO - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = YES - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = YES - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = NO - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. -# This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by -# doxygen. The layout file controls the global structure of the generated output files -# in an output format independent way. The create the layout file that represents -# doxygen's defaults, run doxygen with the -l option. You can optionally specify a -# file name after the option, if omitted DoxygenLayout.xml will be used as the name -# of the layout file. - -LAYOUT_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = YES - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = @CMAKE_HOME_DIRECTORY@/libcaf_core/caf @CMAKE_HOME_DIRECTORY@/libcaf_core/caf/mixin @CMAKE_HOME_DIRECTORY@/libcaf_core/caf/policy @CMAKE_HOME_DIRECTORY@/libcaf_io/caf/io - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 - -FILE_PATTERNS = - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = examples - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = YES - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. -# If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. -# Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. -# The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. -# Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER -# are set, an additional index file will be generated that can be used as input for -# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated -# HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. -# For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's -# filter section matches. -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 1 - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to FRAME, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. Other possible values -# for this tag are: HIERARCHIES, which will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list; -# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which -# disables this behavior completely. For backwards compatibility with previous -# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE -# respectively. - -GENERATE_TREEVIEW = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. -# This is useful -# if you want to understand what is going on. -# On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = CAF_DOCUMENTATION - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = YES - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Options related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = YES diff -Nru actor-framework-0.13.2/examples/aout.cpp actor-framework-0.16.3/examples/aout.cpp --- actor-framework-0.13.2/examples/aout.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/aout.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -1,20 +1,17 @@ -/******************************************************************************\ - * This example illustrates how to use aout. * -\******************************************************************************/ - #include #include #include #include #include "caf/all.hpp" +#include "caf/io/all.hpp" using namespace caf; using std::endl; -int main() { +void caf_main(actor_system& system) { for (int i = 1; i <= 50; ++i) { - spawn([i](blocking_actor* self) { + system.spawn([i](blocking_actor* self) { aout(self) << "Hi there! This is actor nr. " << i << "!" << endl; std::random_device rd; @@ -29,8 +26,6 @@ ); }); } - // wait until all other actors we've spawned are done - await_all_actors_done(); - // done - shutdown(); } + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/broker/protobuf_broker.cpp actor-framework-0.16.3/examples/broker/protobuf_broker.cpp --- actor-framework-0.13.2/examples/broker/protobuf_broker.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/broker/protobuf_broker.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,201 @@ +#include +#include +#include +#include +#include + +#include "caf/all.hpp" +#include "caf/io/all.hpp" + +#ifdef CAF_WINDOWS +#include +#else +#include +#endif + +CAF_PUSH_WARNINGS +#include "pingpong.pb.h" +CAF_POP_WARNINGS + +namespace { + +using namespace std; +using namespace caf; +using namespace caf::io; + +using ping_atom = atom_constant; +using pong_atom = atom_constant; +using kickoff_atom = atom_constant; + +// utility function to print an exit message with custom name +void print_on_exit(scheduled_actor* self, const std::string& name) { + self->attach_functor([=](const error& reason) { + aout(self) << name << " exited: " << self->home_system().render(reason) + << endl; + }); +} + +struct ping_state { + size_t count = 0; +}; + +behavior ping(stateful_actor* self, size_t num_pings) { + print_on_exit(self, "ping"); + return { + [=](kickoff_atom, const actor& pong) { + self->send(pong, ping_atom::value, 1); + self->become ( + [=](pong_atom, int value) -> message { + if (++(self->state.count) >= num_pings) + self->quit(); + return make_message(ping_atom::value, value + 1); + } + ); + } + }; +} + +behavior pong(event_based_actor* self) { + print_on_exit(self, "pong"); + return { + [=](ping_atom, int value) { + return make_message(pong_atom::value, value); + } + }; +} + +void protobuf_io(broker* self, connection_handle hdl, const actor& buddy) { + print_on_exit(self, "protobuf_io"); + aout(self) << "protobuf broker started" << endl; + self->monitor(buddy); + self->set_down_handler( + [=](const down_msg& dm) { + if (dm.source == buddy) { + aout(self) << "our buddy is down" << endl; + self->quit(dm.reason); + } + }); + auto write = [=](const org::libcppa::PingOrPong& p) { + string buf = p.SerializeAsString(); + auto s = htonl(static_cast(buf.size())); + self->write(hdl, sizeof(uint32_t), &s); + self->write(hdl, buf.size(), buf.data()); + self->flush(hdl); + }; + message_handler default_bhvr = { + [=](const connection_closed_msg&) { + aout(self) << "connection closed" << endl; + self->send_exit(buddy, exit_reason::remote_link_unreachable); + self->quit(exit_reason::remote_link_unreachable); + }, + [=](ping_atom, int i) { + aout(self) << "'ping' " << i << endl; + org::libcppa::PingOrPong p; + p.mutable_ping()->set_id(i); + write(p); + }, + [=](pong_atom, int i) { + aout(self) << "'pong' " << i << endl; + org::libcppa::PingOrPong p; + p.mutable_pong()->set_id(i); + write(p); + } + }; + auto await_protobuf_data = message_handler { + [=](const new_data_msg& msg) { + org::libcppa::PingOrPong p; + p.ParseFromArray(msg.buf.data(), static_cast(msg.buf.size())); + if (p.has_ping()) { + self->send(buddy, ping_atom::value, p.ping().id()); + } + else if (p.has_pong()) { + self->send(buddy, pong_atom::value, p.pong().id()); + } + else { + self->quit(exit_reason::user_shutdown); + cerr << "neither Ping nor Pong!" << endl; + } + // receive next length prefix + self->configure_read(hdl, receive_policy::exactly(sizeof(uint32_t))); + self->unbecome(); + } + }.or_else(default_bhvr); + auto await_length_prefix = message_handler { + [=](const new_data_msg& msg) { + uint32_t num_bytes; + memcpy(&num_bytes, msg.buf.data(), sizeof(uint32_t)); + num_bytes = htonl(num_bytes); + if (num_bytes > (1024 * 1024)) { + aout(self) << "someone is trying something nasty" << endl; + self->quit(exit_reason::user_shutdown); + return; + } + // receive protobuf data + auto nb = static_cast(num_bytes); + self->configure_read(hdl, receive_policy::exactly(nb)); + self->become(keep_behavior, await_protobuf_data); + } + }.or_else(default_bhvr); + // initial setup + self->configure_read(hdl, receive_policy::exactly(sizeof(uint32_t))); + self->become(await_length_prefix); +} + +behavior server(broker* self, const actor& buddy) { + print_on_exit(self, "server"); + aout(self) << "server is running" << endl; + return { + [=](const new_connection_msg& msg) { + aout(self) << "server accepted new connection" << endl; + auto io_actor = self->fork(protobuf_io, msg.handle, buddy); + // only accept 1 connection in our example + self->quit(); + } + }; +} + +class config : public actor_system_config { +public: + uint16_t port = 0; + std::string host = "localhost"; + bool server_mode = false; + + config() { + opt_group{custom_options_, "global"} + .add(port, "port,p", "set port") + .add(host, "host,H", "set host (ignored in server mode)") + .add(server_mode, "server-mode,s", "enable server mode"); + } +}; + +void run_server(actor_system& system, const config& cfg) { + cout << "run in server mode" << endl; + auto pong_actor = system.spawn(pong); + auto server_actor = system.middleman().spawn_server(server, cfg.port, + pong_actor); + if (!server_actor) + cerr << "unable to spawn server: " + << system.render(server_actor.error()) << endl; +} + +void run_client(actor_system& system, const config& cfg) { + cout << "run in client mode" << endl; + auto ping_actor = system.spawn(ping, 20u); + auto io_actor = system.middleman().spawn_client(protobuf_io, cfg.host, + cfg.port, ping_actor); + if (!io_actor) { + cout << "cannot connect to " << cfg.host << " at port " << cfg.port + << ": " << system.render(io_actor.error()) << endl; + return; + } + send_as(*io_actor, ping_actor, kickoff_atom::value, *io_actor); +} + +void caf_main(actor_system& system, const config& cfg) { + auto f = cfg.server_mode ? run_server : run_client; + f(system, cfg); +} + +} // namespace + +CAF_MAIN(io::middleman) diff -Nru actor-framework-0.13.2/examples/broker/simple_broker.cpp actor-framework-0.16.3/examples/broker/simple_broker.cpp --- actor-framework-0.13.2/examples/broker/simple_broker.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/broker/simple_broker.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,227 @@ +/******************************************************************************\ + * This example program showcases how to manually manage socket IO using * + * a broker. Server and client exchange integers in a 'ping-pong protocol'. * + * * + * Minimal setup: * + * - ./build/bin/broker -s 4242 * + * - ./build/bin/broker -c localhost 4242 * +\ ******************************************************************************/ + +// Manual refs: 46-50 (Actors.tex) + +#include "caf/config.hpp" + +#ifdef WIN32 +# define _WIN32_WINNT 0x0600 +# include +#else +# include // htonl +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "caf/all.hpp" +#include "caf/io/all.hpp" + +using std::cout; +using std::cerr; +using std::endl; + +using namespace caf; +using namespace caf::io; + +namespace { + +using ping_atom = atom_constant; +using pong_atom = atom_constant; +using kickoff_atom = atom_constant; + +// utility function to print an exit message with custom name +void print_on_exit(const actor& hdl, const std::string& name) { + hdl->attach_functor([=](const error& reason) { + cout << name << " exited: " << to_string(reason) << endl; + }); +} + +behavior ping(event_based_actor* self, size_t num_pings) { + auto count = std::make_shared(0); + return { + [=](kickoff_atom, const actor& pong) { + self->send(pong, ping_atom::value, int32_t(1)); + self->become ( + [=](pong_atom, int32_t value) -> result { + if (++*count >= num_pings) self->quit(); + return {ping_atom::value, value + 1}; + } + ); + } + }; +} + +behavior pong() { + return { + [](ping_atom, int32_t value) -> result { + return {pong_atom::value, value}; + } + }; +} + +// utility function for sending an integer type +template +void write_int(broker* self, connection_handle hdl, T value) { + using unsigned_type = typename std::make_unsigned::type; + auto cpy = static_cast(htonl(static_cast(value))); + self->write(hdl, sizeof(T), &cpy); + 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(value)); + write_int(self, hdl, static_cast(value >> sizeof(uint32_t))); +} + +// utility function for reading an ingeger from incoming data +template +void read_int(const void* data, T& storage) { + using unsigned_type = typename std::make_unsigned::type; + memcpy(&storage, data, sizeof(T)); + storage = static_cast(ntohl(static_cast(storage))); +} + +void read_int(const void* data, uint64_t& storage) { + uint32_t first; + uint32_t second; + read_int(data, first); + read_int(reinterpret_cast(data) + sizeof(uint32_t), second); + storage = first | (static_cast(second) << sizeof(uint32_t)); +} + +// implemenation of our broker +behavior broker_impl(broker* self, connection_handle hdl, const actor& buddy) { + // we assume io_fsm manages a broker with exactly one connection, + // i.e., the connection ponted to by `hdl` + assert(self->num_connections() == 1); + // monitor buddy to quit broker if buddy is done + self->monitor(buddy); + self->set_down_handler([=](down_msg& dm) { + if (dm.source == buddy) { + aout(self) << "our buddy is down" << endl; + // quit for same reason + self->quit(dm.reason); + } + }); + // setup: we are exchanging only messages consisting of an atom + // (as uint64_t) and an integer value (int32_t) + self->configure_read(hdl, receive_policy::exactly(sizeof(uint64_t) + + sizeof(int32_t))); + // our message handlers + return { + [=](const connection_closed_msg& msg) { + // brokers can multiplex any number of connections, however + // this example assumes io_fsm to manage a broker with + // exactly one connection + if (msg.handle == hdl) { + aout(self) << "connection closed" << endl; + // force buddy to quit + self->send_exit(buddy, exit_reason::remote_link_unreachable); + self->quit(exit_reason::remote_link_unreachable); + } + }, + [=](atom_value av, int32_t i) { + assert(av == ping_atom::value || av == pong_atom::value); + aout(self) << "send {" << to_string(av) << ", " << i << "}" << endl; + // cast atom to its underlying type, i.e., uint64_t + write_int(self, hdl, static_cast(av)); + write_int(self, hdl, i); + }, + [=](const new_data_msg& msg) { + // read the atom value as uint64_t from buffer + uint64_t atm_val; + read_int(msg.buf.data(), atm_val); + // cast to original type + auto atm = static_cast(atm_val); + // read integer value from buffer, jumping to the correct + // position via offset_data(...) + int32_t ival; + read_int(msg.buf.data() + sizeof(uint64_t), ival); + // show some output + aout(self) << "received {" << to_string(atm) << ", " << ival << "}" + << endl; + // send composed message to our buddy + self->send(buddy, atm, ival); + } + }; +} + +behavior server(broker* self, const actor& buddy) { + aout(self) << "server is running" << endl; + return { + [=](const new_connection_msg& msg) { + aout(self) << "server accepted new connection" << endl; + // by forking into a new broker, we are no longer + // responsible for the connection + auto impl = self->fork(broker_impl, msg.handle, buddy); + print_on_exit(impl, "broker_impl"); + aout(self) << "quit server (only accept 1 connection)" << endl; + self->quit(); + } + }; +} + +class config : public actor_system_config { +public: + uint16_t port = 0; + std::string host = "localhost"; + bool server_mode = false; + + config() { + opt_group{custom_options_, "global"} + .add(port, "port,p", "set port") + .add(host, "host,H", "set host (ignored in server mode)") + .add(server_mode, "server-mode,s", "enable server mode"); + } +}; + +void run_server(actor_system& system, const config& cfg) { + cout << "run in server mode" << endl; + auto pong_actor = system.spawn(pong); + auto server_actor = system.middleman().spawn_server(server, cfg.port, + pong_actor); + if (!server_actor) { + std::cerr << "failed to spawn server: " + << system.render(server_actor.error()) << endl; + return; + } + print_on_exit(*server_actor, "server"); + print_on_exit(pong_actor, "pong"); +} + +void run_client(actor_system& system, const config& cfg) { + auto ping_actor = system.spawn(ping, size_t{20}); + auto io_actor = system.middleman().spawn_client(broker_impl, cfg.host, + cfg.port, ping_actor); + if (!io_actor) { + std::cerr << "failed to spawn client: " + << system.render(io_actor.error()) << endl; + return; + } + print_on_exit(ping_actor, "ping"); + print_on_exit(*io_actor, "protobuf_io"); + send_as(*io_actor, ping_actor, kickoff_atom::value, *io_actor); +} + +void caf_main(actor_system& system, const config& cfg) { + auto f = cfg.server_mode ? run_server : run_client; + f(system, cfg); +} + +} // namespace + +CAF_MAIN(io::middleman) diff -Nru actor-framework-0.13.2/examples/broker/simple_http_broker.cpp actor-framework-0.16.3/examples/broker/simple_http_broker.cpp --- actor-framework-0.13.2/examples/broker/simple_http_broker.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/broker/simple_http_broker.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,97 @@ +#include +#include + +#include "caf/all.hpp" +#include "caf/io/all.hpp" + +using std::cout; +using std::cerr; +using std::endl; + +using namespace caf; +using namespace caf::io; + +namespace { + +using tick_atom = atom_constant; + +constexpr const char http_ok[] = R"__(HTTP/1.1 200 OK +Content-Type: text/plain +Connection: keep-alive +Transfer-Encoding: chunked + +d +Hi there! :) + +0 + + +)__"; + +template +constexpr size_t cstr_size(const char (&)[Size]) { + return Size; +} + +behavior connection_worker(broker* self, connection_handle hdl) { + self->configure_read(hdl, receive_policy::at_most(1024)); + return { + [=](const new_data_msg& msg) { + self->write(msg.handle, cstr_size(http_ok), http_ok); + self->quit(); + }, + [=](const connection_closed_msg&) { + self->quit(); + } + }; +} + +behavior server(broker* self) { + auto counter = std::make_shared(0); + self->set_down_handler([=](down_msg&) { + ++*counter; + }); + self->delayed_send(self, std::chrono::seconds(1), tick_atom::value); + return { + [=](const new_connection_msg& ncm) { + auto worker = self->fork(connection_worker, ncm.handle); + self->monitor(worker); + self->link_to(worker); + }, + [=](tick_atom) { + aout(self) << "Finished " << *counter << " requests per second." << endl; + *counter = 0; + self->delayed_send(self, std::chrono::seconds(1), tick_atom::value); + } + }; +} + +class config : public actor_system_config { +public: + uint16_t port = 0; + + config() { + opt_group{custom_options_, "global"} + .add(port, "port,p", "set port"); + } +}; + +void caf_main(actor_system& system, const config& cfg) { + auto server_actor = system.middleman().spawn_server(server, cfg.port); + if (!server_actor) { + cerr << "*** cannot spawn server: " + << system.render(server_actor.error()) << endl; + return; + } + cout << "*** listening on port " << cfg.port << endl; + cout << "*** to quit the program, simply press " << endl; + // wait for any input + std::string dummy; + std::getline(std::cin, dummy); + // kill server + anon_send_exit(*server_actor, exit_reason::user_shutdown); +} + +} // namespace + +CAF_MAIN(io::middleman) diff -Nru actor-framework-0.13.2/examples/brokers/protobuf_broker.cpp actor-framework-0.16.3/examples/brokers/protobuf_broker.cpp --- actor-framework-0.13.2/examples/brokers/protobuf_broker.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/brokers/protobuf_broker.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,170 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -#include "caf/all.hpp" -#include "caf/io/all.hpp" - -CAF_PUSH_WARNINGS -#include "pingpong.pb.h" -CAF_POP_WARNINGS - -using namespace std; -using namespace caf; -using namespace caf::io; - -void print_on_exit(const actor& ptr, const std::string& name) { - ptr->attach_functor([=](std::uint32_t reason) { - aout(ptr) << name << " exited with reason " << reason << endl; - }); -} - -behavior ping(event_based_actor* self, size_t num_pings) { - auto count = make_shared(0); - return { - on(atom("kickoff"), arg_match) >> [=](const actor& pong) { - self->send(pong, atom("ping"), 1); - self->become ( - on(atom("pong"), arg_match) >> [=](int value) -> message { - if (++*count >= num_pings) self->quit(); - return make_message(atom("ping"), value + 1); - } - ); - } - }; -} - -behavior pong() { - return { - on(atom("ping"), arg_match) >> [](int value) { - return make_message(atom("pong"), value); - } - }; -} - -void protobuf_io(broker* self, connection_handle hdl, const actor& buddy) { - self->monitor(buddy); - auto write = [=](const org::libcppa::PingOrPong& p) { - string buf = p.SerializeAsString(); - int32_t s = htonl(static_cast(buf.size())); - self->write(hdl, sizeof(int32_t), &s); - self->write(hdl, buf.size(), buf.data()); - self->flush(hdl); - }; - message_handler default_bhvr = { - [=](const connection_closed_msg&) { - aout(self) << "connection closed" << endl; - self->send_exit(buddy, exit_reason::remote_link_unreachable); - self->quit(exit_reason::remote_link_unreachable); - }, - on(atom("ping"), arg_match) >> [=](int i) { - aout(self) << "'ping' " << i << endl; - org::libcppa::PingOrPong p; - p.mutable_ping()->set_id(i); - write(p); - }, - on(atom("pong"), arg_match) >> [=](int i) { - aout(self) << "'pong' " << i << endl; - org::libcppa::PingOrPong p; - p.mutable_pong()->set_id(i); - write(p); - }, - [=](const down_msg& dm) { - if (dm.source == buddy) { - aout(self) << "our buddy is down" << endl; - self->quit(dm.reason); - } - }, - others >> [=] { - cout << "unexpected: " << to_string(self->current_message()) << endl; - } - }; - auto await_protobuf_data = message_handler { - [=](const new_data_msg& msg) { - org::libcppa::PingOrPong p; - p.ParseFromArray(msg.buf.data(), static_cast(msg.buf.size())); - if (p.has_ping()) { - self->send(buddy, atom("ping"), p.ping().id()); - } - else if (p.has_pong()) { - self->send(buddy, atom("pong"), p.pong().id()); - } - else { - self->quit(exit_reason::user_shutdown); - cerr << "neither Ping nor Pong!" << endl; - } - // receive next length prefix - self->configure_read(hdl, receive_policy::exactly(sizeof(int32_t))); - self->unbecome(); - } - }.or_else(default_bhvr); - auto await_length_prefix = message_handler { - [=](const new_data_msg& msg) { - int32_t num_bytes; - memcpy(&num_bytes, msg.buf.data(), sizeof(int32_t)); - num_bytes = htonl(num_bytes); - if (num_bytes < 0 || num_bytes > (1024 * 1024)) { - aout(self) << "someone is trying something nasty" << endl; - self->quit(exit_reason::user_shutdown); - return; - } - // receive protobuf data - auto nb = static_cast(num_bytes); - self->configure_read(hdl, receive_policy::exactly(nb)); - self->become(keep_behavior, await_protobuf_data); - } - }.or_else(default_bhvr); - // initial setup - self->configure_read(hdl, receive_policy::exactly(sizeof(int32_t))); - self->become(await_length_prefix); -} - -behavior server(broker* self, actor buddy) { - aout(self) << "server is running" << endl; - return { - [=](const new_connection_msg& msg) { - aout(self) << "server accepted new connection" << endl; - auto io_actor = self->fork(protobuf_io, msg.handle, buddy); - print_on_exit(io_actor, "protobuf_io"); - // only accept 1 connection in our example - self->quit(); - }, - others >> [=] { - cout << "unexpected: " << to_string(self->current_message()) << endl; - } - }; -} - -optional as_u16(const std::string& str) { - return static_cast(stoul(str)); -} - -int main(int argc, char** argv) { - message_builder{argv + 1, argv + argc}.apply({ - on("-s", as_u16) >> [&](uint16_t port) { - cout << "run in server mode" << endl; - auto pong_actor = spawn(pong); - auto sever_actor = spawn_io_server(server, port, pong_actor); - print_on_exit(sever_actor, "server"); - print_on_exit(pong_actor, "pong"); - }, - on("-c", val, as_u16) >> [&](const string& host, uint16_t port) { - auto ping_actor = spawn(ping, 20); - auto io_actor = spawn_io_client(protobuf_io, host, port, ping_actor); - print_on_exit(io_actor, "protobuf_io"); - print_on_exit(ping_actor, "ping"); - send_as(io_actor, ping_actor, atom("kickoff"), io_actor); - }, - others >> [] { - cerr << "use with eihter '-s PORT' as server or " - "'-c HOST PORT' as client" - << endl; - } - }); - await_all_actors_done(); - shutdown(); -} diff -Nru actor-framework-0.13.2/examples/brokers/simple_broker.cpp actor-framework-0.16.3/examples/brokers/simple_broker.cpp --- actor-framework-0.13.2/examples/brokers/simple_broker.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/brokers/simple_broker.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,208 +0,0 @@ -/******************************************************************************\ - * This example program showcases how to manually manage socket IO using * - * a broker. Server and client exchange integers in a 'ping-pong protocol'. * - * * - * Minimal setup: * - * - ./build/bin/broker -s 4242 * - * - ./build/bin/broker -c localhost 4242 * -\ ******************************************************************************/ - -#ifdef WIN32 -# define _WIN32_WINNT 0x0600 -# include -#else -# include // htonl -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "caf/all.hpp" -#include "caf/io/all.hpp" - -using std::cout; -using std::cerr; -using std::endl; - -using namespace caf; -using namespace caf::io; - -using ping_atom = atom_constant; -using pong_atom = atom_constant; -using kickoff_atom = atom_constant; - -// utility function to print an exit message with custom name -void print_on_exit(const actor& ptr, const std::string& name) { - ptr->attach_functor([=](uint32_t reason) { - aout(ptr) << name << " exited with reason " << reason << endl; - }); -} - -behavior ping(event_based_actor* self, size_t num_pings) { - auto count = std::make_shared(0); - return { - [=](kickoff_atom, const actor& pong) { - self->send(pong, ping_atom::value, int32_t(1)); - self->become ( - [=](pong_atom, int32_t value) -> message { - if (++*count >= num_pings) self->quit(); - return make_message(ping_atom::value, value + 1); - } - ); - } - }; -} - -behavior pong() { - return { - [](ping_atom, int32_t value) { - return make_message(pong_atom::value, value); - } - }; -} - -// utility function for sending an integer type -template -void write_int(broker* self, connection_handle hdl, T value) { - using unsigned_type = typename std::make_unsigned::type; - auto cpy = static_cast(htonl(static_cast(value))); - self->write(hdl, sizeof(T), &cpy); - 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(value)); - write_int(self, hdl, static_cast(value >> sizeof(uint32_t))); -} - -// utility function for reading an ingeger from incoming data -template -void read_int(const void* data, T& storage) { - using unsigned_type = typename std::make_unsigned::type; - memcpy(&storage, data, sizeof(T)); - storage = static_cast(ntohl(static_cast(storage))); -} - -void read_int(const void* data, uint64_t& storage) { - uint32_t first; - uint32_t second; - read_int(data, first); - read_int(reinterpret_cast(data) + sizeof(uint32_t), second); - storage = first | (static_cast(second) << sizeof(uint32_t)); -} - -// implemenation of our broker -behavior broker_impl(broker* self, connection_handle hdl, const actor& buddy) { - // we assume io_fsm manages a broker with exactly one connection, - // i.e., the connection ponted to by `hdl` - assert(self->num_connections() == 1); - // monitor buddy to quit broker if buddy is done - self->monitor(buddy); - // setup: we are exchanging only messages consisting of an atom - // (as uint64_t) and an integer value (int32_t) - self->configure_read(hdl, receive_policy::exactly(sizeof(uint64_t) + - sizeof(int32_t))); - // our message handlers - return { - [=](const connection_closed_msg& msg) { - // brokers can multiplex any number of connections, however - // this example assumes io_fsm to manage a broker with - // exactly one connection - if (msg.handle == hdl) { - aout(self) << "connection closed" << endl; - // force buddy to quit - self->send_exit(buddy, exit_reason::remote_link_unreachable); - self->quit(exit_reason::remote_link_unreachable); - } - }, - [=](atom_value av, int32_t i) { - assert(av == ping_atom::value || av == pong_atom::value); - aout(self) << "send {" << to_string(av) << ", " << i << "}" << endl; - // cast atom to its underlying type, i.e., uint64_t - write_int(self, hdl, static_cast(av)); - write_int(self, hdl, i); - }, - [=](const down_msg& dm) { - if (dm.source == buddy) { - aout(self) << "our buddy is down" << endl; - // quit for same reason - self->quit(dm.reason); - } - }, - [=](const new_data_msg& msg) { - // read the atom value as uint64_t from buffer - uint64_t atm_val; - read_int(msg.buf.data(), atm_val); - // cast to original type - auto atm = static_cast(atm_val); - // read integer value from buffer, jumping to the correct - // position via offset_data(...) - int32_t ival; - read_int(msg.buf.data() + sizeof(uint64_t), ival); - // show some output - aout(self) << "received {" << to_string(atm) << ", " << ival << "}" - << endl; - // send composed message to our buddy - self->send(buddy, atm, ival); - }, - others >> [=] { - aout(self) << "unexpected: " - << to_string(self->current_message()) << endl; - } - }; -} - -behavior server(broker* self, const actor& buddy) { - aout(self) << "server is running" << endl; - return { - [=](const new_connection_msg& msg) { - aout(self) << "server accepted new connection" << endl; - // by forking into a new broker, we are no longer - // responsible for the connection - auto impl = self->fork(broker_impl, msg.handle, buddy); - print_on_exit(impl, "broker_impl"); - aout(self) << "quit server (only accept 1 connection)" << endl; - self->quit(); - }, - others >> [=] { - aout(self) << "unexpected: " - << to_string(self->current_message()) << endl; - } - }; -} - -optional as_u16(const std::string& str) { - return static_cast(stoul(str)); -} - -int main(int argc, char** argv) { - using std::string; - message_builder{argv + 1, argv + argc}.apply({ - on("-s", as_u16) >> [&](uint16_t port) { - cout << "run in server mode" << endl; - auto pong_actor = spawn(pong); - auto server_actor = spawn_io_server(server, port, pong_actor); - print_on_exit(server_actor, "server"); - print_on_exit(pong_actor, "pong"); - }, - on("-c", val, as_u16) >> [&](const string& host, uint16_t port) { - auto ping_actor = spawn(ping, 20); - auto io_actor = spawn_io_client(broker_impl, host, port, ping_actor); - print_on_exit(io_actor, "protobuf_io"); - print_on_exit(ping_actor, "ping"); - send_as(io_actor, ping_actor, kickoff_atom::value, io_actor); - }, - others >> [] { - cerr << "use with eihter '-s PORT' as server or '-c HOST PORT' as client" - << endl; - } - }); - await_all_actors_done(); - shutdown(); -} diff -Nru actor-framework-0.13.2/examples/brokers/simple_http_broker.cpp actor-framework-0.16.3/examples/brokers/simple_http_broker.cpp --- actor-framework-0.13.2/examples/brokers/simple_http_broker.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/brokers/simple_http_broker.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -#include -#include - -#include "caf/all.hpp" -#include "caf/io/all.hpp" - -using std::cout; -using std::cerr; -using std::endl; - -using namespace caf; -using namespace caf::io; - -using tick_atom = atom_constant; - -const char http_ok[] = R"__(HTTP/1.1 200 OK -Content-Type: text/plain -Connection: keep-alive -Transfer-Encoding: chunked - -d -Hi there! :) - -0 - - -)__"; - -template -constexpr size_t cstr_size(const char (&)[Size]) { - return Size; -} - -behavior connection_worker(broker* self, connection_handle hdl) { - self->configure_read(hdl, receive_policy::at_most(1024)); - return { - [=](const new_data_msg& msg) { - self->write(msg.handle, cstr_size(http_ok), http_ok); - self->quit(); - }, - [=](const connection_closed_msg&) { - self->quit(); - } - }; -} - -behavior server(broker* self) { - auto counter = std::make_shared(0); - self->delayed_send(self, std::chrono::seconds(1), tick_atom::value); - return { - [=](const new_connection_msg& ncm) { - auto worker = self->fork(connection_worker, ncm.handle); - self->monitor(worker); - self->link_to(worker); - }, - [=](const down_msg&) { - ++*counter; - }, - [=](tick_atom) { - aout(self) << "Finished " << *counter << " requests per second." << endl; - *counter = 0; - self->delayed_send(self, std::chrono::seconds(1), tick_atom::value); - }, - others >> [=] { - aout(self) << "unexpected: " << to_string(self->current_message()) << endl; - } - }; -} - -optional as_u16(const std::string& str) { - return static_cast(stoul(str)); -} - -int main(int argc, const char **argv) { - message_builder{argv + 1, argv + argc}.apply({ - on("-p", as_u16) >> [&](uint16_t port) { - cout << "*** run in server mode listen on: " << port << endl; - cout << "*** to quit the program, simply press " << endl; - auto server_actor = spawn_io_server(server, port); - // wait for any input - std::string dummy; - std::getline(std::cin, dummy); - // kill server - anon_send_exit(server_actor, exit_reason::user_shutdown); - }, - others >> [] { - cerr << "use with '-p PORT' as server on port" << endl; - } - }); - await_all_actors_done(); - shutdown(); -} diff -Nru actor-framework-0.13.2/examples/caf-application.ini actor-framework-0.16.3/examples/caf-application.ini --- actor-framework-0.13.2/examples/caf-application.ini 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/caf-application.ini 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,77 @@ +; This file shows all possible parameters with defaults. +; Values enclosed in <> are detected at runtime unless defined by the user. + +; when using the default scheduler +[scheduler] +; accepted alternative: 'sharing' +policy='stealing' +; configures whether the scheduler generates profiling output +enable-profiling=false +; forces a fixed number of threads if set +max-threads= +; maximum number of messages actors can consume in one run +max-throughput= +; measurement resolution in milliseconds (only if profiling is enabled) +profiling-resolution=100ms +; output file for profiler data (only if profiling is enabled) +profiling-output-file="/dev/null" + +; when using 'stealing' as scheduler policy +[work-stealing] +; number of zero-sleep-interval polling attempts +aggressive-poll-attempts=100 +; frequency of steal attempts during aggressive polling +aggressive-steal-interval=10 +; number of moderately aggressive polling attempts +moderate-poll-attempts=500 +; frequency of steal attempts during moderate polling +moderate-steal-interval=5 +; sleep interval between poll attempts +moderate-sleep-duration=50us +; frequency of steal attempts during relaxed polling +relaxed-steal-interval=1 +; sleep interval between poll attempts +relaxed-sleep-duration=10ms + +; when loading io::middleman +[middleman] +; configures whether MMs try to span a full mesh +enable-automatic-connections=false +; application identifier of this node, prevents connection to other CAF +; instances with different identifier +app-identifier="" +; maximum number of consecutive I/O reads per broker +max-consecutive-reads=50 +; heartbeat message interval in ms (0 disables heartbeating) +heartbeat-interval=0ms +; configures whether the MM attaches its internal utility actors to the +; scheduler instead of dedicating individual threads (needed only for +; deterministic testing) +attach-utility-actors=false +; configures whether the MM starts a background thread for I/O activity, +; setting this to true allows fully deterministic execution in unit test and +; requires the user to trigger I/O manually +manual-multiplexing=false +; disables communication via TCP +disable-tcp=false +; enable communication via UDP +enable-udp=false + +; when compiling with logging enabled +[logger] +; file name template for output log file files (empty string disables logging) +file-name="actor_log_[PID]_[TIMESTAMP]_[NODE].log" +; format for rendering individual log file entries +file-format="%r %c %p %a %t %C %M %F:%L %m%n" +; configures the minimum severity of messages that are written to the log file +; (quiet|error|warning|info|debug|trace) +file-verbosity='trace' +; mode for console log output generation (none|colored|uncolored) +console='none' +; format for printing individual log entries to the console +console-format="%m" +; configures the minimum severity of messages that are written to the console +; (quiet|error|warning|info|debug|trace) +console-verbosity='trace' +; excludes listed components from logging +component-filter="" diff -Nru actor-framework-0.13.2/examples/CMakeLists.txt actor-framework-0.16.3/examples/CMakeLists.txt --- actor-framework-0.13.2/examples/CMakeLists.txt 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/CMakeLists.txt 2018-12-27 20:33:32.000000000 +0000 @@ -5,55 +5,72 @@ include_directories(${LIBCAF_INCLUDE_DIRS}) -if(${CMAKE_SYSTEM_NAME} MATCHES "Window") - set(WSLIB -lws2_32) -else () - set(WSLIB) -endif() - -macro(add name folder) +macro(add folder name) add_executable(${name} ${folder}/${name}.cpp ${ARGN}) target_link_libraries(${name} - ${LD_FLAGS} - ${LIBCAF_LIBRARIES} - ${PTHREAD_LIBRARIES} - ${WSLIB}) + ${CAF_EXTRA_LDFLAGS} + ${CAF_LIBRARIES} + ${PTHREAD_LIBRARIES}) install(FILES ${folder}/${name}.cpp DESTINATION share/caf/examples/${folder}) add_dependencies(${name} all_examples) endmacro() -add(announce_1 type_system) -add(announce_2 type_system) -add(announce_3 type_system) -add(announce_4 type_system) -add(announce_5 type_system) -add(dancing_kirby message_passing) -add(dining_philosophers message_passing) -add(hello_world .) -add(aout .) -add(calculator message_passing) -add(typed_calculator message_passing) -add(distributed_calculator remote_actors) -add(group_server remote_actors) -add(group_chat remote_actors) -add(simple_broker brokers) -add(simple_http_broker brokers) +# introductionary applications +add(. aout) +add(. hello_world) + +# basic message passing primitives +add(message_passing calculator) +add(message_passing cell) +add(message_passing dancing_kirby) +add(message_passing delegating) +add(message_passing divider) +add(message_passing fixed_stack) +add(message_passing promises) +add(message_passing request) +add(message_passing typed_calculator) + +# streaming API +add(streaming integer_stream) + +# dynamic behavior changes using 'become' +add(dynamic_behavior skip_messages) +add(dynamic_behavior dining_philosophers) + +# composing actors using states or other actors +add(composition calculator_behavior) +add(composition dictionary_behavior) + +# adding custom message types +add(custom_type custom_types_1) +add(custom_type custom_types_2) +add(custom_type custom_types_3) + +# basic remoting +add(remoting group_chat) +add(remoting group_server) +add(remoting remote_spawn) +add(remoting distributed_calculator) + +# basic I/O with brokers +add(broker simple_broker) +add(broker simple_http_broker) -if(NOT CAF_NO_PROTOBUF_EXAMPLES) +if(CAF_BUILD_PROTOBUF_EXAMPLES) find_package(Protobuf) if(PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE) - PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders "${CMAKE_CURRENT_SOURCE_DIR}/remote_actors/pingpong.proto") + PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders "${CMAKE_CURRENT_SOURCE_DIR}/remoting/pingpong.proto") include_directories(${PROTOBUF_INCLUDE_DIR}) # add binary dir as include path as generated headers will be located there include_directories(${CMAKE_CURRENT_BINARY_DIR}) - add_executable(protobuf_broker brokers/protobuf_broker.cpp ${ProtoSources}) - target_link_libraries(protobuf_broker ${CMAKE_DL_LIBS} ${LIBCAF_LIBRARIES} ${PTHREAD_LIBRARIES} ${PROTOBUF_LIBRARIES}) + add_executable(protobuf_broker broker/protobuf_broker.cpp ${ProtoSources}) + target_link_libraries(protobuf_broker ${CMAKE_DL_LIBS} ${CAF_LIBRARIES} ${PTHREAD_LIBRARIES} ${PROTOBUF_LIBRARIES}) add_dependencies(protobuf_broker all_examples) endif(PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE) endif() -if(NOT CAF_NO_QT_EXAMPLES) - find_package(Qt5 COMPONENTS Core Gui Widgets) +if(CAF_BUILD_QT_EXAMPLES) + find_package(Qt5 COMPONENTS Core Gui Widgets QUIET) if(Qt5_FOUND) message(STATUS "Found Qt5") #include(${QT_USE_FILE}) @@ -74,7 +91,7 @@ ${GROUP_CHAT_UI_HDR}) target_link_libraries(qt_group_chat ${CMAKE_DL_LIBS} - ${LIBCAF_LIBRARIES} + ${CAF_LIBRARIES} Qt5::Core Qt5::Gui Qt5::Widgets) @@ -97,7 +114,7 @@ ${GROUP_CHAT_UI_HDR}) target_link_libraries(qt_group_chat ${CMAKE_DL_LIBS} - ${LIBCAF_LIBRARIES} + ${CAF_LIBRARIES} ${QT_LIBRARIES}) add_dependencies(qt_group_chat all_examples) endif() @@ -109,7 +126,7 @@ 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}) + target_link_libraries(curl_fuse ${CMAKE_DL_LIBS} ${CAF_LIBRARIES} ${PTHREAD_LIBRARIES} ${CURL_LIBRARY}) add_dependencies(curl_fuse all_examples) endif(CURL_FOUND) endif() diff -Nru actor-framework-0.13.2/examples/composition/calculator_behavior.cpp actor-framework-0.16.3/examples/composition/calculator_behavior.cpp --- actor-framework-0.13.2/examples/composition/calculator_behavior.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/composition/calculator_behavior.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,51 @@ +/******************************************************************************\ + * This example is a very basic, non-interactive math service implemented * + * using composable states. * +\******************************************************************************/ + +// This file is partially included in the manual, do not modify +// without updating the references in the *.tex files! +// Manual references: lines 20-52 (Actor.tex) + +#include + +#include "caf/all.hpp" + +using std::cout; +using std::endl; +using namespace caf; + +namespace { + +// using add_atom = atom_constant; (defined in atom.hpp) +using multiply_atom = atom_constant; + +using adder = typed_actor::with>; +using multiplier = typed_actor::with>; + +class adder_bhvr : public composable_behavior { +public: + result operator()(add_atom, int x, int y) override { + return x + y; + } +}; + +class multiplier_bhvr : public composable_behavior { +public: + result operator()(multiply_atom, int x, int y) override { + return x * y; + } +}; + +// calculator_bhvr can be inherited from or composed further +using calculator_bhvr = composed_behavior; + +} // namespace + +void caf_main(actor_system& system) { + auto f = make_function_view(system.spawn()); + cout << "10 + 20 = " << f(add_atom::value, 10, 20) << endl; + cout << "7 * 9 = " << f(multiply_atom::value, 7, 9) << endl; +} + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/composition/dictionary_behavior.cpp actor-framework-0.16.3/examples/composition/dictionary_behavior.cpp --- actor-framework-0.13.2/examples/composition/dictionary_behavior.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/composition/dictionary_behavior.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,54 @@ +/******************************************************************************\ + * This example is a simple dictionary implemented * using composable states. * +\******************************************************************************/ + +// This file is partially included in the manual, do not modify +// without updating the references in the *.tex files! +// Manual references: lines 22-44 (Actor.tex) + +#include +#include +#include + +#include "caf/all.hpp" + +using std::cout; +using std::endl; +using std::string; +using namespace caf; + +namespace { + +using dict = typed_actor, + replies_to::with>; + +class dict_behavior : public composable_behavior { +public: + result operator()(get_atom, param key) override { + auto i = values_.find(key); + if (i == values_.end()) + return ""; + return i->second; + } + + result operator()(put_atom, param key, + param value) override { + if (values_.count(key) != 0) + return unit; + values_.emplace(key.move(), value.move()); + return unit; + } + +protected: + std::unordered_map values_; +}; + +} // namespace + +void caf_main(actor_system& system) { + auto f = make_function_view(system.spawn()); + f(put_atom::value, "CAF", "success"); + cout << "CAF is the key to " << f(get_atom::value, "CAF") << endl; +} + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/curl/curl_fuse.cpp actor-framework-0.16.3/examples/curl/curl_fuse.cpp --- actor-framework-0.13.2/examples/curl/curl_fuse.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/curl/curl_fuse.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -1,4 +1,4 @@ -/******************************************************************************\ +/****************************************************************************** * This example * * - emulates a client launching a request every 10-300ms * * - uses a CURL-backend consisting of a master and 10 workers * @@ -28,12 +28,12 @@ * | |<--/ * * | <-------------(reply)-------------- | * * X * -\ ******************************************************************************/ + ******************************************************************************/ // C includes -#include -#include -#include +#include +#include +#include // C++ includes #include @@ -41,13 +41,15 @@ #include #include -// libcurl -#include - -// libcaf +// CAF #include "caf/all.hpp" +#include "caf/io/all.hpp" + +CAF_PUSH_WARNINGS +#include +CAF_POP_WARNINGS -// disable some clang warnings here caused by CURL +// disable some clang warnings here caused by CURL macros #ifdef __clang__ # pragma clang diagnostic ignored "-Wshorten-64-to-32" # pragma clang diagnostic ignored "-Wdisabled-macro-expansion" @@ -97,287 +99,248 @@ // maximum delay between HTTP requests constexpr int max_req_interval = 300; -// provides print utility and each base_actor has a parent -class base_actor : public event_based_actor { - protected: - base_actor(actor parent, std::string name, std::string color_code) - : m_parent(std::move(parent)), - m_name(std::move(name)), - m_color(std::move(color_code)), - m_out(this) { +// put everything into anonymous namespace (except main) +namespace { + +// provides print utility, a name, and a parent +struct base_state { + base_state(local_actor* thisptr) : self(thisptr) { // nop } - ~base_actor(); - - inline actor_ostream& print() { - return m_out << m_color << m_name << " (id = " << id() << "): "; + actor_ostream print() { + return aout(self) << color << name << " (id = " << self->id() << "): "; } - void on_exit() { - print() << "on_exit" << color::reset_endl; + virtual bool init(std::string m_name, std::string m_color) { + name = std::move(m_name); + color = std::move(m_color); + print() << "started" << color::reset_endl; + return true; } - actor m_parent; - - private: - std::string m_name; - std::string m_color; - actor_ostream m_out; -}; - -base_actor::~base_actor() { - // avoid weak-vtables warning -} - -// encapsulates an HTTP request -class client_job : public base_actor { - public: - client_job(actor parent) - : base_actor(std::move(parent), "client_job", color::blue) { - // nop + virtual ~base_state() { + print() << "done" << color::reset_endl; } - ~client_job(); - - protected: - behavior make_behavior() override { - print() << "init" << color::reset_endl; - send(m_parent, read_atom::value, "http://www.example.com/index.html", - uint64_t{0}, uint64_t{4095}); - return { - [=](reply_atom, const buffer_type& buf) { - print() << "successfully received " << buf.size() << " bytes" - << color::reset_endl; - quit(); - }, - [=](fail_atom) { - print() << "failure" << color::reset_endl; - quit(); - } - }; - } + local_actor* self; + std::string name; + std::string color; }; -client_job::~client_job() { - // avoid weak-vtables warning +// encapsulates an HTTP request +behavior client_job(stateful_actor* self, const actor& parent) { + if (!self->state.init("client-job", color::blue)) + return {}; // returning an empty behavior terminates the actor + self->send(parent, read_atom::value, + "http://www.example.com/index.html", + uint64_t{0}, uint64_t{4095}); + return { + [=](reply_atom, const buffer_type& buf) { + self->state.print() << "successfully received " << buf.size() << " bytes" + << color::reset_endl; + self->quit(); + }, + [=](fail_atom) { + self->state.print() << "failure" << color::reset_endl; + self->quit(); + } + }; } -// spawns HTTP requests -class client : public base_actor { - public: - - client(const actor& parent) - : base_actor(parent, "client", color::green), - m_count(0), - m_re(m_rd()), - m_dist(min_req_interval, max_req_interval) { +struct client_state : base_state { + client_state(local_actor* selfptr) + : base_state(selfptr), + count(0), + re(rd()), + dist(min_req_interval, max_req_interval) { // nop } - ~client(); - - protected: - behavior make_behavior() override { - using std::chrono::milliseconds; - link_to(m_parent); - print() << "init" << color::reset_endl; - // start 'loop' - send(this, next_atom::value); - return ( - [=](next_atom) { - print() << "spawn new client_job (nr. " - << ++m_count - << ")" - << color::reset_endl; - // client_job will use IO - // and should thus be spawned in a separate thread - spawn(m_parent); - // compute random delay until next job is launched - auto delay = m_dist(m_re); - delayed_send(this, milliseconds(delay), next_atom::value); - } - ); - } - - private: - size_t m_count; - std::random_device m_rd; - std::default_random_engine m_re; - std::uniform_int_distribution m_dist; + size_t count; + std::random_device rd; + std::default_random_engine re; + std::uniform_int_distribution dist; }; -client::~client() { - // avoid weak-vtables warning +// spawns HTTP requests +behavior client(stateful_actor* self, const actor& parent) { + using std::chrono::milliseconds; + self->link_to(parent); + if (!self->state.init("client", color::green)) + return {}; // returning an empty behavior terminates the actor + self->send(self, next_atom::value); + return { + [=](next_atom) { + auto& st = self->state; + st.print() << "spawn new client_job (nr. " << ++st.count << ")" + << color::reset_endl; + // client_job will use IO + // and should thus be spawned in a separate thread + self->spawn(client_job, parent); + // compute random delay until next job is launched + auto delay = st.dist(st.re); + self->delayed_send(self, milliseconds(delay), next_atom::value); + } + }; } -// manages a CURL session -class curl_worker : public base_actor { - public: - curl_worker(const actor& parent) - : base_actor(parent, "curl_worker", color::yellow), - m_curl(nullptr) { +struct curl_state : base_state { + curl_state(local_actor* selfptr) : base_state(selfptr) { // nop } - ~curl_worker(); - - protected: - behavior make_behavior() override { - print() << "init" << color::reset_endl; - m_curl = curl_easy_init(); - curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, &curl_worker::cb); - curl_easy_setopt(m_curl, CURLOPT_NOSIGNAL, 1); - return ( - [=](read_atom, const std::string& fname, uint64_t offset, uint64_t range) - -> message { - print() << "read" << color::reset_endl; - for (;;) { - m_buf.clear(); - // set URL - curl_easy_setopt(m_curl, CURLOPT_URL, fname.c_str()); - // set range - std::ostringstream oss; - oss << offset << "-" << range; - curl_easy_setopt(m_curl, CURLOPT_RANGE, oss.str().c_str()); - // set curl callback - curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, - reinterpret_cast(this)); - // launch file transfer - auto res = curl_easy_perform(m_curl); - if (res != CURLE_OK) { - print() << "curl_easy_perform() failed: " - << curl_easy_strerror(res) - << color::reset_endl; - } else { - long hc = 0; // http return code - curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &hc); - switch (hc) { - default: - print() << "http error: download failed with " - << "'HTTP RETURN CODE': " - << hc - << color::reset_endl; - break; - case 200: // ok - case 206: // partial content - print() << "received " - << m_buf.size() - << " bytes with 'HTTP RETURN CODE': " - << hc - << color::reset_endl; - // tell parent that this worker is done - send(m_parent, finished_atom::value); - return make_message(reply_atom::value, m_buf); - case 404: // file does not exist - print() << "http error: download failed with " - << "'HTTP RETURN CODE': 404 (file does " - << "not exist!)" - << color::reset_endl; - } - } - // avoid 100% cpu utilization if remote side is not accessible - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - } - ); - } - - void on_exit() { - curl_easy_cleanup(m_curl); - print() << "on_exit" << color::reset_endl; + ~curl_state() override { + if (curl != nullptr) + curl_easy_cleanup(curl); } - private: - static size_t cb(void* data, size_t bsize, size_t nmemb, void* userp) { + static size_t callback(void* data, size_t bsize, size_t nmemb, void* userp) { size_t size = bsize * nmemb; - auto& buf = reinterpret_cast(userp)->m_buf; + auto& buf = reinterpret_cast(userp)->buf; auto first = reinterpret_cast(data); auto last = first + bsize; buf.insert(buf.end(), first, last); return size; } - CURL* m_curl; - 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: - curl_master() : base_actor(invalid_actor, "curl_master", color::magenta) { - // nop + bool init(std::string m_name, std::string m_color) override { + curl = curl_easy_init(); + if (curl == nullptr) + return false; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_state::callback); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + return base_state::init(std::move(m_name), std::move(m_color)); } - ~curl_master(); + CURL* curl = nullptr; + buffer_type buf; +}; - protected: - behavior make_behavior() override { - print() << "init" << color::reset_endl; - // spawn workers - for(size_t i = 0; i < num_curl_workers; ++i) { - m_idle_worker.push_back(spawn(this)); - } - auto worker_finished = [=] { - auto sender = current_sender(); - auto i = std::find(m_busy_worker.begin(), m_busy_worker.end(), sender); - m_idle_worker.push_back(*i); - m_busy_worker.erase(i); - print() << "worker is done" << color::reset_endl; - }; - print() << "spawned " << m_idle_worker.size() - << " worker(s)" << color::reset_endl; - return { - [=](read_atom, const std::string&, uint64_t, uint64_t) { - print() << "received {'read'}" << color::reset_endl; - // forward job to an idle worker - actor worker = m_idle_worker.back(); - m_idle_worker.pop_back(); - m_busy_worker.push_back(worker); - forward_to(worker); - print() << m_busy_worker.size() << " active jobs" << color::reset_endl; - if (m_idle_worker.empty()) { - // wait until at least one worker finished its job - become ( - keep_behavior, - [=](finished_atom) { - worker_finished(); - unbecome(); - } - ); +// manages a CURL session +behavior curl_worker(stateful_actor* self, const actor& parent) { + if (!self->state.init("curl-worker", color::yellow)) + return {}; // returning an empty behavior terminates the actor + return { + [=](read_atom, const std::string& fname, uint64_t offset, uint64_t range) + -> message { + auto& st = self->state; + st.print() << "read" << color::reset_endl; + for (;;) { + st.buf.clear(); + // set URL + curl_easy_setopt(st.curl, CURLOPT_URL, fname.c_str()); + // set range + std::ostringstream oss; + oss << offset << "-" << range; + curl_easy_setopt(st.curl, CURLOPT_RANGE, oss.str().c_str()); + // set curl callback + curl_easy_setopt(st.curl, CURLOPT_WRITEDATA, + reinterpret_cast(&st)); + // launch file transfer + auto res = curl_easy_perform(st.curl); + if (res != CURLE_OK) { + st.print() << "curl_easy_perform() failed: " + << curl_easy_strerror(res) + << color::reset_endl; + } else { + long hc = 0; // http return code + curl_easy_getinfo(st.curl, CURLINFO_RESPONSE_CODE, &hc); + switch (hc) { + default: + st.print() << "http error: download failed with " + << "'HTTP RETURN CODE': " + << hc + << color::reset_endl; + break; + case 200: // ok + case 206: // partial content + st.print() << "received " + << st.buf.size() + << " bytes with 'HTTP RETURN CODE': " + << hc + << color::reset_endl; + // tell parent that this worker is done + self->send(parent, finished_atom::value); + return make_message(reply_atom::value, std::move(st.buf)); + case 404: // file does not exist + st.print() << "http error: download failed with " + << "'HTTP RETURN CODE': 404 (file does " + << "not exist!)" + << color::reset_endl; + } } - }, - [=](finished_atom) { - worker_finished(); + // avoid 100% cpu utilization if remote side is not accessible + std::this_thread::sleep_for(std::chrono::milliseconds(100)); } - }; - } + } + }; +} - private: - std::vector m_idle_worker; - std::vector m_busy_worker; +struct master_state : base_state { + master_state(local_actor* selfptr) : base_state(selfptr) { + // nop + } + std::vector idle; + std::vector busy; }; -curl_master::~curl_master() { - // avoid weak-vtables warning +behavior curl_master(stateful_actor* self) { + if (!self->state.init("curl-master", color::magenta)) + return {}; // returning an empty behavior terminates the actor + // spawn workers + for(size_t i = 0; i < num_curl_workers; ++i) + self->state.idle.push_back(self->spawn(curl_worker, self)); + auto worker_finished = [=] { + auto sender = self->current_sender(); + auto last = self->state.busy.end(); + auto i = std::find(self->state.busy.begin(), last, sender); + if (i == last) + return; + self->state.idle.push_back(*i); + self->state.busy.erase(i); + self->state.print() << "worker is done" << color::reset_endl; + }; + self->state.print() << "spawned " << self->state.idle.size() + << " worker(s)" << color::reset_endl; + return { + [=](read_atom rd, std::string& str, uint64_t x, uint64_t y) { + auto& st = self->state; + st.print() << "received {'read'}" << color::reset_endl; + // forward job to an idle worker + actor worker = st.idle.back(); + st.idle.pop_back(); + st.busy.push_back(worker); + self->delegate(worker, rd, std::move(str), x, y); + st.print() << st.busy.size() << " active jobs" << color::reset_endl; + if (st.idle.empty()) { + // wait until at least one worker finished its job + self->become ( + keep_behavior, + [=](finished_atom) { + worker_finished(); + self->unbecome(); + } + ); + } + }, + [=](finished_atom) { + worker_finished(); + } + }; } // signal handling for ctrl+c -namespace { std::atomic shutdown_flag{false}; + } // namespace -int main() { - // random number setup +void caf_main(actor_system& system) { // install signal handler struct sigaction act; act.sa_handler = [](int) { shutdown_flag = true; }; auto set_sighandler = [&] { - if (sigaction(SIGINT, &act, 0)) { + if (sigaction(SIGINT, &act, nullptr) != 0) { std::cerr << "fatal: cannot set signal handler" << std::endl; abort(); } @@ -385,29 +348,27 @@ set_sighandler(); // initialize CURL curl_global_init(CURL_GLOBAL_DEFAULT); - { // lifetime scope of self - scoped_actor self; - // spawn client and curl_master - auto master = self->spawn(); - self->spawn(master); - // poll CTRL+C flag every second - while (!shutdown_flag) { - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - aout(self) << color::cyan << "received CTRL+C" << color::reset_endl; - // shutdown actors - anon_send_exit(master, exit_reason::user_shutdown); - // await actors - act.sa_handler = [](int) { abort(); }; - set_sighandler(); - aout(self) << color::cyan - << "await CURL; this may take a while " - "(press CTRL+C again to abort)" - << color::reset_endl; - self->await_all_other_actors_done(); - } - // shutdown libcaf - shutdown(); + // get a scoped actor for the communication with our CURL actors + scoped_actor self{system}; + // spawn client and curl_master + auto master = self->spawn(curl_master); + self->spawn(client, master); + // poll CTRL+C flag every second + while (!shutdown_flag) + std::this_thread::sleep_for(std::chrono::seconds(1)); + aout(self) << color::cyan << "received CTRL+C" << color::reset_endl; + // shutdown actors + anon_send_exit(master, exit_reason::user_shutdown); + // await actors + act.sa_handler = [](int) { abort(); }; + set_sighandler(); + aout(self) << color::cyan + << "await CURL; this may take a while " + "(press CTRL+C again to abort)" + << color::reset_endl; + self->await_all_other_actors_done(); // shutdown CURL curl_global_cleanup(); } + +CAF_MAIN(io::middleman) diff -Nru actor-framework-0.13.2/examples/custom_type/custom_types_1.cpp actor-framework-0.16.3/examples/custom_type/custom_types_1.cpp --- actor-framework-0.13.2/examples/custom_type/custom_types_1.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/custom_type/custom_types_1.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,123 @@ +// Showcases how to add custom POD message types. + +// Manual refs: 24-27, 30-34, 75-78, 81-84 (ConfiguringActorApplications) +// 23-33 (TypeInspection) + +#include +#include +#include +#include +#include + +#include "caf/all.hpp" + +using std::cout; +using std::cerr; +using std::endl; +using std::vector; + +using namespace caf; + +namespace { + +// POD struct foo +struct foo { + std::vector a; + int b; +}; + +// foo needs to be serializable +template +typename Inspector::result_type inspect(Inspector& f, foo& x) { + return f(meta::type_name("foo"), x.a, x.b); +} + +// a pair of two ints +using foo_pair = std::pair; + +// another alias for pairs of two ints +using foo_pair2 = std::pair; + +// a struct with a nested container +struct foo2 { + int a; + vector> b; +}; + +// foo2 also needs to be serializable +template +typename Inspector::result_type inspect(Inspector& f, foo2& x) { + return f(meta::type_name("foo2"), x.a, x.b); +} + +// receives our custom message types +void testee(event_based_actor* self, size_t remaining) { + auto set_next_behavior = [=] { + if (remaining > 1) + testee(self, remaining - 1); + else + self->quit(); + }; + self->become ( + // note: we sent a foo_pair2, but match on foo_pair + // that works because both are aliases for std::pair + [=](const foo_pair& val) { + aout(self) << "foo_pair" << deep_to_string(val) << endl; + set_next_behavior(); + }, + [=](const foo& val) { + aout(self) << to_string(val) << endl; + set_next_behavior(); + } + ); +} + +class config : public actor_system_config { +public: + config() { + add_message_type("foo"); + add_message_type("foo2"); + add_message_type("foo_pair"); + } +}; + +void caf_main(actor_system& system, const config&) { + // two variables for testing serialization + foo2 f1; + foo2 f2; + // init some test data + f1.a = 5; + f1.b.resize(1); + f1.b.back().push_back(42); + // I/O buffer + vector buf; + // write f1 to buffer + binary_serializer bs{system, buf}; + auto e = bs(f1); + if (e) { + std::cerr << "*** unable to serialize foo2: " + << system.render(e) << std::endl; + return; + } + // read f2 back from buffer + binary_deserializer bd{system, buf}; + e = bd(f2); + if (e) { + std::cerr << "*** unable to serialize foo2: " + << system.render(e) << std::endl; + return; + } + // must be equal + assert(to_string(f1) == to_string(f2)); + // spawn a testee that receives two messages of user-defined type + auto t = system.spawn(testee, 2u); + scoped_actor self{system}; + // send t a foo + self->send(t, foo{std::vector{1, 2, 3, 4}, 5}); + // send t a foo_pair2 + self->send(t, foo_pair2{3, 4}); +} + +} // namespace + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/custom_type/custom_types_2.cpp actor-framework-0.16.3/examples/custom_type/custom_types_2.cpp --- actor-framework-0.13.2/examples/custom_type/custom_types_2.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/custom_type/custom_types_2.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,74 @@ +// showcases how to add custom message types to CAF +// if friend access for serialization is available + +#include +#include + +#include "caf/all.hpp" + +using std::cout; +using std::endl; +using std::make_pair; + +using namespace caf; + +namespace { + +// a simple class using getter and setter member functions +class foo { +public: + foo(int a0 = 0, int b0 = 0) : a_(a0), b_(b0) { + // nop + } + + foo(const foo&) = default; + foo& operator=(const foo&) = default; + + int a() const { + return a_; + } + + void set_a(int val) { + a_ = val; + } + + int b() const { + return b_; + } + + void set_b(int val) { + b_ = val; + } + + template + friend typename Inspector::result_type inspect(Inspector& f, foo& x) { + return f(meta::type_name("foo"), x.a_, x.b_); + } + +private: + int a_; + int b_; +}; + +behavior testee(event_based_actor* self) { + return { + [=](const foo& x) { + aout(self) << to_string(x) << endl; + } + }; +} + +class config : public actor_system_config { +public: + config() { + add_message_type("foo"); + } +}; + +void caf_main(actor_system& system, const config&) { + anon_send(system.spawn(testee), foo{1, 2}); +} + +} // namespace + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/custom_type/custom_types_3.cpp actor-framework-0.16.3/examples/custom_type/custom_types_3.cpp --- actor-framework-0.13.2/examples/custom_type/custom_types_3.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/custom_type/custom_types_3.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,118 @@ +// Showcases custom message types that cannot provide +// friend access to the inspect() function. + +// Manual refs: 20-49, 76-103 (TypeInspection) + +#include +#include + +#include "caf/all.hpp" + +using std::cout; +using std::endl; +using std::make_pair; + +using namespace caf; + +namespace { + +// identical to our second custom type example, but +// no friend access for `inspect` +class foo { +public: + foo(int a0 = 0, int b0 = 0) : a_(a0), b_(b0) { + // nop + } + + foo(const foo&) = default; + foo& operator=(const foo&) = default; + + int a() const { + return a_; + } + + void set_a(int val) { + a_ = val; + } + + int b() const { + return b_; + } + + void set_b(int val) { + b_ = val; + } + +private: + int a_; + int b_; +}; + +// A lightweight scope guard implementation. +template +class scope_guard { +public: + scope_guard(Fun f) : fun_(std::move(f)), enabled_(true) { } + + scope_guard(scope_guard&& x) : fun_(std::move(x.fun_)), enabled_(x.enabled_) { + x.enabled_ = false; + } + + ~scope_guard() { + if (enabled_) fun_(); + } + +private: + Fun fun_; + bool enabled_; +}; + +// Creates a guard that executes `f` as soon as it goes out of scope. +template +scope_guard make_scope_guard(Fun f) { + return {std::move(f)}; +} + +template +typename std::enable_if::type +inspect(Inspector& f, foo& x) { + return f(meta::type_name("foo"), x.a(), x.b()); +} + +template +typename std::enable_if::type +inspect(Inspector& f, foo& x) { + int a; + int b; + // write back to x at scope exit + auto g = make_scope_guard([&] { + x.set_a(a); + x.set_b(b); + }); + return f(meta::type_name("foo"), a, b); +} + +behavior testee(event_based_actor* self) { + return { + [=](const foo& x) { + aout(self) << to_string(x) << endl; + } + }; +} + +class config : public actor_system_config { +public: + config() { + add_message_type("foo"); + } +}; + +void caf_main(actor_system& system, const config&) { + anon_send(system.spawn(testee), foo{1, 2}); +} + +} // namespace + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/dynamic_behavior/dining_philosophers.cpp actor-framework-0.16.3/examples/dynamic_behavior/dining_philosophers.cpp --- actor-framework-0.13.2/examples/dynamic_behavior/dining_philosophers.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/dynamic_behavior/dining_philosophers.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,212 @@ +/******************************************************************************\ + * This example is an implementation of the classical Dining Philosophers * + * exercise using only libcaf's event-based actor implementation. * +\******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "caf/all.hpp" + +using std::cout; +using std::cerr; +using std::endl; +using std::chrono::seconds; + +using namespace caf; + +namespace { + +// atoms for chopstick interface +using put_atom = atom_constant; +using take_atom = atom_constant; +using taken_atom = atom_constant; + +// atoms for philosopher interface +using eat_atom = atom_constant; +using think_atom = atom_constant; + +// a chopstick +using chopstick = typed_actor::with, + reacts_to>; + +chopstick::behavior_type taken_chopstick(chopstick::pointer, + const strong_actor_ptr&); + +// either taken by a philosopher or available +chopstick::behavior_type available_chopstick(chopstick::pointer self) { + return { + [=](take_atom) -> std::tuple { + self->become(taken_chopstick(self, self->current_sender())); + return std::make_tuple(taken_atom::value, true); + }, + [](put_atom) { + cerr << "chopstick received unexpected 'put'" << endl; + } + }; +} + +chopstick::behavior_type taken_chopstick(chopstick::pointer self, + const strong_actor_ptr& user) { + return { + [](take_atom) -> std::tuple { + return std::make_tuple(taken_atom::value, false); + }, + [=](put_atom) { + if (self->current_sender() == user) + self->become(available_chopstick(self)); + } + }; +} + +// Based on: http://www.dalnefre.com/wp/2010/08/dining-philosophers-in-humus/ +// +// +// +-------------+ {busy|taken} +// +-------->| thinking |<------------------+ +// | +-------------+ | +// | | | +// | | {eat} | +// | | | +// | V | +// | +-------------+ {busy} +-------------+ +// | | hungry |----------->| denied | +// | +-------------+ +-------------+ +// | | +// | | {taken} +// | | +// | V +// | +-------------+ +// | | granted | +// | +-------------+ +// | | | +// | {busy} | | {taken} +// +-----------+ | +// | V +// | {think} +-------------+ +// +---------| eating | +// +-------------+ + +class philosopher : public event_based_actor { +public: + philosopher(actor_config& cfg, + std::string n, + chopstick l, + chopstick r) + : event_based_actor(cfg), + name_(std::move(n)), + left_(std::move(l)), + right_(std::move(r)) { + // we only accept one message per state and skip others in the meantime + set_default_handler(skip); + // a philosopher that receives {eat} stops thinking and becomes hungry + thinking_.assign( + [=](eat_atom) { + become(hungry_); + send(left_, take_atom::value); + send(right_, take_atom::value); + } + ); + // wait for the first answer of a chopstick + hungry_.assign( + [=](taken_atom, bool result) { + if (result) + become(granted_); + else + become(denied_); + } + ); + // philosopher was able to obtain the first chopstick + granted_.assign( + [=](taken_atom, bool result) { + if (result) { + aout(this) << name_ + << " has picked up chopsticks with IDs " + << left_->id() << " and " << right_->id() + << " and starts to eat\n"; + // eat some time + delayed_send(this, seconds(5), think_atom::value); + become(eating_); + } else { + send(current_sender() == left_ ? right_ : left_, put_atom::value); + send(this, eat_atom::value); + become(thinking_); + } + } + ); + // philosopher was *not* able to obtain the first chopstick + denied_.assign( + [=](taken_atom, bool result) { + if (result) + send(current_sender() == left_ ? left_ : right_, put_atom::value); + send(this, eat_atom::value); + become(thinking_); + } + ); + // philosopher obtained both chopstick and eats (for five seconds) + eating_.assign( + [=](think_atom) { + send(left_, put_atom::value); + send(right_, put_atom::value); + delayed_send(this, seconds(5), eat_atom::value); + aout(this) << name_ + << " puts down his chopsticks and starts to think\n"; + become(thinking_); + } + ); + } + + const char* name() const override { + return name_.c_str(); + } + +protected: + behavior make_behavior() override { + // start thinking + send(this, think_atom::value); + // philosophers start to think after receiving {think} + return ( + [=](think_atom) { + aout(this) << name_ << " starts to think\n"; + delayed_send(this, seconds(5), eat_atom::value); + become(thinking_); + } + ); + } + +private: + std::string name_; // the name of this philosopher + chopstick left_; // left chopstick + chopstick right_; // right chopstick + behavior thinking_; // initial behavior + behavior hungry_; // tries to take chopsticks + behavior granted_; // has one chopstick and waits for the second one + behavior denied_; // could not get first chopsticks + behavior eating_; // wait for some time, then go thinking again +}; + +} // namespace + +void caf_main(actor_system& system) { + scoped_actor self{system}; + // create five chopsticks + aout(self) << "chopstick ids are:"; + std::vector chopsticks; + for (size_t i = 0; i < 5; ++i) { + chopsticks.push_back(self->spawn(available_chopstick)); + aout(self) << " " << chopsticks.back()->id(); + } + aout(self) << endl; + // spawn five philosophers + std::vector names {"Plato", "Hume", "Kant", + "Nietzsche", "Descartes"}; + for (size_t i = 0; i < 5; ++i) + self->spawn(names[i], chopsticks[i], chopsticks[(i + 1) % 5]); +} + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/dynamic_behavior/skip_messages.cpp actor-framework-0.16.3/examples/dynamic_behavior/skip_messages.cpp --- actor-framework-0.13.2/examples/dynamic_behavior/skip_messages.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/dynamic_behavior/skip_messages.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,60 @@ +#include "caf/all.hpp" +using namespace caf; + +using idle_atom = atom_constant; +using request_atom = atom_constant; +using response_atom = atom_constant; + +behavior server(event_based_actor* self) { + return { + [=](idle_atom, const actor& worker) { + self->become ( + keep_behavior, + [=](request_atom atm) { + self->delegate(worker, atm); + self->unbecome(); + }, + [=](idle_atom) { + return skip(); + } + ); + }, + [=](request_atom) { + return skip(); + } + }; +} + +behavior client(event_based_actor* self, const actor& serv) { + self->link_to(serv); + self->send(serv, idle_atom::value, self); + return { + [=](request_atom) { + self->send(serv, idle_atom::value, self); + return response_atom::value; + } + }; +} + +void caf_main(actor_system& system) { + auto serv = system.spawn(server); + auto worker = system.spawn(client, serv); + scoped_actor self{system}; + self->request(serv, std::chrono::seconds(10), request_atom::value).receive( + [&](response_atom) { + aout(self) << "received response from " + << (self->current_sender() == worker ? "worker\n" + : "server\n"); + }, + [&](error& err) { + aout(self) << "received error " + << system.render(err) + << " from " + << (self->current_sender() == worker ? "worker\n" + : "server\n"); + } + ); + self->send_exit(serv, exit_reason::user_shutdown); +} + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/hello_world.cpp actor-framework-0.16.3/examples/hello_world.cpp --- actor-framework-0.13.2/examples/hello_world.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/hello_world.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -16,8 +16,6 @@ [=](const string& what) -> string { // prints "Hello World!" via aout (thread-safe cout wrapper) aout(self) << what << endl; - // terminates this actor ('become' otherwise loops forever) - self->quit(); // reply "!dlroW olleH" return string(what.rbegin(), what.rend()); } @@ -26,8 +24,8 @@ void hello_world(event_based_actor* self, const actor& buddy) { // send "Hello World!" to our buddy ... - self->sync_send(buddy, "Hello World!").then( - // ... wait for a response ... + self->request(buddy, std::chrono::seconds(10), "Hello World!").then( + // ... wait up to 10s for a response ... [=](const string& what) { // ... and print it aout(self) << what << endl; @@ -36,12 +34,12 @@ } int main() { + // our CAF environment + actor_system_config cfg; + actor_system system{cfg}; // create a new actor that calls 'mirror()' - auto mirror_actor = spawn(mirror); + auto mirror_actor = system.spawn(mirror); // create another actor that calls 'hello_world(mirror_actor)'; - spawn(hello_world, mirror_actor); - // wait until all other actors we have spawned are done - await_all_actors_done(); - // run cleanup code before exiting main - shutdown(); + system.spawn(hello_world, mirror_actor); + // system will wait until both actors are destroyed before leaving main } diff -Nru actor-framework-0.13.2/examples/message_passing/calculator.cpp actor-framework-0.16.3/examples/message_passing/calculator.cpp --- actor-framework-0.13.2/examples/message_passing/calculator.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/message_passing/calculator.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -1,79 +1,153 @@ /******************************************************************************\ * This example is a very basic, non-interactive math service implemented * * for both the blocking and the event-based API. * -\ ******************************************************************************/ +\******************************************************************************/ + +// Manual refs: lines 19-21, 31-72, 74-108, 140-145 (Actor) -#include -#include #include #include "caf/all.hpp" -using std::cout; using std::endl; using namespace caf; -using plus_atom = atom_constant; -using minus_atom = atom_constant; +namespace { + +using add_atom = atom_constant; +using sub_atom = atom_constant; + +using calculator_actor = typed_actor::with, + replies_to::with>; + +// prototypes and forward declarations +behavior calculator_fun(event_based_actor* self); +void blocking_calculator_fun(blocking_actor* self); +calculator_actor::behavior_type typed_calculator_fun(); +class calculator; +class blocking_calculator; +class typed_calculator; + +// function-based, dynamically typed, event-based API +behavior calculator_fun(event_based_actor*) { + return { + [](add_atom, int a, int b) { + return a + b; + }, + [](sub_atom, int a, int b) { + return a - b; + } + }; +} -// implementation using the blocking API -void blocking_calculator(blocking_actor* self) { - self->receive_loop ( - [](plus_atom, int a, int b) { +// function-based, dynamically typed, blocking API +void blocking_calculator_fun(blocking_actor* self) { + bool running = true; + self->receive_while(running) ( + [](add_atom, int a, int b) { return a + b; }, - [](minus_atom, int a, int b) { + [](sub_atom, int a, int b) { return a - b; }, - others >> [=] { - cout << "unexpected: " << to_string(self->current_message()) << endl; + [&](exit_msg& em) { + if (em.reason) { + self->fail_state(std::move(em.reason)); + running = false; + } } ); } -// execute this behavior until actor terminates -behavior calculator(event_based_actor* self) { - return behavior{ - [](plus_atom, int a, int b) { +// function-based, statically typed, event-based API +calculator_actor::behavior_type typed_calculator_fun() { + return { + [](add_atom, int a, int b) { return a + b; }, - [](minus_atom, int a, int b) { + [](sub_atom, int a, int b) { return a - b; - }, - others >> [=] { - cout << "unexpected: " << to_string(self->current_message()) << endl; } }; } -void tester(event_based_actor* self, const actor& testee) { - self->link_to(testee); - // will be invoked if we receive an unexpected response message - self->on_sync_failure([=] { - aout(self) << "AUT (actor under test) failed" << endl; - self->quit(exit_reason::user_shutdown); - }); - // first test: 2 + 1 = 3 - self->sync_send(testee, plus_atom::value, 2, 1).then( - on(3) >> [=] { - // second test: 2 - 1 = 1 - self->sync_send(testee, minus_atom::value, 2, 1).then( - on(1) >> [=] { - // both tests succeeded - aout(self) << "AUT (actor under test) seems to be ok" << endl; - self->quit(exit_reason::user_shutdown); - } +// class-based, dynamically typed, event-based API +class calculator : public event_based_actor { +public: + calculator(actor_config& cfg) : event_based_actor(cfg) { + // nop + } + + behavior make_behavior() override { + return calculator_fun(this); + } +}; + +// class-based, dynamically typed, blocking API +class blocking_calculator : public blocking_actor { +public: + blocking_calculator(actor_config& cfg) : blocking_actor(cfg) { + // nop + } + + void act() override { + blocking_calculator_fun(this); + } +}; + +// class-based, statically typed, event-based API +class typed_calculator : public calculator_actor::base { +public: + typed_calculator(actor_config& cfg) : calculator_actor::base(cfg) { + // nop + } + + behavior_type make_behavior() override { + return typed_calculator_fun(); + } +}; + +void tester(scoped_actor&) { + // end of recursion +} + +// tests a calculator instance +template +void tester(scoped_actor& self, const Handle& hdl, int x, int y, Ts&&... xs) { + auto handle_err = [&](const error& err) { + aout(self) << "AUT (actor under test) failed: " + << self->system().render(err) << endl; + }; + // first test: x + y = z + self->request(hdl, infinite, add_atom::value, x, y).receive( + [&](int res1) { + aout(self) << x << " + " << y << " = " << res1 << endl; + // second test: x - y = z + self->request(hdl, infinite, sub_atom::value, x, y).receive( + [&](int res2) { + aout(self) << x << " - " << y << " = " << res2 << endl; + }, + handle_err ); - } + }, + handle_err ); + tester(self, std::forward(xs)...); } -int main() { - cout << "test blocking actor" << endl; - spawn(tester, spawn(blocking_calculator)); - await_all_actors_done(); - cout << "test event-based actor" << endl; - spawn(tester, spawn(calculator)); - await_all_actors_done(); - shutdown(); +void caf_main(actor_system& system) { + auto a1 = system.spawn(blocking_calculator_fun); + auto a2 = system.spawn(calculator_fun); + auto a3 = system.spawn(typed_calculator_fun); + auto a4 = system.spawn(); + auto a5 = system.spawn(); + auto a6 = system.spawn(); + scoped_actor self{system}; + tester(self, a1, 1, 2, a2, 3, 4, a3, 5, 6, a4, 7, 8, a5, 9, 10, a6, 11, 12); + self->send_exit(a1, exit_reason::user_shutdown); + self->send_exit(a4, exit_reason::user_shutdown); } + +} // namespace + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/message_passing/cell.cpp actor-framework-0.16.3/examples/message_passing/cell.cpp --- actor-framework-0.13.2/examples/message_passing/cell.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/message_passing/cell.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,59 @@ +/******************************************************************************\ + * This example is a very basic, non-interactive math service implemented * + * for both the blocking and the event-based API. * +\******************************************************************************/ + +// This file is partially included in the manual, do not modify +// without updating the references in the *.tex files! +// Manual references: lines 18-44, and 49-50 (Actor.tex) + +#include + +#include "caf/all.hpp" + +using std::cout; +using std::endl; +using namespace caf; + +using cell = typed_actor, + replies_to::with>; + +struct cell_state { + int value = 0; +}; + +cell::behavior_type type_checked_cell(cell::stateful_pointer self) { + return { + [=](put_atom, int val) { + self->state.value = val; + }, + [=](get_atom) { + return self->state.value; + } + }; +} + +behavior unchecked_cell(stateful_actor* self) { + return { + [=](put_atom, int val) { + self->state.value = val; + }, + [=](get_atom) { + return self->state.value; + } + }; +} + +void caf_main(actor_system& system) { + // create one cell for each implementation + auto cell1 = system.spawn(type_checked_cell); + auto cell2 = system.spawn(unchecked_cell); + auto f = make_function_view(cell1); + cout << "cell value: " << f(get_atom::value) << endl; + f(put_atom::value, 20); + cout << "cell value (after setting to 20): " << f(get_atom::value) << endl; + // get an unchecked cell and send it some garbage + anon_send(cell2, "hello there!"); +} + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/message_passing/dancing_kirby.cpp actor-framework-0.16.3/examples/message_passing/dancing_kirby.cpp --- actor-framework-0.13.2/examples/message_passing/dancing_kirby.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/message_passing/dancing_kirby.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -7,6 +7,10 @@ #include #include "caf/all.hpp" +// This file is partially included in the manual, do not modify +// without updating the references in the *.tex files! +// Manual references: lines 56-75 (MessagePassing.tex) + using std::cout; using std::endl; using std::pair; @@ -70,8 +74,8 @@ ); } -int main() { - spawn(dancing_kirby); - await_all_actors_done(); - shutdown(); +void caf_main(actor_system& system) { + system.spawn(dancing_kirby); } + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/message_passing/delegating.cpp actor-framework-0.16.3/examples/message_passing/delegating.cpp --- actor-framework-0.13.2/examples/message_passing/delegating.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/message_passing/delegating.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,43 @@ +#include +#include "caf/all.hpp" + +// This file is partially included in the manual, do not modify +// without updating the references in the *.tex files! +// Manual references: lines 15-42 (MessagePassing.tex) + +using std::endl; +using namespace caf; + +// using add_atom = atom_constant; (defined in atom.hpp) + +using calc = typed_actor::with>; + +void actor_a(event_based_actor* self, const calc& worker) { + self->request(worker, std::chrono::seconds(10), add_atom::value, 1, 2).then( + [=](int result) { + aout(self) << "1 + 2 = " << result << endl; + } + ); +} + +calc::behavior_type actor_b(calc::pointer self, const calc& worker) { + return { + [=](add_atom add, int x, int y) { + return self->delegate(worker, add, x, y); + } + }; +} + +calc::behavior_type actor_c() { + return { + [](add_atom, int x, int y) { + return x + y; + } + }; +} + +void caf_main(actor_system& system) { + system.spawn(actor_a, system.spawn(actor_b, system.spawn(actor_c))); +} + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/message_passing/dining_philosophers.cpp actor-framework-0.16.3/examples/message_passing/dining_philosophers.cpp --- actor-framework-0.13.2/examples/message_passing/dining_philosophers.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/message_passing/dining_philosophers.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,211 +0,0 @@ -/******************************************************************************\ - * This example is an implementation of the classical Dining Philosophers * - * exercise using only libcaf's event-based actor implementation. * -\ ******************************************************************************/ - -#include -#include -#include -#include -#include - -#include "caf/all.hpp" - -using std::cout; -using std::cerr; -using std::endl; -using std::chrono::seconds; - -using namespace caf; - -namespace { - -// atoms for chopstick interface -using put_atom = atom_constant; -using take_atom = atom_constant; -using busy_atom = atom_constant; -using taken_atom = atom_constant; - -// atoms for philosopher interface -using eat_atom = atom_constant; -using think_atom = atom_constant; - -// a chopstick -using chopstick = typed_actor - ::with_either - ::or_else, - reacts_to>; - -chopstick::behavior_type taken_chopstick(chopstick::pointer self, actor_addr); - -// either taken by a philosopher or available -chopstick::behavior_type available_chopstick(chopstick::pointer self) { - return { - [=](take_atom) { - self->become(taken_chopstick(self, self->current_sender())); - return taken_atom::value; - }, - [](put_atom) { - cerr << "chopstick received unexpected 'put'" << endl; - } - }; -} - -chopstick::behavior_type taken_chopstick(chopstick::pointer self, - actor_addr user) { - return { - [](take_atom) { - return busy_atom::value; - }, - [=](put_atom) { - if (self->current_sender() == user) { - self->become(available_chopstick(self)); - } - } - }; -} - -/* Based on: http://www.dalnefre.com/wp/2010/08/dining-philosophers-in-humus/ - * - * - * +-------------+ {busy|taken} - * /-------->| thinking |<------------------\ - * | +-------------+ | - * | | | - * | | {eat} | - * | | | - * | V | - * | +-------------+ {busy} +-------------+ - * | | hungry |----------->| denied | - * | +-------------+ +-------------+ - * | | - * | | {taken} - * | | - * | V - * | +-------------+ - * | | granted | - * | +-------------+ - * | | | - * | {busy} | | {taken} - * \-----------/ | - * | V - * | {think} +-------------+ - * \---------| eating | - * +-------------+ - */ - -class philosopher : public event_based_actor { - public: - philosopher(const std::string& n, const chopstick& l, const chopstick& r) - : name(n), - left(l), - right(r) { - // a philosopher that receives {eat} stops thinking and becomes hungry - thinking.assign( - [=](eat_atom) { - become(hungry); - send(left, take_atom::value); - send(right, take_atom::value); - } - ); - // wait for the first answer of a chopstick - hungry.assign( - [=](taken_atom) { - become(granted); - }, - [=](busy_atom) { - become(denied); - } - ); - // philosopher was able to obtain the first chopstick - granted.assign( - [=](taken_atom) { - aout(this) << name - << " has picked up chopsticks with IDs " - << left->id() << " and " << right->id() - << " and starts to eat\n"; - // eat some time - delayed_send(this, seconds(5), think_atom::value); - become(eating); - }, - [=](busy_atom) { - send(current_sender() == left ? right : left, put_atom::value); - send(this, eat_atom::value); - become(thinking); - } - ); - // philosopher was *not* able to obtain the first chopstick - denied.assign( - [=](taken_atom) { - send(current_sender() == left ? left : right, put_atom::value); - send(this, eat_atom::value); - become(thinking); - }, - [=](busy_atom) { - send(this, eat_atom::value); - become(thinking); - } - ); - // philosopher obtained both chopstick and eats (for five seconds) - eating.assign( - [=](think_atom) { - send(left, put_atom::value); - send(right, put_atom::value); - delayed_send(this, seconds(5), eat_atom::value); - aout(this) << name << " puts down his chopsticks and starts to think\n"; - become(thinking); - } - ); - } - - protected: - behavior make_behavior() override { - // start thinking - send(this, think_atom::value); - // philosophers start to think after receiving {think} - return ( - [=](think_atom) { - aout(this) << name << " starts to think\n"; - delayed_send(this, seconds(5), eat_atom::value); - become(thinking); - } - ); - } - - private: - std::string name; // the name of this philosopher - chopstick left; // left chopstick - chopstick right; // right chopstick - behavior thinking; // initial behavior - behavior hungry; // tries to take chopsticks - behavior granted; // has one chopstick and waits for the second one - behavior denied; // could not get first chopsticks - behavior eating; // waits for some time, then go thinking again -}; - -void dining_philosophers() { - scoped_actor self; - // create five chopsticks - aout(self) << "chopstick ids are:"; - std::vector chopsticks; - for (size_t i = 0; i < 5; ++i) { - chopsticks.push_back(spawn_typed(available_chopstick)); - aout(self) << " " << chopsticks.back()->id(); - } - aout(self) << endl; - // spawn five philosophers - std::vector names {"Plato", "Hume", "Kant", - "Nietzsche", "Descartes"}; - for (size_t i = 0; i < 5; ++i) { - spawn(names[i], chopsticks[i], chopsticks[(i + 1) % 5]); - } -} - -} // namespace - -int main(int, char**) { - dining_philosophers(); - // real philosophers are never done - await_all_actors_done(); - shutdown(); -} diff -Nru actor-framework-0.13.2/examples/message_passing/divider.cpp actor-framework-0.16.3/examples/message_passing/divider.cpp --- actor-framework-0.13.2/examples/message_passing/divider.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/message_passing/divider.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,82 @@ +/******************************************************************************\ + * A very basic, interactive divider. * +\******************************************************************************/ + +// Manual refs: 19-25, 35-48, 68-77 (MessagePassing); +// 19-34, 50-58 (Error) + +#include + +#include "caf/all.hpp" + +using std::cout; +using std::endl; +using std::flush; +using namespace caf; + +namespace { + +enum class math_error : uint8_t { + division_by_zero = 1 +}; + +error make_error(math_error x) { + return {static_cast(x), atom("math")}; +} + +std::string to_string(math_error x) { + switch (x) { + case math_error::division_by_zero: + return "division_by_zero"; + default: + return "-unknown-error-"; + } +} + +using div_atom = atom_constant; + +using divider = typed_actor::with>; + +divider::behavior_type divider_impl() { + return { + [](div_atom, double x, double y) -> result { + if (y == 0.0) + return math_error::division_by_zero; + return x / y; + } + }; +} + +class config : public actor_system_config { +public: + config() { + auto renderer = [](uint8_t x, atom_value, const message&) { + return "math_error" + deep_to_string_as_tuple(static_cast(x)); + }; + add_error_category(atom("math"), renderer); + } +}; + +void caf_main(actor_system& system, const config&) { + double x; + double y; + cout << "x: " << flush; + std::cin >> x; + cout << "y: " << flush; + std::cin >> y; + auto div = system.spawn(divider_impl); + scoped_actor self{system}; + self->request(div, std::chrono::seconds(10), div_atom::value, x, y).receive( + [&](double z) { + aout(self) << x << " / " << y << " = " << z << endl; + }, + [&](const error& err) { + aout(self) << "*** cannot compute " << x << " / " << y << " => " + << system.render(err) << endl; + } + ); +} + +} // namespace + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/message_passing/fixed_stack.cpp actor-framework-0.16.3/examples/message_passing/fixed_stack.cpp --- actor-framework-0.13.2/examples/message_passing/fixed_stack.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/message_passing/fixed_stack.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,99 @@ +#include +#include +#include +#include "caf/all.hpp" + +using std::endl; +using namespace caf; + +namespace { + +using pop_atom = atom_constant; +using push_atom = atom_constant; + +enum class fixed_stack_errc : uint8_t { push_to_full = 1, pop_from_empty }; + +error make_error(fixed_stack_errc x) { + return error{static_cast(x), atom("FixedStack")}; +} + +class fixed_stack : public event_based_actor { +public: + fixed_stack(actor_config& cfg, size_t stack_size) + : event_based_actor(cfg), + size_(stack_size) { + full_.assign( + [=](push_atom, int) -> error { + return fixed_stack_errc::push_to_full; + }, + [=](pop_atom) -> int { + auto result = data_.back(); + data_.pop_back(); + become(filled_); + return result; + } + ); + filled_.assign( + [=](push_atom, int what) { + data_.push_back(what); + if (data_.size() == size_) + become(full_); + }, + [=](pop_atom) -> int { + auto result = data_.back(); + data_.pop_back(); + if (data_.empty()) + become(empty_); + return result; + } + ); + empty_.assign( + [=](push_atom, int what) { + data_.push_back(what); + become(filled_); + }, + [=](pop_atom) -> error { + return fixed_stack_errc::pop_from_empty; + } + ); + } + + behavior make_behavior() override { + assert(size_ < 2); + return empty_; + } + +private: + size_t size_; + std::vector data_; + behavior full_; + behavior filled_; + behavior empty_; +}; + +void caf_main(actor_system& system) { + scoped_actor self{system}; + auto st = self->spawn(5u); + // fill stack + for (int i = 0; i < 10; ++i) + self->send(st, push_atom::value, i); + // drain stack + aout(self) << "stack: { "; + bool stack_empty = false; + while (!stack_empty) { + self->request(st, std::chrono::seconds(10), pop_atom::value).receive( + [&](int x) { + aout(self) << x << " "; + }, + [&](const error&) { + stack_empty = true; + } + ); + } + aout(self) << "}" << endl; + self->send_exit(st, exit_reason::user_shutdown); +} + +} // namespace + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/message_passing/promises.cpp actor-framework-0.16.3/examples/message_passing/promises.cpp --- actor-framework-0.13.2/examples/message_passing/promises.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/message_passing/promises.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,50 @@ +/******************************************************************************\ + * Illustrates response promises. * +\******************************************************************************/ + +// This file is partially included in the manual, do not modify +// without updating the references in the *.tex files! +// Manual references: lines 18-43 (MessagePassing.tex) + +#include + +#include "caf/all.hpp" + +using std::cout; +using std::endl; + +using namespace caf; + +// using add_atom = atom_constant; (defined in atom.hpp) + +using adder = typed_actor::with>; + +// function-based, statically typed, event-based API +adder::behavior_type worker() { + return { + [](add_atom, int a, int b) { + return a + b; + } + }; +} + +// function-based, statically typed, event-based API +adder::behavior_type calculator_master(adder::pointer self) { + auto w = self->spawn(worker); + return { + [=](add_atom x, int y, int z) -> result { + auto rp = self->make_response_promise(); + self->request(w, infinite, x, y, z).then([=](int result) mutable { + rp.deliver(result); + }); + return rp; + } + }; +} + +void caf_main(actor_system& system) { + auto f = make_function_view(system.spawn(calculator_master)); + cout << "12 + 13 = " << f(add_atom::value, 12, 13) << endl; +} + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/message_passing/request.cpp actor-framework-0.16.3/examples/message_passing/request.cpp --- actor-framework-0.13.2/examples/message_passing/request.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/message_passing/request.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,81 @@ +/******************************************************************************\ + * Illustrates semantics of request().{then|await|receive}. * +\******************************************************************************/ + +// This file is partially included in the manual, do not modify +// without updating the references in the *.tex files! +// Manual references: lines 20-37, 39-51, 53-64, 67-69 (MessagePassing.tex) + +#include +#include +#include + +#include "caf/all.hpp" + +using std::endl; +using std::vector; +using std::chrono::seconds; +using namespace caf; + +using cell = typed_actor, + replies_to::with>; + +struct cell_state { + int value = 0; +}; + +cell::behavior_type cell_impl(cell::stateful_pointer self, int x0) { + self->state.value = x0; + return { + [=](put_atom, int val) { + self->state.value = val; + }, + [=](get_atom) { + return self->state.value; + } + }; +} + +void waiting_testee(event_based_actor* self, vector cells) { + for (auto& x : cells) + self->request(x, seconds(1), get_atom::value).await([=](int y) { + aout(self) << "cell #" << x.id() << " -> " << y << endl; + }); +} + +void multiplexed_testee(event_based_actor* self, vector cells) { + for (auto& x : cells) + self->request(x, seconds(1), get_atom::value).then([=](int y) { + aout(self) << "cell #" << x.id() << " -> " << y << endl; + }); +} + +void blocking_testee(blocking_actor* self, vector cells) { + for (auto& x : cells) + self->request(x, seconds(1), get_atom::value).receive( + [&](int y) { + aout(self) << "cell #" << x.id() << " -> " << y << endl; + }, + [&](error& err) { + aout(self) << "cell #" << x.id() + << " -> " << self->system().render(err) << endl; + } + ); +} + +void caf_main(actor_system& system) { + vector cells; + for (auto i = 0; i < 5; ++i) + cells.emplace_back(system.spawn(cell_impl, i * i)); + scoped_actor self{system}; + aout(self) << "waiting_testee" << endl; + auto x1 = self->spawn(waiting_testee, cells); + self->wait_for(x1); + aout(self) << "multiplexed_testee" << endl; + auto x2 = self->spawn(multiplexed_testee, cells); + self->wait_for(x2); + aout(self) << "blocking_testee" << endl; + system.spawn(blocking_testee, cells); +} + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/message_passing/typed_calculator.cpp actor-framework-0.16.3/examples/message_passing/typed_calculator.cpp --- actor-framework-0.13.2/examples/message_passing/typed_calculator.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/message_passing/typed_calculator.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -12,40 +12,39 @@ namespace { -struct shutdown_request { }; -struct plus_request { int a; int b; }; -struct minus_request { int a; int b; }; - -using calculator_type = typed_actor::with, - replies_to::with, - replies_to::with>; +using plus_atom = atom_constant; +using minus_atom = atom_constant; +using result_atom = atom_constant; + +using calculator_type = + typed_actor::with, + replies_to::with>; -calculator_type::behavior_type typed_calculator(calculator_type::pointer self) { +calculator_type::behavior_type typed_calculator_fun(calculator_type::pointer) { return { - [](const plus_request& pr) { - return pr.a + pr.b; + [](plus_atom, int x, int y) { + return std::make_tuple(result_atom::value, x + y); }, - [](const minus_request& pr) { - return pr.a - pr.b; - }, - [=](const shutdown_request&) { - self->quit(); + [](minus_atom, int x, int y) { + return std::make_tuple(result_atom::value, x - y); } }; } class typed_calculator_class : public calculator_type::base { - protected: +public: + typed_calculator_class(actor_config& cfg) : calculator_type::base(cfg) { + // nop + } + +protected: behavior_type make_behavior() override { return { - [](const plus_request& pr) { - return pr.a + pr.b; + [](plus_atom, int x, int y) { + return std::make_tuple(result_atom::value, x + y); }, - [](const minus_request& pr) { - return pr.a - pr.b; - }, - [=](const shutdown_request&) { - quit(); + [](minus_atom, int x, int y) { + return std::make_tuple(result_atom::value, x - y); } }; } @@ -53,44 +52,37 @@ void tester(event_based_actor* self, const calculator_type& testee) { self->link_to(testee); - // will be invoked if we receive an unexpected response message - self->on_sync_failure([=] { - aout(self) << "AUT (actor under test) failed" << endl; - self->quit(exit_reason::user_shutdown); - }); // first test: 2 + 1 = 3 - self->sync_send(testee, plus_request{2, 1}).then( - [=](int r1) { + self->request(testee, infinite, plus_atom::value, 2, 1).then( + [=](result_atom, int r1) { // second test: 2 - 1 = 1 - self->sync_send(testee, minus_request{2, 1}).then( - [=](int r2) { + self->request(testee, infinite, minus_atom::value, 2, 1).then( + [=](result_atom, int r2) { // both tests succeeded if (r1 == 3 && r2 == 1) { aout(self) << "AUT (actor under test) seems to be ok" << endl; } - self->send(testee, shutdown_request{}); + self->send_exit(testee, exit_reason::user_shutdown); } ); + }, + [=](const error& err) { + aout(self) << "AUT (actor under test) failed: " + << self->system().render(err) << endl; + self->quit(exit_reason::user_shutdown); } ); } -} // namespace - -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); +void caf_main(actor_system& system) { // test function-based impl - spawn(tester, spawn_typed(typed_calculator)); - await_all_actors_done(); + system.spawn(tester, system.spawn(typed_calculator_fun)); + system.await_all_actors_done(); // test class-based impl - spawn(tester, spawn_typed()); - await_all_actors_done(); - // done - shutdown(); - return 0; + system.spawn(tester, system.spawn()); } + +} // namespace + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/qtsupport/chatwidget.cpp actor-framework-0.16.3/examples/qtsupport/chatwidget.cpp --- actor-framework-0.13.2/examples/qtsupport/chatwidget.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/qtsupport/chatwidget.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -15,118 +15,127 @@ using namespace caf; ChatWidget::ChatWidget(QWidget* parent, Qt::WindowFlags f) -: super(parent, f), m_input(nullptr), m_output(nullptr) { - set_message_handler ([=](local_actor* self) -> message_handler { - return { - on(atom("join"), arg_match) >> [=](const group& what) { - if (m_chatroom) { - self->send(m_chatroom, m_name + " has left the chatroom"); - self->leave(m_chatroom); - } - self->join(what); - print(("*** joined " + to_string(what)).c_str()); - m_chatroom = what; - self->send(what, m_name + " has entered the chatroom"); - }, - on(atom("setName"), arg_match) >> [=](string& name) { - self->send(m_chatroom, m_name + " is now known as " + name); - m_name = std::move(name); - print("*** changed name to " - + QString::fromUtf8(m_name.c_str())); - }, - on(atom("quit")) >> [=] { - close(); // close widget - }, - [=](const string& txt) { - // don't print own messages - if (self != self->current_sender()) { - print(QString::fromUtf8(txt.c_str())); - } - }, - [=](const group_down_msg& gdm) { - print("*** chatroom offline: " - + QString::fromUtf8(to_string(gdm.source).c_str())); - } - }; - }); + : super(parent, f), + input_(nullptr), + output_(nullptr) { + // nop +} + +ChatWidget::~ChatWidget() { + // nop +} + +void ChatWidget::init(actor_system& system) { + super::init(system); + set_message_handler ([=](actor_companion* self) -> message_handler { + return { + [=](join_atom, const group& what) { + if (chatroom_) { + self->send(chatroom_, name_ + " has left the chatroom"); + self->leave(chatroom_); + } + self->join(what); + print(("*** joined " + to_string(what)).c_str()); + chatroom_ = what; + self->send(what, name_ + " has entered the chatroom"); + }, + [=](set_name_atom, string& name) { + self->send(chatroom_, name_ + " is now known as " + name); + name_ = std::move(name); + print("*** changed name to " + QString::fromUtf8(name_.c_str())); + }, + [=](quit_atom) { + quit_and_close(); + }, + [=](const string& txt) { + // don't print own messages + if (self != self->current_sender()) + print(QString::fromUtf8(txt.c_str())); + }, + [=](const group_down_msg& gdm) { + print("*** chatroom offline: " + + QString::fromUtf8(to_string(gdm.source).c_str())); + } + }; + }); } void ChatWidget::sendChatMessage() { - auto cleanup = detail::make_scope_guard([=] { - input()->setText(QString()); + auto cleanup = detail::make_scope_guard([=] { + input()->setText(QString()); + }); + QString line = input()->text(); + if (line.startsWith('/')) { + vector words; + split(words, line.midRef(1).toUtf8().constData(), is_any_of(" ")); + message_builder mb; + if (words.size() > 1) { + // convert first word to an atom + mb.append(atom_from_string(words.front())) + .append(words.begin() + 1, words.end()); + }; + auto res = mb.apply({ + [=](join_atom, const string& mod, const string& g) { + auto x = system().groups().get(mod, g); + if (! x) + print("*** error: " + + QString::fromUtf8(system().render(x.error()).c_str())); + else + self()->send(self(), atom("join"), std::move(*x)); + }, + [=](set_name_atom atm, string& name) { + send_as(as_actor(), as_actor(), atm, std::move(name)); + } }); - QString line = input()->text(); - if (line.startsWith('/')) { - vector words; - split(words, line.midRef(1).toUtf8().constData(), is_any_of(" ")); - message_builder(words.begin(), words.end()).apply({ - on("join", arg_match) >> [=](const string& mod, const string& g) { - group gptr; - try { gptr = group::get(mod, g); } - catch (exception& e) { - print("*** exception: " + QString::fromUtf8((e.what()))); - } - if (gptr) { - send_as(as_actor(), as_actor(), atom("join"), gptr); - } - }, - on("setName", arg_match) >> [=](const string& str) { - send_as(as_actor(), as_actor(), atom("setName"), str); - }, - others() >> [=] { - print("*** list of commands:\n" - "/join \n" - "/setName \n"); - } - }); - return; - } - if (m_name.empty()) { - print("*** please set a name before sending messages"); - return; - } - if (!m_chatroom) { - print("*** no one is listening... please join a group"); - return; - } - string msg = m_name; - msg += ": "; - msg += line.toUtf8().constData(); - print(": " + input()->text()); - send_as(as_actor(), m_chatroom, std::move(msg)); + if (! res) + print("*** list of commands:\n" + "/join \n" + "/setName \n"); + return; + } + if (name_.empty()) { + print("*** please set a name before sending messages"); + return; + } + if (! chatroom_) { + print("*** no one is listening... please join a group"); + return; + } + string msg = name_; + msg += ": "; + msg += line.toUtf8().constData(); + print(": " + input()->text()); + send_as(as_actor(), chatroom_, std::move(msg)); } void ChatWidget::joinGroup() { - if (m_name.empty()) { - QMessageBox::information(this, - "No Name, No Chat", - "Please set a name first."); - return; - } - auto gname = QInputDialog::getText(this, - "Join Group", - "Please enter a group as :", - QLineEdit::Normal, - "remote:chatroom@localhost:4242"); - int pos = gname.indexOf(':'); - if (pos < 0) { - QMessageBox::warning(this, "Not a Group", "Invalid format"); - return; - } - string mod = gname.left(pos).toUtf8().constData(); - string gid = gname.midRef(pos+1).toUtf8().constData(); - try { - auto gptr = group::get(mod, gid); - send_as(as_actor(), as_actor(), atom("join"), gptr); - } - catch (exception& e) { - QMessageBox::critical(this, "Exception", e.what()); - } + if (name_.empty()) { + QMessageBox::information(this, "No Name, No Chat", + "Please set a name first."); + return; + } + auto gname = QInputDialog::getText(this, + "Join Group", + "Please enter a group as :", + QLineEdit::Normal, + "remote:chatroom@localhost:4242"); + int pos = gname.indexOf(':'); + if (pos < 0) { + QMessageBox::warning(this, "Not a Group", "Invalid format"); + return; + } + string mod = gname.left(pos).toUtf8().constData(); + string gid = gname.midRef(pos+1).toUtf8().constData(); + auto x = system().groups().get(mod, gid); + if (! x) + QMessageBox::critical(this, "Error", system().render(x.error()).c_str()); + else + self()->send(self(), join_atom::value, std::move(*x)); } void ChatWidget::changeName() { - auto name = QInputDialog::getText(this, "Change Name", "Please enter a new name"); - if (!name.isEmpty()) { - send_as(as_actor(), as_actor(), atom("setName"), name.toUtf8().constData()); - } + auto name = QInputDialog::getText(this, "Change Name", + "Please enter a new name"); + if (! name.isEmpty()) + send_as(as_actor(), as_actor(), atom("setName"), name.toUtf8().constData()); } diff -Nru actor-framework-0.13.2/examples/qtsupport/chatwidget.hpp actor-framework-0.16.3/examples/qtsupport/chatwidget.hpp --- actor-framework-0.13.2/examples/qtsupport/chatwidget.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/qtsupport/chatwidget.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -1,3 +1,5 @@ +#pragma once + #include #include "caf/all.hpp" @@ -10,49 +12,62 @@ CAF_POP_WARNINGS class ChatWidget : public caf::mixin::actor_widget { +private: + // -- Qt boilerplate code ---------------------------------------------------- - Q_OBJECT + Q_OBJECT - typedef caf::mixin::actor_widget super; +public: + // -- member types ----------------------------------------------------------- - public: + using super = caf::mixin::actor_widget; - ChatWidget(QWidget* parent = nullptr, Qt::WindowFlags f = 0); + using set_name_atom = caf::atom_constant; - public slots: + using quit_atom = caf::atom_constant; - void sendChatMessage(); - void joinGroup(); - void changeName(); + ChatWidget(QWidget* parent = nullptr, Qt::WindowFlags f = 0); - private: + ~ChatWidget(); - template - T* get(T*& member, const char* name) { - if (member == nullptr) { - member = findChild(name); - if (member == nullptr) - throw std::runtime_error("unable to find child: " - + std::string(name)); - } - return member; - } + void init(caf::actor_system& system); - inline QLineEdit* input() { - return get(m_input, "input"); - } +public slots: - inline QTextEdit* output() { - return get(m_output, "output"); - } + void sendChatMessage(); + void joinGroup(); + void changeName(); - inline void print(const QString& what) { - output()->append(what); - } +private: - QLineEdit* m_input; - QTextEdit* m_output; - std::string m_name; - caf::group m_chatroom; + template + T* get(T*& member, const char* name) { + if (member == nullptr) { + member = findChild(name); + if (member == nullptr) + throw std::runtime_error("unable to find child: " + std::string(name)); + } + return member; + } + inline QLineEdit* input() { + return get(input_, "input"); + } + + inline QTextEdit* output() { + return get(output_, "output"); + } + + inline void print(const QString& what) { + output()->append(what); + } + + caf::actor_system& system() { + return self()->home_system(); + } + + QLineEdit* input_; + QTextEdit* output_; + std::string name_; + caf::group chatroom_; }; diff -Nru actor-framework-0.13.2/examples/qtsupport/chatwindow.ui actor-framework-0.16.3/examples/qtsupport/chatwindow.ui --- actor-framework-0.13.2/examples/qtsupport/chatwindow.ui 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/qtsupport/chatwindow.ui 2018-12-27 20:33:32.000000000 +0000 @@ -18,7 +18,16 @@ 0 - + + 0 + + + 0 + + + 0 + + 0 @@ -62,7 +71,16 @@ 0 - + + 0 + + + 0 + + + 0 + + 0 @@ -116,7 +134,7 @@ actionJoin_Group - activated() + triggered() chatwidget joinGroup() @@ -132,7 +150,7 @@ actionSet_Name - activated() + triggered() chatwidget changeName() diff -Nru actor-framework-0.13.2/examples/qtsupport/qt_group_chat.cpp actor-framework-0.16.3/examples/qtsupport/qt_group_chat.cpp --- actor-framework-0.13.2/examples/qtsupport/qt_group_chat.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/qtsupport/qt_group_chat.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -18,6 +18,7 @@ #include #include "caf/all.hpp" +#include "caf/io/all.hpp" CAF_PUSH_WARNINGS #include @@ -28,52 +29,55 @@ using namespace std; using namespace caf; -int main(int argc, char** argv) { - string name; - string group_id; - auto res = message_builder(argv + 1, argv + argc).extract_opts({ - {"name,n", "set chat name", name}, - {"group,g", "join chat group", group_id} - }); - if (!res.remainder.empty()) { - std::cerr << res.helptext << std::endl; - return 1; - } - if (res.opts.count("help") > 0) { - return 0; +class config : public actor_system_config { +public: + std::string name; + std::string group_id; + + config(int argc, char** argv) { + opt_group{custom_options_, "global"} + .add(name, "name,n", "set name") + .add(group_id, "group,g", "join group (format: :"); + parse(argc, argv); + load(); } - group gptr; - // evaluate group parameter - if (!group_id.empty()) { - auto p = group_id.find(':'); +}; + +int main(int argc, char** argv) { + config cfg{argc, argv}; + actor_system system{cfg}; + auto name = cfg.name; + group grp; + // evaluate group parameters + if (! cfg.group_id.empty()) { + auto p = cfg.group_id.find(':'); if (p == std::string::npos) { - cerr << "*** error parsing argument " << group_id - << ", expected format: :"; + cerr << "*** error parsing argument " << cfg.group_id + << ", expected format: :"; } else { - try { - gptr = group::get(group_id.substr(0, p), group_id.substr(p + 1)); - } catch (exception& e) { - cerr << "*** exception: group::get(\"" << group_id.substr(0, p) - << "\", \"" << group_id.substr(p + 1) << "\") failed; " - << to_verbose_string(e) << endl; + auto module = cfg.group_id.substr(0, p); + auto group_uri = cfg.group_id.substr(p + 1); + auto g = system.groups().get(module, group_uri); + if (! g) { + cerr << "*** unable to get group " << group_uri + << " from module " << module << ": " + << system.render(g.error()) << endl; + return -1; } + grp = std::move(*g); } } - QApplication app(argc, argv); + QApplication app{argc, argv}; app.setQuitOnLastWindowClosed(true); QMainWindow mw; Ui::ChatWindow helper; helper.setupUi(&mw); + helper.chatwidget->init(system); auto client = helper.chatwidget->as_actor(); - if (!name.empty()) { + if (! name.empty()) send_as(client, client, atom("setName"), move(name)); - } - if (gptr) { - send_as(client, client, atom("join"), gptr); - } + if (grp) + send_as(client, client, atom("join"), std::move(grp)); mw.show(); - auto app_res = app.exec(); - await_all_actors_done(); - shutdown(); - return app_res; + return app.exec(); } diff -Nru actor-framework-0.13.2/examples/remote_actors/distributed_calculator.cpp actor-framework-0.16.3/examples/remote_actors/distributed_calculator.cpp --- actor-framework-0.13.2/examples/remote_actors/distributed_calculator.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/remote_actors/distributed_calculator.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,290 +0,0 @@ -/******************************************************************************\ - * This program is a distributed version of the math_actor example. * - * Client and server use a stateless request/response protocol and the client * - * is failure resilient by using a FIFO request queue. * - * The client auto-reconnects and also allows for server reconfiguration. * - * * - * Run server at port 4242: * - * - ./build/bin/distributed_math_actor -s -p 4242 * - * * - * Run client at the same host: * - * - ./build/bin/distributed_math_actor -c -p 4242 * -\ ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#include "caf/all.hpp" -#include "caf/io/all.hpp" - -using std::cout; -using std::cerr; -using std::endl; -using std::string; - -using namespace caf; - -namespace { - -using plus_atom = atom_constant; -using minus_atom = atom_constant; -using result_atom = atom_constant; -using rebind_atom = atom_constant; -using connect_atom = atom_constant; -using reconnect_atom = atom_constant; - -// our "service" -behavior calculator() { - return { - [](plus_atom, int a, int b) -> message { - return make_message(result_atom::value, a + b); - }, - [](minus_atom, int a, int b) -> message { - return make_message(result_atom::value, a - b); - } - }; -} - -class client_impl : public event_based_actor { - public: - client_impl(string hostaddr, uint16_t port) - : m_host(std::move(hostaddr)), - m_port(port) { - // nop - } - - behavior make_behavior() override { - become(awaiting_task()); - become(keep_behavior, reconnecting()); - return {}; - } - - private: - void sync_send_task(atom_value op, int lhs, int rhs) { - on_sync_failure([=] { - aout(this) << "*** sync_failure!" << endl; - }); - sync_send(m_server, op, lhs, rhs).then( - [=](result_atom, int result) { - aout(this) << lhs << (op == plus_atom::value ? " + " : " - ") - << rhs << " = " << result << endl; - }, - [=](const sync_exited_msg& msg) { - aout(this) << "*** server down [" << msg.reason << "], " - << "try to reconnect ..." << endl; - // try sync_sending this again after successful reconnect - become(keep_behavior, - reconnecting([=] { sync_send_task(op, lhs, rhs); })); - } - ); - } - - behavior awaiting_task() { - return { - [=](atom_value op, int lhs, int rhs) { - if (op != plus_atom::value && op != minus_atom::value) { - return; - } - sync_send_task(op, lhs, rhs); - }, - [=](rebind_atom, string& nhost, uint16_t nport) { - aout(this) << "*** rebind to " << nhost << ":" << nport << endl; - using std::swap; - swap(m_host, nhost); - swap(m_port, nport); - become(keep_behavior, reconnecting()); - } - }; - } - - behavior reconnecting(std::function continuation = nullptr) { - using std::chrono::seconds; - auto mm = io::get_middleman_actor(); - send(mm, get_atom::value, m_host, m_port); - return { - [=](ok_atom, const actor_addr& new_server) { - aout(this) << "*** connection succeeded, awaiting tasks" << endl; - m_server = actor_cast(new_server); - // return to previous behavior - if (continuation) { - continuation(); - } - unbecome(); - }, - [=](error_atom, const string& errstr) { - aout(this) << "*** could not connect to " << m_host - << " at port " << m_port - << ": " << errstr - << " [try again in 3s]" - << endl; - delayed_send(mm, seconds(3), get_atom::value, m_host, m_port); - }, - [=](rebind_atom, string& nhost, uint16_t nport) { - aout(this) << "*** rebind to " << nhost << ":" << nport << endl; - using std::swap; - swap(m_host, nhost); - swap(m_port, nport); - // await pending ok/error message first, then send new request to MM - become( - keep_behavior, - (on() || on()) >> [=] { - unbecome(); - send(mm, get_atom::value, m_host, m_port); - } - ); - }, - // simply ignore all requests until we have a connection - others >> skip_message - }; - } - - actor m_server; - string m_host; - uint16_t m_port; -}; - -// removes leading and trailing whitespaces -string trim(std::string s) { - auto not_space = [](char c) { return !isspace(c); }; - // trim left - s.erase(s.begin(), find_if(s.begin(), s.end(), not_space)); - // trim right - s.erase(find_if(s.rbegin(), s.rend(), not_space).base(), s.end()); - return s; -} - -// tries to convert `str` to an int -optional toint(const string& str) { - char* end; - auto result = static_cast(strtol(str.c_str(), &end, 10)); - if (end == str.c_str() + str.size()) { - return result; - } - return none; -} - -// converts "+" to the atom '+' and "-" to the atom '-' -optional plus_or_minus(const string& str) { - if (str == "+") { - return {plus_atom::value}; - } - if (str == "-") { - return {minus_atom::value}; - } - return none; -} - -void client_repl(string host, uint16_t port) { - // keeps track of requests and tries to reconnect on server failures - auto usage = [] { - cout << "Usage:" << endl - << " quit : terminates the program" << endl - << " connect : connects to a remote actor" << endl - << " + : adds two integers" << endl - << " - : subtracts two integers" << endl - << endl; - }; - usage(); - bool done = false; - auto client = spawn(std::move(host), port); - // defining the handler outside the loop is more efficient as it avoids - // re-creating the same object over and over again - message_handler eval{ - on("quit") >> [&] { - anon_send_exit(client, exit_reason::user_shutdown); - done = true; - }, - on("connect", arg_match) >> [&](string& nhost, string& sport) { - try { - auto lport = std::stoul(sport); - if (lport < std::numeric_limits::max()) { - anon_send(client, rebind_atom::value, move(nhost), - static_cast(lport)); - } - else { - cout << lport << " is not a valid port" << endl; - } - } - catch (std::exception&) { - cout << "\"" << sport << "\" is not an unsigned integer" - << endl; - } - }, - on(toint, plus_or_minus, toint) >> [&](int x, atom_value op, int y) { - anon_send(client, op, x, y); - }, - others >> usage - }; - // read next line, split it, and feed to the eval handler - string line; - while (!done && std::getline(std::cin, line)) { - line = trim(std::move(line)); // ignore leading and trailing whitespaces - std::vector words; - split(words, line, is_any_of(" "), token_compress_on); - message_builder(words.begin(), words.end()).apply(eval); - } -} - -} // namespace - -int main(int argc, char** argv) { - uint16_t port = 0; - string host = "localhost"; - auto res = message_builder(argv + 1, argv + argc).extract_opts({ - {"port,p", "set port (either to publish at or to connect to)", port}, - {"host,H", "set host (client mode only, default: localhost)", host}, - {"server,s", "run in server mode"}, - {"client,c", "run in client mode"} - }); - if (res.opts.count("help") > 0) { - // help text has already been printed - return 0; - } - if (!res.remainder.empty()) { - // not all CLI arguments could be consumed - cerr << "*** invalid command line options" << endl << res.helptext << endl; - return 1; - } - bool is_server = res.opts.count("server") > 0; - if (is_server == (res.opts.count("client") > 0)) { - if (is_server) { - cerr << "*** cannot be server and client at the same time" << endl; - } else { - cerr << "*** either --server or --client option must be set" << endl; - } - return 1; - } - if (!is_server && port == 0) { - cerr << "*** no port to server specified" << endl; - return 1; - } - if (is_server) { - auto calc = spawn(calculator); - try { - // try to publish math actor at given port - cout << "*** try publish at port " << port << endl; - auto p = io::publish(calc, port); - cout << "*** server successfully published at port " << p << endl; - cout << "*** press [enter] to quit" << endl; - string dummy; - std::getline(std::cin, dummy); - cout << "... cya" << endl; - } - catch (std::exception& e) { - cerr << "*** unable to publish math actor at port " << port << "\n" - << to_verbose_string(e) // prints exception type and e.what() - << endl; - } - anon_send_exit(calc, exit_reason::user_shutdown); - } - else { - client_repl(host, port); - } - await_all_actors_done(); - shutdown(); -} diff -Nru actor-framework-0.13.2/examples/remote_actors/group_chat.cpp actor-framework-0.16.3/examples/remote_actors/group_chat.cpp --- actor-framework-0.13.2/examples/remote_actors/group_chat.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/remote_actors/group_chat.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,156 +0,0 @@ -/******************************************************************************\ - * This example program represents a minimal terminal chat program * - * based on group communication. * - * * - * Setup for a minimal chat between "alice" and "bob": * - * - ./build/bin/group_server -p 4242 * - * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n alice * - * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n bob * -\ ******************************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include "caf/all.hpp" -#include "caf/io/all.hpp" - -#include "caf/string_algorithms.hpp" - -using namespace std; -using namespace caf; - -using broadcast_atom = atom_constant; - -struct line { string str; }; - -istream& operator>>(istream& is, line& l) { - getline(is, l.str); - return is; -} - -namespace { string s_last_line; } - -void client(event_based_actor* self, const string& name) { - self->become ( - [=](broadcast_atom, const string& message) { - for(auto& dest : self->joined_groups()) { - self->send(dest, name + ": " + message); - } - }, - [=](join_atom, const group& what) { - for (auto g : self->joined_groups()) { - cout << "*** leave " << to_string(g) << endl; - self->send(self, g, name + " has left the chatroom"); - self->leave(g); - } - cout << "*** join " << to_string(what) << endl; - self->join(what); - self->send(what, name + " has entered the chatroom"); - }, - [=](const string& txt) { - // don't print own messages - if (self->current_sender() != self) cout << txt << endl; - }, - [=](const group_down_msg& g) { - cout << "*** chatroom offline: " << to_string(g.source) << endl; - }, - others >> [=]() { - cout << "unexpected: " << to_string(self->current_message()) << endl; - } - ); -} - -int main(int argc, char** argv) { - string name; - string group_id; - auto res = message_builder(argv + 1, argv + argc).extract_opts({ - {"name,n", "set name", name}, - {"group,g", "join group", group_id} - }); - if (!res.remainder.empty()) { - std::cout << res.helptext << std::endl; - return 1; - } - if (res.opts.count("help") > 0) { - return 0; - } - while (name.empty()) { - cout << "please enter your name: " << flush; - if (!getline(cin, name)) { - cerr << "*** no name given... terminating" << endl; - return 1; - } - } - auto client_actor = spawn(client, name); - // evaluate group parameters - if (!group_id.empty()) { - auto p = group_id.find(':'); - if (p == std::string::npos) { - cerr << "*** error parsing argument " << group_id - << ", expected format: :"; - } else { - try { - auto module = group_id.substr(0, p); - auto group_uri = group_id.substr(p + 1); - auto g = (module == "remote") ? io::remote_group(group_uri) - : group::get(module, group_uri); - anon_send(client_actor, join_atom::value, g); - } - catch (exception& e) { - cerr << "*** exception: group::get(\"" << group_id.substr(0, p) - << "\", \"" << group_id.substr(p + 1) << "\") failed; " - << to_verbose_string(e) << endl; - } - } - } - cout << "*** starting client, type '/help' for a list of commands" << endl; - auto starts_with = [](const string& str) -> function (const string&)> { - return [=](const string& arg) -> optional { - if (arg.compare(0, str.size(), str) == 0) { - return arg; - } - return none; - }; - }; - istream_iterator eof; - vector words; - for (istream_iterator i(cin); i != eof; ++i) { - words.clear(); - split(words, i->str, is_any_of(" ")); - message_builder(words.begin(), words.end()).apply({ - on("/join", arg_match) >> [&](const string& mod, const string& id) { - try { - group grp = (mod == "remote") ? io::remote_group(id) - : group::get(mod, id); - anon_send(client_actor, join_atom::value, grp); - } - catch (exception& e) { - cerr << "*** exception: " << to_verbose_string(e) << endl; - } - }, - on("/quit") >> [&] { - // close STDIN; causes this match loop to quit - cin.setstate(ios_base::eofbit); - }, - on(starts_with("/"), any_vals) >> [&] { - cout << "*** available commands:\n" - " /join join a new chat channel\n" - " /quit quit the program\n" - " /help print this text\n" << flush; - }, - others >> [&] { - if (!s_last_line.empty()) { - anon_send(client_actor, broadcast_atom::value, s_last_line); - } - } - }); - } - // force actor to quit - anon_send_exit(client_actor, exit_reason::user_shutdown); - await_all_actors_done(); - shutdown(); -} diff -Nru actor-framework-0.13.2/examples/remote_actors/group_server.cpp actor-framework-0.16.3/examples/remote_actors/group_server.cpp --- actor-framework-0.13.2/examples/remote_actors/group_server.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/remote_actors/group_server.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -/******************************************************************************\ - * This example program represents a minimal IRC-like group * - * communication server. * - * * - * Setup for a minimal chat between "alice" and "bob": * - * - ./build/bin/group_server -p 4242 * - * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n alice * - * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n bob * -\ ******************************************************************************/ - -#include -#include -#include - -#include "caf/all.hpp" -#include "caf/io/all.hpp" - -using namespace std; -using namespace caf; - -optional to_port(const string& arg) { - char* last = nullptr; - auto res = strtoul(arg.c_str(), &last, 10); - if (last == (arg.c_str() + arg.size()) && res <= 65536) { - return static_cast(res); - } - return none; -} - -optional long_port(const string& arg) { - if (arg.compare(0, 7, "--port=") == 0) { - return to_port(arg.substr(7)); - } - return none; -} - -int main(int argc, char** argv) { - uint16_t port = 0; - message_builder{argv + 1, argv + argc}.apply({ - (on("-p", to_port) || on(long_port)) >> [&](uint16_t arg) { - port = arg; - } - }); - if (port <= 1024) { - cerr << "*** no port > 1024 given" << endl; - cout << "options:" << endl - << " -p | --port= set port" << endl; - return 1; - } - try { - // try to bind the group server to the given port, - // this allows other nodes to access groups of this server via - // group::get("remote", "@:"); - // note: it is not needed to explicitly create a on the server, - // as groups are created on-the-fly on first usage - io::publish_local_groups(port); - } - catch (bind_failure& e) { - // thrown if is already in use - cerr << "*** bind_failure: " << e.what() << endl; - return 2; - } - catch (network_error& e) { - // thrown on errors in the socket API - cerr << "*** network error: " << e.what() << endl; - return 2; - } - cout << "type 'quit' to shutdown the server" << endl; - string line; - while (getline(cin, line)) { - if (line == "quit") { - return 0; - } - else { - cerr << "illegal command" << endl; - } - } - shutdown(); -} diff -Nru actor-framework-0.13.2/examples/remote_actors/pingpong.proto actor-framework-0.16.3/examples/remote_actors/pingpong.proto --- actor-framework-0.13.2/examples/remote_actors/pingpong.proto 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/remote_actors/pingpong.proto 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -package org.libcppa; - -message Ping { - required int32 id = 1; -} -message Pong { - required int32 id = 1; -} - -message PingOrPong { - optional Ping ping = 1; - optional Pong pong = 2; -} diff -Nru actor-framework-0.13.2/examples/remoting/distributed_calculator.cpp actor-framework-0.16.3/examples/remoting/distributed_calculator.cpp --- actor-framework-0.13.2/examples/remoting/distributed_calculator.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/remoting/distributed_calculator.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,321 @@ +// This program is a distributed version of the math_actor example. +// Client and server use a stateless request/response protocol and the client +// is failure resilient by using a FIFO request queue. +// The client auto-reconnects and also allows for server reconfiguration. +// +// Run server at port 4242: +// - ./build/bin/distributed_math_actor -s -p 4242 +// +// Run client at the same host: +// - ./build/bin/distributed_math_actor -c -p 4242 + +// Manual refs: 222-234 (ConfiguringActorSystems) + +#include +#include +#include +#include +#include +#include +#include + +#include "caf/all.hpp" +#include "caf/io/all.hpp" + +using std::cout; +using std::cerr; +using std::endl; +using std::string; + +using namespace caf; + +namespace { + +constexpr auto task_timeout = std::chrono::seconds(10); + +using plus_atom = atom_constant; +using minus_atom = atom_constant; + +// our "service" +behavior calculator_fun() { + return { + [](plus_atom, int a, int b) { + return a + b; + }, + [](minus_atom, int a, int b) { + return a - b; + } + }; +} + +// State transition of the client for connecting to the server: +// +// +-------------+ +// | init | +// +-------------+ +// | +// V +// +-------------+ +// | unconnected |<------------------+ +// +-------------+ | +// | | +// | {connect Host Port} | +// | | +// V | +// +-------------+ {error} | +// +-------------->| connecting |-------------------+ +// | +-------------+ | +// | | | +// | | {ok, Calculator} | +// |{connect Host Port} | | +// | V | +// | +-------------+ {DOWN server} | +// +---------------| running |-------------------+ +// +-------------+ + +namespace client { + +// a simple calculater task: operation + operands +struct task { + atom_value op; + int lhs; + int rhs; +}; + +// the client queues pending tasks +struct state { + strong_actor_ptr current_server; + std::vector tasks; +}; + +// prototype definition for unconnected state +behavior unconnected(stateful_actor*); + +// prototype definition for transition to `connecting` with Host and Port +void connecting(stateful_actor*, + const std::string& host, uint16_t port); + +// prototype definition for transition to `running` with Calculator +behavior running(stateful_actor*, const actor& calculator); + +// starting point of our FSM +behavior init(stateful_actor* self) { + // transition to `unconnected` on server failure + self->set_down_handler([=](const down_msg& dm) { + if (dm.source == self->state.current_server) { + aout(self) << "*** lost connection to server" << endl; + self->state.current_server = nullptr; + self->become(unconnected(self)); + } + }); + return unconnected(self); +} + +behavior unconnected(stateful_actor* self) { + return { + [=](plus_atom op, int x, int y) { + self->state.tasks.emplace_back(task{op, x, y}); + }, + [=](minus_atom op, int x, int y) { + self->state.tasks.emplace_back(task{op, x, y}); + }, + [=](connect_atom, const std::string& host, uint16_t port) { + connecting(self, host, port); + } + }; +} + +void connecting(stateful_actor* self, + const std::string& host, uint16_t port) { + // make sure we are not pointing to an old server + self->state.current_server = nullptr; + // use request().await() to suspend regular behavior until MM responded + auto mm = self->system().middleman().actor_handle(); + self->request(mm, infinite, connect_atom::value, host, port).await( + [=](const node_id&, strong_actor_ptr serv, + const std::set& ifs) { + if (!serv) { + aout(self) << R"(*** no server found at ")" << host << R"(":)" + << port << endl; + return; + } + if (!ifs.empty()) { + aout(self) << R"(*** typed actor found at ")" << host << R"(":)" + << port << ", but expected an untyped actor "<< endl; + return; + } + aout(self) << "*** successfully connected to server" << endl; + self->state.current_server = serv; + auto hdl = actor_cast(serv); + self->monitor(hdl); + self->become(running(self, hdl)); + }, + [=](const error& err) { + aout(self) << R"(*** cannot connect to ")" << host << R"(":)" + << port << " => " << self->system().render(err) << endl; + self->become(unconnected(self)); + } + ); +} + +// prototype definition for transition to `running` with Calculator +behavior running(stateful_actor* self, const actor& calculator) { + auto send_task = [=](const task& x) { + self->request(calculator, task_timeout, x.op, x.lhs, x.rhs).then( + [=](int result) { + aout(self) << x.lhs << (x.op == plus_atom::value ? " + " : " - ") + << x.rhs << " = " << result << endl; + }, + [=](const error&) { + // simply try again by enqueueing the task to the mailbox again + self->send(self, x.op, x.lhs, x.rhs); + } + ); + }; + for (auto& x : self->state.tasks) + send_task(x); + self->state.tasks.clear(); + return { + [=](plus_atom op, int x, int y) { + send_task(task{op, x, y}); + }, + [=](minus_atom op, int x, int y) { + send_task(task{op, x, y}); + }, + [=](connect_atom, const std::string& host, uint16_t port) { + connecting(self, host, port); + } + }; +} + +} // namespace client + +// removes leading and trailing whitespaces +string trim(std::string s) { + auto not_space = [](char c) { return isspace(c) == 0; }; + // trim left + s.erase(s.begin(), find_if(s.begin(), s.end(), not_space)); + // trim right + s.erase(find_if(s.rbegin(), s.rend(), not_space).base(), s.end()); + return s; +} + +// tries to convert `str` to an int +optional toint(const string& str) { + char* end; + auto result = static_cast(strtol(str.c_str(), &end, 10)); + if (end == str.c_str() + str.size()) + return result; + return none; +} + +// converts "+" to the atom '+' and "-" to the atom '-' +optional plus_or_minus(const string& str) { + if (str == "+") + return plus_atom::value; + if (str == "-") + return minus_atom::value; + return none; +} + +class config : public actor_system_config { +public: + uint16_t port = 0; + std::string host = "localhost"; + bool server_mode = false; + + config() { + opt_group{custom_options_, "global"} + .add(port, "port,p", "set port") + .add(host, "host,H", "set host (ignored in server mode)") + .add(server_mode, "server-mode,s", "enable server mode"); + } +}; + +void client_repl(actor_system& system, const config& cfg) { + // keeps track of requests and tries to reconnect on server failures + auto usage = [] { + cout << "Usage:" << endl + << " quit : terminates the program" << endl + << " connect : connects to a remote actor" << endl + << " + : adds two integers" << endl + << " - : subtracts two integers" << endl + << endl; + }; + usage(); + bool done = false; + auto client = system.spawn(client::init); + if (!cfg.host.empty() && cfg.port > 0) + anon_send(client, connect_atom::value, cfg.host, cfg.port); + else + cout << "*** no server received via config, " + << R"(please use "connect " before using the calculator)" + << endl; + // defining the handler outside the loop is more efficient as it avoids + // re-creating the same object over and over again + message_handler eval{ + [&](const string& cmd) { + if (cmd != "quit") + return; + anon_send_exit(client, exit_reason::user_shutdown); + done = true; + }, + [&](string& arg0, string& arg1, string& arg2) { + if (arg0 == "connect") { + char* end = nullptr; + auto lport = strtoul(arg2.c_str(), &end, 10); + if (end != arg2.c_str() + arg2.size()) + cout << R"(")" << arg2 << R"(" is not an unsigned integer)" << endl; + else if (lport > std::numeric_limits::max()) + cout << R"(")" << arg2 << R"(" > )" + << std::numeric_limits::max() << endl; + else + anon_send(client, connect_atom::value, move(arg1), + static_cast(lport)); + } + else { + auto x = toint(arg0); + auto op = plus_or_minus(arg1); + auto y = toint(arg2); + if (x && y && op) + anon_send(client, *op, *x, *y); + } + } + }; + // read next line, split it, and feed to the eval handler + string line; + while (!done && std::getline(std::cin, line)) { + line = trim(std::move(line)); // ignore leading and trailing whitespaces + std::vector words; + split(words, line, is_any_of(" "), token_compress_on); + if (!message_builder(words.begin(), words.end()).apply(eval)) + usage(); + } +} + +void run_server(actor_system& system, const config& cfg) { + auto calc = system.spawn(calculator_fun); + // try to publish math actor at given port + cout << "*** try publish at port " << cfg.port << endl; + auto expected_port = io::publish(calc, cfg.port); + if (!expected_port) { + std::cerr << "*** publish failed: " + << system.render(expected_port.error()) << endl; + return; + } + cout << "*** server successfully published at port " << *expected_port << endl + << "*** press [enter] to quit" << endl; + string dummy; + std::getline(std::cin, dummy); + cout << "... cya" << endl; + anon_send_exit(calc, exit_reason::user_shutdown); +} + +void caf_main(actor_system& system, const config& cfg) { + auto f = cfg.server_mode ? run_server : client_repl; + f(system, cfg); +} + +} // namespace + +CAF_MAIN(io::middleman) diff -Nru actor-framework-0.13.2/examples/remoting/group_chat.cpp actor-framework-0.16.3/examples/remoting/group_chat.cpp --- actor-framework-0.13.2/examples/remoting/group_chat.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/remoting/group_chat.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,163 @@ +/******************************************************************************\ + * This example program represents a minimal terminal chat program * + * based on group communication. * + * * + * Setup for a minimal chat between "alice" and "bob": * + * - ./build/bin/group_chat -s -p 4242 * + * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n alice * + * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n bob * +\ ******************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "caf/all.hpp" +#include "caf/io/all.hpp" + +#include "caf/string_algorithms.hpp" + +using namespace std; +using namespace caf; + +namespace { + +using broadcast_atom = atom_constant; + +struct line { string str; }; + +istream& operator>>(istream& is, line& l) { + getline(is, l.str); + return is; +} + +behavior client(event_based_actor* self, const string& name) { + return { + [=](broadcast_atom, const string& message) { + for(auto& dest : self->joined_groups()) { + self->send(dest, name + ": " + message); + } + }, + [=](join_atom, const group& what) { + for (const auto& g : self->joined_groups()) { + cout << "*** leave " << to_string(g) << endl; + self->send(g, name + " has left the chatroom"); + self->leave(g); + } + cout << "*** join " << to_string(what) << endl; + self->join(what); + self->send(what, name + " has entered the chatroom"); + }, + [=](const string& txt) { + // don't print own messages + if (self->current_sender() != self) + cout << txt << endl; + }, + [=](const group_down_msg& g) { + cout << "*** chatroom offline: " << to_string(g.source) << endl; + } + }; +} + +class config : public actor_system_config { +public: + std::string name; + std::vector group_uris; + uint16_t port = 0; + bool server_mode = false; + + config() { + opt_group{custom_options_, "global"} + .add(name, "name,n", "set name") + .add(group_uris, "group,g", "join group") + .add(server_mode, "server,s", "run in server mode") + .add(port, "port,p", "set port (ignored in client mode)"); + } +}; + +void run_server(actor_system& system, const config& cfg) { + auto res = system.middleman().publish_local_groups(cfg.port); + if (! res) { + std::cerr << "*** publishing local groups failed: " + << system.render(res.error()) << endl; + return; + } + cout << "*** listening at port " << *res << endl + << "*** press [enter] to quit" << endl; + string dummy; + std::getline(std::cin, dummy); + cout << "... cya" << endl; +} + +void run_client(actor_system& system, const config& cfg) { + auto name = cfg.name; + while (name.empty()) { + cout << "please enter your name: " << flush; + if (!getline(cin, name)) { + cerr << "*** no name given... terminating" << endl; + return; + } + } + cout << "*** starting client, type '/help' for a list of commands" << endl; + auto client_actor = system.spawn(client, name); + for (auto& uri : cfg.group_uris) { + auto tmp = system.groups().get(uri); + if (tmp) + anon_send(client_actor, join_atom::value, std::move(*tmp)); + else + cerr << R"(*** failed to parse ")" << uri << R"(" as group URI: )" + << system.render(tmp.error()) << endl; + } + istream_iterator eof; + vector words; + for (istream_iterator i(cin); i != eof; ++i) { + auto send_input = [&] { + if (!i->str.empty()) + anon_send(client_actor, broadcast_atom::value, i->str); + }; + words.clear(); + split(words, i->str, is_any_of(" ")); + auto res = message_builder(words.begin(), words.end()).apply({ + [&](const string& cmd, const string& mod, const string& id) { + if (cmd == "/join") { + auto grp = system.groups().get(mod, id); + if (grp) + anon_send(client_actor, join_atom::value, *grp); + } + else { + send_input(); + } + }, + [&](const string& cmd) { + if (cmd == "/quit") { + cin.setstate(ios_base::eofbit); + } + else if (cmd[0] == '/') { + cout << "*** available commands:\n" + " /join join a new chat channel\n" + " /quit quit the program\n" + " /help print this text\n" << flush; + } + else { + send_input(); + } + } + }); + if (!res) + send_input(); + } + // force actor to quit + anon_send_exit(client_actor, exit_reason::user_shutdown); +} + +void caf_main(actor_system& system, const config& cfg) { + auto f = cfg.server_mode ? run_server : run_client; + f(system, cfg); +} + +} // namespace + +CAF_MAIN(io::middleman) diff -Nru actor-framework-0.13.2/examples/remoting/group_server.cpp actor-framework-0.16.3/examples/remoting/group_server.cpp --- actor-framework-0.13.2/examples/remoting/group_server.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/remoting/group_server.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,46 @@ +/******************************************************************************\ + * This example program represents a minimal IRC-like group * + * communication server. * + * * + * Setup for a minimal chat between "alice" and "bob": * + * - ./build/bin/group_server -p 4242 * + * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n alice * + * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n bob * +\ ******************************************************************************/ + +#include +#include +#include + +#include "caf/all.hpp" +#include "caf/io/all.hpp" + +using namespace std; +using namespace caf; + +namespace { + +class config : public actor_system_config { +public: + uint16_t port = 0; + + config() { + opt_group{custom_options_, "global"} + .add(port, "port,p", "set port"); + } +}; + +void caf_main(actor_system& system, const config& cfg) { + system.middleman().publish_local_groups(cfg.port); + cout << "type 'quit' to shutdown the server" << endl; + string line; + while (getline(cin, line)) + if (line == "quit") + return; + else + cerr << "illegal command" << endl; +} + +} // namespace + +CAF_MAIN(io::middleman) diff -Nru actor-framework-0.13.2/examples/remoting/pingpong.proto actor-framework-0.16.3/examples/remoting/pingpong.proto --- actor-framework-0.13.2/examples/remoting/pingpong.proto 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/remoting/pingpong.proto 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,13 @@ +package org.libcppa; + +message Ping { + required int32 id = 1; +} +message Pong { + required int32 id = 1; +} + +message PingOrPong { + optional Ping ping = 1; + optional Pong pong = 2; +} diff -Nru actor-framework-0.13.2/examples/remoting/remote_spawn.cpp actor-framework-0.16.3/examples/remoting/remote_spawn.cpp --- actor-framework-0.13.2/examples/remoting/remote_spawn.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/remoting/remote_spawn.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,155 @@ +// This program illustrates how to spawn a simple calculator +// across the network. +// +// Run server at port 4242: +// - remote_spawn -s -p 4242 +// +// Run client at the same host: +// - remote_spawn -H localhost -p 4242 + +// Manual refs: 33-39, 99-101,106,110 (ConfiguringActorApplications) +// 125-143 (RemoteSpawn) + +#include +#include +#include +#include +#include +#include +#include + +#include "caf/all.hpp" +#include "caf/io/all.hpp" + +using std::cout; +using std::cerr; +using std::endl; +using std::string; + +using namespace caf; + +namespace { + +using add_atom = atom_constant; +using sub_atom = atom_constant; + +using calculator = typed_actor::with, + replies_to::with>; + +calculator::behavior_type calculator_fun(calculator::pointer self) { + return { + [=](add_atom, int a, int b) -> int { + aout(self) << "received task from a remote node" << endl; + return a + b; + }, + [=](sub_atom, int a, int b) -> int { + aout(self) << "received task from a remote node" << endl; + return a - b; + } + }; +} + +// removes leading and trailing whitespaces +string trim(string s) { + auto not_space = [](char c) { return isspace(c) == 0; }; + // trim left + s.erase(s.begin(), find_if(s.begin(), s.end(), not_space)); + // trim right + s.erase(find_if(s.rbegin(), s.rend(), not_space).base(), s.end()); + return s; +} + +// implements our main loop for reading user input +void client_repl(function_view f) { + auto usage = [] { + cout << "Usage:" << endl + << " quit : terminate program" << endl + << " + : adds two integers" << endl + << " - : subtracts two integers" << endl << endl; + }; + usage(); + // read next line, split it, and evaluate user input + string line; + while (std::getline(std::cin, line)) { + if ((line = trim(std::move(line))) == "quit") + return; + std::vector words; + split(words, line, is_any_of(" "), token_compress_on); + if (words.size() != 3) { + usage(); + continue; + } + auto to_int = [](const string& str) -> optional { + char* end = nullptr; + auto res = strtol(str.c_str(), &end, 10); + if (end == str.c_str() + str.size()) + return static_cast(res); + return none; + }; + auto x = to_int(words[0]); + auto y = to_int(words[2]); + if (!x || !y || (words[1] != "+" && words[1] != "-")) + usage(); + else + cout << " = " << (words[1] == "+" ? f(add_atom::value, *x, *y) + : f(sub_atom::value, *x, *y)) << "\n"; + } +} + +struct config : actor_system_config { + config() { + add_actor_type("calculator", calculator_fun); + opt_group{custom_options_, "global"} + .add(port, "port,p", "set port") + .add(host, "host,H", "set node (ignored in server mode)") + .add(server_mode, "server-mode,s", "enable server mode"); + } + uint16_t port = 0; + string host = "localhost"; + bool server_mode = false; +}; + +void server(actor_system& system, const config& cfg) { + auto res = system.middleman().open(cfg.port); + if (!res) { + cerr << "*** cannot open port: " + << system.render(res.error()) << endl; + return; + } + cout << "*** running on port: " + << *res << endl + << "*** press to shutdown server" << endl; + getchar(); +} + +void client(actor_system& system, const config& cfg) { + auto node = system.middleman().connect(cfg.host, cfg.port); + if (!node) { + cerr << "*** connect failed: " + << system.render(node.error()) << endl; + return; + } + auto type = "calculator"; // type of the actor we wish to spawn + auto args = make_message(); // arguments to construct the actor + auto tout = std::chrono::seconds(30); // wait no longer than 30s + auto worker = system.middleman().remote_spawn(*node, type, + args, tout); + if (!worker) { + cerr << "*** remote spawn failed: " + << system.render(worker.error()) << endl; + return; + } + // start using worker in main loop + client_repl(make_function_view(*worker)); + // be a good citizen and terminate remotely spawned actor before exiting + anon_send_exit(*worker, exit_reason::kill); +} + +void caf_main(actor_system& system, const config& cfg) { + auto f = cfg.server_mode ? server : client; + f(system, cfg); +} + +} // namespace + +CAF_MAIN(io::middleman) diff -Nru actor-framework-0.13.2/examples/streaming/integer_stream.cpp actor-framework-0.16.3/examples/streaming/integer_stream.cpp --- actor-framework-0.13.2/examples/streaming/integer_stream.cpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/examples/streaming/integer_stream.cpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,143 @@ +/****************************************************************************** + * Basic, non-interactive streaming example for processing integers. * + ******************************************************************************/ + +// Manual refs: lines 17-52, 54-87, 89-120, 133-139 (Streaming) + +#include +#include + +#include "caf/all.hpp" + +using std::endl; +using namespace caf; + +namespace { + +// Simple source for generating a stream of integers from [0, n). +behavior int_source(event_based_actor* self) { + return { + [=](open_atom, int n) { + // Produce at least one value. + if (n <= 0) + n = 1; + // Create a stream manager for implementing a stream source. The + // streaming logic requires three functions: initializer, generator, and + // predicate. + return self->make_source( + // Initializer. The type of the first argument (state) is freely + // chosen. If no state is required, `caf::unit_t` can be used here. + [](int& x) { + x = 0; + }, + // Generator. This function is called by CAF to produce new stream + // elements for downstream actors. The `x` argument is our state again + // (with our freely chosen type). The second argument `out` points to + // the output buffer. The template argument (here: int) determines what + // elements downstream actors receive in this stream. Finally, `num` is + // a hint from CAF how many elements we should ideally insert into + // `out`. We can always insert fewer or more items. + [n](int& x, downstream& out, size_t num) { + auto max_x = std::min(x + static_cast(num), n); + for (; x < max_x; ++x) + out.push(x); + }, + // Predicate. This function tells CAF when we reached the end. + [n](const int& x) { + return x == n; + } + ); + } + }; +} + +// Simple stage that only selects even numbers. +behavior int_selector(event_based_actor* self) { + return { + [=](stream in) { + // Create a stream manager for implementing a stream stage. Similar to + // `make_source`, we need three functions: initialzer, processor, and + // finalizer. + return self->make_stage( + // Our input source. + in, + // Initializer. Here, we don't need any state and simply use unit_t. + [](unit_t&) { + // nop + }, + // Processor. This function takes individual input elements as `val` + // and forwards even integers to `out`. + [](unit_t&, downstream& out, int val) { + if (val % 2 == 0) + out.push(val); + }, + // Finalizer. Allows us to run cleanup code once the stream terminates. + [=](unit_t&, const error& err) { + if (err) { + aout(self) << "int_selector aborted with error: " << err + << std::endl; + } else { + aout(self) << "int_selector finalized" << std::endl; + } + // else: regular stream shutdown + } + ); + } + }; +} + +behavior int_sink(event_based_actor* self) { + return { + [=](stream in) { + // Create a stream manager for implementing a stream sink. Once more, we + // have to provide three functions: Initializer, Consumer, Finalizer. + return self->make_sink( + // Our input source. + in, + // Initializer. Here, we store all values we receive. Note that streams + // are potentially unbound, so this is usually a bad idea outside small + // examples like this one. + [](std::vector&) { + // nop + }, + // Consumer. Takes individual input elements as `val` and stores them + // in our history. + [](std::vector& xs, int val) { + xs.emplace_back(val); + }, + // Finalizer. Allows us to run cleanup code once the stream terminates. + [=](std::vector& xs, const error& err) { + if (err) { + aout(self) << "int_sink aborted with error: " << err << std::endl; + } else { + aout(self) << "int_sink finalized after receiving: " << xs + << std::endl; + } + } + ); + } + }; +} + +struct config : actor_system_config { + config() { + opt_group{custom_options_, "global"} + .add(with_stage, "with-stage,s", "use a stage for filtering odd numbers") + .add(n, "num-values,n", "number of values produced by the source"); + } + + bool with_stage = false; + int n = 100; +}; + +void caf_main(actor_system& sys, const config& cfg) { + auto src = sys.spawn(int_source); + auto snk = sys.spawn(int_sink); + auto pipeline = cfg.with_stage ? snk * sys.spawn(int_selector) * src + : snk * src; + anon_send(pipeline, open_atom::value, cfg.n); +} + +} // namespace + +CAF_MAIN() diff -Nru actor-framework-0.13.2/examples/type_system/announce_1.cpp actor-framework-0.16.3/examples/type_system/announce_1.cpp --- actor-framework-0.13.2/examples/type_system/announce_1.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/type_system/announce_1.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -#include -#include -#include -#include - -#include "caf/all.hpp" -#include "caf/binary_serializer.hpp" -#include "caf/binary_deserializer.hpp" - -using std::cout; -using std::endl; -using std::vector; - -using namespace caf; - -// POD struct -struct foo { - std::vector a; - int b; -}; - -// announce requires foo to have the equal operator implemented -bool operator==(const foo& lhs, const foo& rhs) { - return lhs.a == rhs.a - && lhs.b == rhs.b; -} - -// a pair of two ints -using foo_pair = std::pair; - -// another pair of two ints -using foo_pair2 = std::pair; - -// a struct with member vector> -struct foo2 { - int a; - vector> b; -}; - -bool operator==( const foo2& lhs, const foo2& rhs ) { - return lhs.a == rhs.a && lhs.b == rhs.b; -} - -// receives `remaining` messages -void testee(event_based_actor* self, size_t remaining) { - auto set_next_behavior = [=] { - if (remaining > 1) testee(self, remaining - 1); - else self->quit(); - }; - self->become ( - // note: we sent a foo_pair2, but match on foo_pair - // that's safe because both are aliases for std::pair - on() >> [=](const foo_pair& val) { - cout << "foo_pair(" - << val.first << ", " - << val.second << ")" - << endl; - set_next_behavior(); - }, - on() >> [=](const foo& val) { - cout << "foo({"; - auto i = val.a.begin(); - auto end = val.a.end(); - if (i != end) { - cout << *i; - while (++i != end) { - cout << ", " << *i; - } - } - cout << "}, " << val.b << ")" << endl; - set_next_behavior(); - } - ); -} - -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 foo2 to the libcaf type system, - // note that recursive containers are managed automatically by libcaf - announce("foo2", &foo2::a, &foo2::b); - - foo2 vd; - vd.a = 5; - vd.b.resize(1); - vd.b.back().push_back(42); - - vector buf; - binary_serializer bs(std::back_inserter(buf)); - bs << vd; - - binary_deserializer bd(buf.data(), buf.size()); - foo2 vd2; - uniform_typeid()->deserialize(&vd2, &bd); - - assert(vd == vd2); - - // announce std::pair to the type system - announce("foo_pair", &foo_pair::first, &foo_pair::second); - - // libcaf returns the same uniform_type_info - // instance for the type aliases foo_pair and foo_pair2 - assert(uniform_typeid() == uniform_typeid()); - - // spawn a testee that receives two messages - auto t = spawn(testee, 2); - { - scoped_actor self; - // send t a foo - self->send(t, foo{std::vector{1, 2, 3, 4}, 5}); - // send t a foo_pair2 - self->send(t, foo_pair2{3, 4}); - } - await_all_actors_done(); - shutdown(); - return 0; -} diff -Nru actor-framework-0.13.2/examples/type_system/announce_2.cpp actor-framework-0.16.3/examples/type_system/announce_2.cpp --- actor-framework-0.13.2/examples/type_system/announce_2.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/type_system/announce_2.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -#include -#include - -#include "caf/all.hpp" - -using std::cout; -using std::endl; -using std::make_pair; - -using namespace caf; - -// a simple class using getter and setter member functions -class foo { - - int m_a; - int m_b; - - public: - - foo(int a0 = 0, int b0 = 0) : m_a(a0), m_b(b0) { } - - foo(const foo&) = default; - - foo& operator=(const foo&) = default; - - int a() const { return m_a; } - - void set_a(int val) { m_a = val; } - - int b() const { return m_b; } - - void set_b(int val) { m_b = val; } - -}; - -// announce requires foo to be comparable -bool operator==(const foo& lhs, const foo& rhs) { - return lhs.a() == rhs.a() - && lhs.b() == rhs.b(); -} - -void testee(event_based_actor* self) { - self->become ( - on() >> [=](const foo& val) { - aout(self) << "foo(" - << val.a() << ", " - << val.b() << ")" - << endl; - self->quit(); - } - ); -} - -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)); - { - scoped_actor self; - auto t = spawn(testee); - self->send(t, foo{1, 2}); - } - await_all_actors_done(); - shutdown(); - return 0; -} diff -Nru actor-framework-0.13.2/examples/type_system/announce_3.cpp actor-framework-0.16.3/examples/type_system/announce_3.cpp --- actor-framework-0.13.2/examples/type_system/announce_3.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/type_system/announce_3.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -#include -#include - -#include "caf/all.hpp" - -using std::cout; -using std::endl; -using std::make_pair; - -using namespace caf; - -// a simple class using overloaded getter and setter member functions -class foo { - - int m_a; - int m_b; - - public: - - foo() : m_a(0), m_b(0) { } - - foo(int a0, int b0) : m_a(a0), m_b(b0) { } - - foo(const foo&) = default; - - foo& operator=(const foo&) = default; - - int a() const { return m_a; } - - void a(int val) { m_a = val; } - - int b() const { return m_b; } - - void b(int val) { m_b = val; } - -}; - -// announce requires foo to have the equal operator implemented -bool operator==(const foo& lhs, const foo& rhs) { - return lhs.a() == rhs.a() - && lhs.b() == rhs.b(); -} - -// a member function pointer to get an attribute of foo -using foo_getter = int (foo::*)() const; -// a member function pointer to set an attribute of foo -using foo_setter = void (foo::*)(int); - -void testee(event_based_actor* self) { - self->become ( - on() >> [=](const foo& val) { - aout(self) << "foo(" - << val.a() << ", " - << val.b() << ")" - << endl; - self->quit(); - } - ); -} - -int main(int, char**) { - // since the member function "a" is ambiguous, the compiler - // also needs a type to select the correct overload - foo_getter g1 = &foo::a; - foo_setter s1 = &foo::a; - // same is true for b - foo_getter g2 = &foo::b; - foo_setter s2 = &foo::b; - - // equal to example 3 - announce("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::a), - static_cast(&foo::a)), - make_pair(static_cast(&foo::b), - static_cast(&foo::b))); - - // spawn a new testee and send it a foo - { - scoped_actor self; - self->send(spawn(testee), foo{1, 2}); - } - await_all_actors_done(); - shutdown(); - return 0; -} - diff -Nru actor-framework-0.13.2/examples/type_system/announce_4.cpp actor-framework-0.16.3/examples/type_system/announce_4.cpp --- actor-framework-0.13.2/examples/type_system/announce_4.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/type_system/announce_4.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +0,0 @@ -#include -#include "caf/all.hpp" -#include "caf/to_string.hpp" - -using std::cout; -using std::endl; -using std::make_pair; - -using namespace caf; - -// the foo class from example 3 -class foo { - - int m_a; - int m_b; - - public: - - foo() : m_a(0), m_b(0) { } - - foo(int a0, int b0) : m_a(a0), m_b(b0) { } - - foo(const foo&) = default; - - foo& operator=(const foo&) = default; - - int a() const { return m_a; } - - void set_a(int val) { m_a = val; } - - int b() const { return m_b; } - - void set_b(int val) { m_b = val; } - -}; - -// needed for operator==() of bar -bool operator==(const foo& lhs, const foo& rhs) { - return lhs.a() == rhs.a() - && lhs.b() == rhs.b(); -} - -// simple struct that has foo as a member -struct bar { - foo f; - int i; -}; - -// announce requires bar to have the equal operator implemented -bool operator==(const bar& lhs, const bar& rhs) { - return lhs.f == rhs.f - && lhs.i == rhs.i; -} - -// "worst case" class ... not a good software design at all ;) -class baz { - - foo m_f; - - public: - - bar b; - - // announce requires a default constructor - baz() = default; - - inline baz(const foo& mf, const bar& mb) : m_f(mf), b(mb) { } - - const foo& f() const { return m_f; } - - void set_f(const foo& val) { m_f = val; } - -}; - -// even worst case classes have to implement operator== -bool operator==(const baz& lhs, const baz& rhs) { - return lhs.f() == rhs.f() - && lhs.b == rhs.b; -} - -// receives `remaining` messages -void testee(event_based_actor* self, size_t remaining) { - auto set_next_behavior = [=] { - if (remaining > 1) testee(self, remaining - 1); - else self->quit(); - }; - self->become ( - on() >> [=](const bar& val) { - aout(self) << "bar(foo(" - << val.f.a() << ", " - << val.f.b() << "), " - << val.i << ")" - << endl; - set_next_behavior(); - }, - on() >> [=](const baz& val) { - // prints: baz ( foo ( 1, 2 ), bar ( foo ( 3, 4 ), 5 ) ) - aout(self) << to_string(make_message(val)) << endl; - set_next_behavior(); - } - ); -} - -int main(int, char**) { - // bar has a non-trivial data member f, thus, we have to told - // announce how to serialize/deserialize this member; - // this is was the compound_member function is for; - // 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 - 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", 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, meta_bar_f(), &bar::i)); - // spawn a testee that receives two messages - auto t = spawn(testee, 2); - { - scoped_actor self; - self->send(t, bar{foo{1, 2}, 3}); - self->send(t, baz{foo{1, 2}, bar{foo{3, 4}, 5}}); - } - await_all_actors_done(); - shutdown(); - return 0; -} - diff -Nru actor-framework-0.13.2/examples/type_system/announce_5.cpp actor-framework-0.16.3/examples/type_system/announce_5.cpp --- actor-framework-0.13.2/examples/type_system/announce_5.cpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/examples/type_system/announce_5.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,216 +0,0 @@ -/****************************************************************************** - * This example shows how to implement serialize/deserialize to announce * - * non-trivial data structures to the libcaf type system. * - * * - * Announce() auto-detects STL compliant containers and provides * - * an easy way to tell libcaf how to serialize user defined types. * - * See announce_example 1-4 for usage examples. * - * * - * You should use "hand written" serialize/deserialize implementations * - * if and only if there is no other way. * - ******************************************************************************/ - -#include -#include -#include "caf/all.hpp" -#include "caf/to_string.hpp" - -using std::cout; -using std::endl; - -using namespace caf; - -namespace { - -// a node containing an integer and a vector of children -struct tree_node { - std::uint32_t value; - std::vector children; - - tree_node(std::uint32_t v = 0) : value(v) { - } - - tree_node& add_child(std::uint32_t v = 0) { - children.push_back({ v }); - return *this; - } - - tree_node(const tree_node&) = default; - - // recursively print this node and all of its children to stdout - void print() const { - // format is: value { children0, children1, ..., childrenN } - // e.g., 10 { 20 { 21, 22 }, 30 } - cout << value; - if (children.empty() == false) { - cout << " { "; - auto begin = children.begin(); - auto end = children.end(); - for (auto i = begin; i != end; ++i) { - if (i != begin) { - cout << ", "; - } - i->print(); - } - cout << " } "; - } - } - -}; - -// a very primitive tree implementation -struct tree { - tree_node root; - - // print tree to stdout - void print() const { - cout << "tree::print: "; - root.print(); - cout << endl; - } - -}; - -// tree nodes are equals if values and all values of all children are equal -bool operator==(const tree_node& lhs, const tree_node& rhs) { - return (lhs.value == rhs.value) && (lhs.children == rhs.children); -} - -bool operator==(const tree& lhs, const tree& rhs) { - return lhs.root == rhs.root; -} - -// abstract_uniform_type_info implements all functions of uniform_type_info -// except for serialize() and deserialize() if the template parameter T: -// - does have a default constructor -// - does have a copy constructor -// - does provide operator== -class tree_type_info : public detail::abstract_uniform_type_info { - public: - tree_type_info() : detail::abstract_uniform_type_info("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(ptr); - // recursively serialize nodes, beginning with root - serialize_node(tree_ptr->root, sink); - } - - void deserialize(void* ptr, deserializer* source) const { - // ptr is guaranteed to be a pointer of type tree - auto tree_ptr = reinterpret_cast(ptr); - tree_ptr->root.children.clear(); - // recursively deserialize nodes, beginning with root - deserialize_node(tree_ptr->root, source); - } - - private: - void serialize_node(const tree_node& node, serializer* sink) const { - // value, ... children ... - sink->write_value(node.value); - sink->begin_sequence(node.children.size()); - for (const tree_node& subnode : node.children) { - serialize_node(subnode, sink); - } - sink->end_sequence(); - } - - void deserialize_node(tree_node& node, deserializer* source) const { - // value, ... children ... - auto value = source->read(); - node.value = value; - auto num_children = source->begin_sequence(); - for (size_t i = 0; i < num_children; ++i) { - node.add_child(); - deserialize_node(node.children.back(), source); - } - source->end_sequence(); - } -}; - -using tree_vector = std::vector; - -// receives `remaining` messages -void testee(event_based_actor* self, size_t remaining) { - auto set_next_behavior = [=] { - if (remaining > 1) testee(self, remaining - 1); - else self->quit(); - }; - self->become ( - [=](const tree& tmsg) { - // prints the tree in its serialized format: - // @<> ( { tree ( 0, { 10, { 11, { }, 12, { }, 13, { } }, 20, { 21, { }, 22, { } } } ) } ) - cout << "to_string(self->current_message()): " - << to_string(self->current_message()) - << endl; - // prints the tree using the print member function: - // 0 { 10 { 11, 12, 13 } , 20 { 21, 22 } } - tmsg.print(); - set_next_behavior(); - }, - [=](const tree_vector& trees) { - // prints "received 2 trees" - cout << "received " << trees.size() << " trees" << endl; - // prints: - // @<> ( { - // std::vector> ( { - // tree ( 0, { 10, { 11, { }, 12, { }, 13, { } }, 20, { 21, { }, 22, { } } } ), - // tree ( 0, { 10, { 11, { }, 12, { }, 13, { } }, 20, { 21, { }, 22, { } } } ) - // ) - // } ) - cout << "to_string: " << to_string(self->current_message()) << endl; - set_next_behavior(); - } - ); -} - -} // namespace - -int main() { - // the tree_type_info is owned by libcaf after this function call - announce(typeid(tree), std::unique_ptr{new tree_type_info}); - announce("tree_vector"); - - tree t0; // create a tree and fill it with some data - - t0.root.add_child(10); - t0.root.children.back().add_child(11).add_child(12).add_child(13); - - t0.root.add_child(20); - t0.root.children.back().add_child(21).add_child(22); - - /* - tree t is now: - 0 - / \ - / \ - / \ - 10 20 - / |\ / \ - / | \ / \ - 11 12 13 21 22 - */ - - { // lifetime scope of self - scoped_actor self; - - // spawn a testee that receives two messages - auto t = spawn(testee, 2); - - // send a tree - self->send(t, t0); - - // send a vector of trees - tree_vector tvec; - tvec.push_back(t0); - tvec.push_back(t0); - self->send(t, tvec); - } - - await_all_actors_done(); - shutdown(); - return 0; -} diff -Nru actor-framework-0.13.2/.gitignore actor-framework-0.16.3/.gitignore --- actor-framework-0.13.2/.gitignore 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/.gitignore 2018-12-27 20:33:32.000000000 +0000 @@ -1,6 +1,5 @@ *.DS_Store Doxyfile -cppa.creator.user* html/ build/* cli_build/* @@ -9,9 +8,12 @@ Makefile bin/* lib/* -manual/build-pdf/* -manual/build-html/* -manual/*.toc -manual/manual.html -manual/variables.tex +manual *.swp +bii/* +.idea/ +.ycm_extra_conf.pyc +blog_release_note.md +github_release_note.md +.make-release-steps.bash +*.swo diff -Nru actor-framework-0.13.2/.gitmodules actor-framework-0.16.3/.gitmodules --- actor-framework-0.13.2/.gitmodules 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/.gitmodules 2018-12-27 20:33:32.000000000 +0000 @@ -1,15 +1,3 @@ -[submodule "benchmarks"] - path = benchmarks - url = https://github.com/actor-framework/benchmarks.git -[submodule "nexus"] - path = nexus - url = https://github.com/actor-framework/nexus.git -[submodule "opencl"] - path = libcaf_opencl - url = https://github.com/actor-framework/opencl.git -[submodule "libcaf_riac"] - path = libcaf_riac - url = https://github.com/actor-framework/riac.git -[submodule "cash"] - path = cash - url = https://github.com/actor-framework/cash.git +[submodule "libcaf_python/third_party/pybind"] + path = libcaf_python/third_party/pybind + url = https://github.com/pybind/pybind11.git diff -Nru actor-framework-0.13.2/HACKING.md actor-framework-0.16.3/HACKING.md --- actor-framework-0.13.2/HACKING.md 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/HACKING.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,419 +0,0 @@ -This document specifies the coding style for the C++ Actor Framework. -The style is loosely based on the -[Google C++ Style Guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml) -and the coding conventions used by the STL. - -Example for the Impatient -========================= - -```cpp -// libcaf_example/caf/example/my_class.hpp - -#ifndef CAF_EXAMPLE_MY_CLASS_HPP -#define CAF_EXAMPLE_MY_CLASS_HPP - -#include - -namespace caf { -namespace example { - -/** - * This class is only being used as style guide example. - */ -class my_class { - public: - /** - * Brief description. More description. Note that CAF uses the - * "JavaDoc-style" autobrief option, i.e., everything up until the - * first dot is the brief description. - */ - my_class(); - - /** - * Destructs `my_class`. Please use Markdown in comments. - */ - ~my_class(); - - // do not use the @return if you start the brief description with "Returns" - /** - * Returns the name of this instance. - */ - inline const std::string& name() const { - return m_name; - } - - /** - * Sets the name of this instance. - */ - inline void name(std::string new_name) { - m_name = std::move(new_name); - } - - /** - * Prints the name to `STDIN`. - */ - void print_name() const; - - /** - * Does something (maybe). - */ - void do_something(); - - /** - * Does something else. - */ - void do_something_else(); - - private: - std::string m_name; -}; - -} // namespace example -} // namespace caf - -#endif // CAF_EXAMPLE_MY_CLASS_HPP -``` - -```cpp -// libcaf_example/src/my_class.cpp - -#include "caf/example/my_class.hpp" - -#include - -namespace caf { -namespace example { - -namespace { - -constexpr const char default_name[] = "my object"; - -} // namespace - -my_class::my_class() : m_name(default_name) { - // nop -} - -my_class::~my_class() { - // nop -} - -void my_class::print_name() const { - std::cout << name() << std::endl; -} - -void my_class::do_something() { - if (name() == default_name) { - std::cout << "You didn't gave me a proper name, so I " - << "refuse to do something." - << std::endl; - } else { - std::cout << "You gave me the name " << name() - << "... Do you really think I'm willing to do something " - "for you after insulting me like that?" - << std::endl; - } -} - -void::my_class::do_something_else() { - switch (default_name[0]) { - case 'a': - // handle a - break; - case 'b': - // handle b - break; - default: - handle_default(); - } -} - -} // namespace example -} // namespace caf - -``` - - -General rules -============= - -- Use 2 spaces per indentation level. - -- The maximum number of characters per line is 80. - -- Never use tabs. - -- Vertical whitespaces separate functions and are not used inside functions: - use comments to document logical blocks. - -- Header filenames end in `.hpp`, implementation files end in `.cpp`. - -- Never declare more than one variable per line. - -- `*` and `&` bind to the *type*, e.g., `const std::string& arg`. - -- Namespaces do not increase the indentation level. - -- Access modifiers, e.g. `public`, are indented one space. - -- Use the order `public`, `protected`, and then `private`. - -- Always use `auto` to declare a variable unless you cannot initialize it - immediately or if you actually want a type conversion. In the latter case, - provide a comment why this conversion is necessary. - -- Never use unwrapped, manual resource management such as `new` and `delete`. - -- Do not use `typedef`. The syntax provided by `using` is much cleaner. - -- Use `typename` only when referring to dependent names. - -- Keywords are always followed by a whitespace: `if (...)`, `template <...>`, - `while (...)`, etc. - -- Always use `{}` for bodies of control structures such as `if` or `while`, - even for bodies consiting only of a single statement. - -- Opening braces belong to the same line: - ```cpp - - if (my_condition) { - my_fun(); - } else { - my_other_fun(); - } - ``` - -- Use standard order for readability: C standard libraries, C++ standard - libraries, other libraries, (your) CAF headers: - ```cpp - - #include - - #include - - #include "some/other/library.hpp" - - #include "caf/example/myclass.hpp" - ``` - -- When declaring a function, the order of parameters is: outputs, then inputs. - This follows the parameter order from the STL. - -- Never use C-style casts. - - -Naming -====== - -- Class names, constants, and function names are all-lowercase with underscores. - -- Types and variables should be nouns, while functions performing an action - should be "command" verbs. Classes used to implement metaprogramming - functions also should use verbs, e.g., `remove_const`. - -- Member variables use the prefix `m_`. - -- Thread-local variables use the prefix `t_`. - -- Static, non-const variables are declared in the anonymous namespace - and use the prefix `s_`. - -- Template parameter names use CamelCase. - -- Getter and setter use the name of the member without the `m_` prefix: - ```cpp - - class some_fun { - public: - // ... - int value() const { - return m_value; - } - void value(int new_value) { - m_value = new_value; - } - private: - int m_value; - }; - ``` - -- Use `T` for generic, unconstrained template parameters and `x` - for generic function arguments. Suffix both with `s` for - template parameter packs: - ```cpp - - template - void print(const Ts&... xs) { - // ... - } - ``` - - -Headers -======= - -- Each `.cpp` file has an associated `.hpp` file. - Exceptions to this rule are unit tests and `main.cpp` files. - -- Each class has its own pair of header and implementation - files and the relative path for the header file is derived from its full name. - For example, the header file for `caf::example::my_class` of `libcaf_example` - is located at `libcaf_example/caf/example/my_class.hpp` and the - source file at `libcaf_example/src/my_class.cpp`. - -- All header files should use `#define` guards to prevent multiple inclusion. - The symbol name is `____HPP`. - -- Do not `#include` when a forward declaration suffices. - -- Each library component must provide a `fwd.hpp` header providing forward - declartations for all types used in the user API. - -- Each library component must provide an `all.hpp` header that contains the - main page for the documentation and includes all headers for the user API. - -- Use `inline` for small functions (rule of thumb: 10 lines or less). - - -Breaking Statements -=================== - -- Break constructor initializers after the comma, use four spaces for - indentation, and place each initializer on its own line (unless you don't - need to break at all): - ```cpp - - my_class::my_class() - : my_base_class(some_function()), - m_greeting("Hello there! This is my_class!"), - m_some_bool_flag(false) { - // ok - } - other_class::other_class() : m_name("tommy"), m_buddy("michael") { - // ok - } - ``` - -- Break function arguments after the comma for both declaration and invocation: - ```cpp - - intptr_t channel::compare(const abstract_channel* lhs, - const abstract_channel* rhs) { - // ... - } - ``` - -- Break before tenary operators and before binary operators: - ```cpp - - if (today_is_a_sunny_day() - && it_is_not_too_hot_to_go_swimming()) { - // ... - } - ``` - - -Template Metaprogramming -======================== - -Despite its power, template metaprogramming came to the language pretty -much by accident. Templates were never meant to be used for compile-time -algorithms and type transformations. This is why C++ punishes metaprogramming -with an insane amount of syntax noise. In CAF, we make excessive use of -templates. To keep the code readable despite all the syntax noise, we have some -extra rules for formatting metaprogramming code. - -- Brake `using name = ...` statements always directly after `=` if it - does not fit in one line. - -- Consider the *semantics* of a metaprogramming function. For example, - `std::conditional` is an if-then-else construct. Hence, place the if-clause - on its own line and do the same for the two cases. - -- Use one level of indentation per "open" template and place the closing `>`, - `>::type` or `>::value` on its own line. For example: - ```cpp - - using optional_result_type = - typename std::conditional< - std::is_same::value, - bool, - optional - >::type; - // think of it as the following (not valid C++): - auto optional_result_type = - conditional { - if result_type == void - then bool - else optional - }; - ``` - -- Note that this is not necessary when simply defining a type alias. - When dealing with "ordinary" templates, indenting based on the position of - the opening `<` is ok, e.g.: - ```cpp - - using response_handle_type = response_handle; - ``` - - -Rvalue References -================= - -- Use rvalue references whenever it makes sense. - -- Write move constructors and assignment operators if possible. - - -Preprocessor Macros -=================== - -- Use macros if and only if you can't get the same result by using inline - functions or proper constants. - -- Macro names use the form `CAF__`. - - -General Git Rules -================= - -- The first line is a capitalized summary and has at most 50 characters. - -- The second line is left empty. - -- Optional long descriptions begin on the third line with a at most 72 - characters per line. - -- Write commit messages in the imperative: "Fix bug" and not "Fixes bug" - or "Fixed bug". - - -Git Branches and Work Flow -========================== - -- The `master` branch always reflects a *production-ready* state, i.e., - the latest release version. - -- The `develop` branch is the main branch. Every time it reaches a stable - point it is merged back to `master` for a new release. The `develop` branch - reflects the latest state of development and should always compile. - -- Simple bugfixes consisting of a single commit can be pushed to `develop`. - -- Fixes for critical issues can be pushed to the `master` (and `develop`) - branch after talking to the maintainer - (and then cause a new release immediately). - -- New features or non-trivial fixes are developed in a *topic branch* using - the naming convention `topic/short-description`. Topic branches are merged - off from `develop`. Finishing topic branches includes these steps: - + Create a *pull request* to `develop` on GitHub - + Wait for the results of Jenkins and fix any issues that might come up - + Squash your commits if necessary once Jenkins succeeds - + Ask the maintainer to review your changes if you have green light from - Jenkins and a clean Git history for your work - + The maintainer will merge the topic branch back into `develop` after the - review phase is done (and you once again have a clean Git history) diff -Nru actor-framework-0.13.2/Jenkinsfile actor-framework-0.16.3/Jenkinsfile --- actor-framework-0.13.2/Jenkinsfile 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/Jenkinsfile 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,302 @@ +#!/usr/bin/env groovy + +// Default CMake flags for most builds (except coverage). +defaultBuildFlags = [ + 'CAF_MORE_WARNINGS:BOOL=yes', + 'CAF_ENABLE_RUNTIME_CHECKS:BOOL=yes', + 'CAF_NO_OPENCL:BOOL=yes', +] + +// CMake flags for release builds. +releaseBuildFlags = defaultBuildFlags + [ +] + +// CMake flags for debug builds. +debugBuildFlags = defaultBuildFlags + [ + 'CAF_ENABLE_RUNTIME_CHECKS:BOOL=yes', + 'CAF_ENABLE_ADDRESS_SANITIZER:BOOL=yes', + 'CAF_LOG_LEVEL:STRING=TRACE', +] + +// CMake flags for macOS builds only. +macBuildFlags = [ + 'OPENSSL_ROOT_DIR=/usr/local/opt/openssl', + 'OPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include', +] + +// Our build matrix. The keys are the operating system labels and the values +// are lists of tool labels. +buildMatrix = [ + // Debug builds with ASAN + logging for various OS/compiler combinations. + ['Linux', [ + builds: ['debug'], + tools: ['gcc4.8', 'gcc4.9', 'gcc5', 'gcc6', 'gcc7', 'gcc8'], + cmakeArgs: debugBuildFlags, + ]], + ['macOS', [ + builds: ['debug'], + tools: ['clang'], + cmakeArgs: debugBuildFlags + macBuildFlags, + ]], + // One release build per supported OS. FreeBSD and Windows have the least + // testing outside Jenkins, so we also explicitly schedule debug builds. + ['Linux', [ + builds: ['release'], + tools: ['gcc8', 'clang'], + cmakeArgs: releaseBuildFlags, + ]], + ['macOS', [ + builds: ['release'], + tools: ['clang'], + cmakeArgs: releaseBuildFlags + macBuildFlags, + ]], + ['FreeBSD', [ + builds: ['debug'], // no release build for now, because it takes 1h + tools: ['clang'], + cmakeArgs: debugBuildFlags, + ]], + ['Windows', [ + builds: ['debug', 'release'], + tools: ['msvc'], + cmakeArgs: [ + 'CAF_BUILD_STATIC_ONLY:BOOL=yes', + 'CAF_ENABLE_RUNTIME_CHECKS:BOOL=yes', + 'CAF_NO_OPENCL:BOOL=yes', + ], + ]], + // One Additional build for coverage reports. + /* TODO: this build exhausts all storage on the node and is temporarily + * disabled until resolving the issue + ['Linux', [ + builds: ['debug'], + tools: ['gcc8 && gcovr'], + extraSteps: ['coverageReport'], + cmakeArgs: [ + 'CAF_ENABLE_GCOV:BOOL=yes', + 'CAF_NO_EXCEPTIONS:BOOL=yes', + 'CAF_FORCE_NO_EXCEPTIONS:BOOL=yes', + ], + ]], + */ +] + +// Optional environment variables for combinations of labels. +buildEnvironments = [ + 'macOS && gcc': ['CXX=g++'], + 'Linux && clang': ['CXX=clang++'], +] + +// Called *after* a build succeeded. +def coverageReport() { + dir('caf-sources') { + sh 'gcovr -e examples -e tools -e libcaf_test -e ".*/test/.*" -e libcaf_core/caf/scheduler/profiled_coordinator.hpp -x -r . > coverage.xml' + archiveArtifacts '**/coverage.xml' + cobertura([ + autoUpdateHealth: false, + autoUpdateStability: false, + coberturaReportFile: '**/coverage.xml', + conditionalCoverageTargets: '70, 0, 0', + failUnhealthy: false, + failUnstable: false, + lineCoverageTargets: '80, 0, 0', + maxNumberOfBuilds: 0, + methodCoverageTargets: '80, 0, 0', + onlyStable: false, + sourceEncoding: 'ASCII', + zoomCoverageChart: false, + ]) + } +} + +def cmakeSteps(buildType, cmakeArgs, buildId) { + def installDir = "$WORKSPACE/$buildId" + dir('caf-sources') { + // Configure and build. + cmakeBuild([ + buildDir: 'build', + buildType: buildType, + cmakeArgs: (cmakeArgs + [ + "CMAKE_INSTALL_PREFIX=\"$installDir\"", + ]).collect { x -> '-D' + x }.join(' '), + installation: 'cmake in search path', + sourceDir: '.', + steps: [[ + args: '--target install', + withCmake: true, + ]], + ]) + // Run unit tests. + ctest([ + arguments: '--output-on-failure', + installation: 'cmake in search path', + workingDir: 'build', + ]) + } + // Only generate artifacts for the master branch. + if (PrettyJobBaseName == 'master') { + zip([ + archive: true, + dir: buildId, + zipFile: "${buildId}.zip", + ]) + } +} + +// Builds `name` with CMake and runs the unit tests. +def buildSteps(buildType, cmakeArgs, buildId) { + echo "build stage: $STAGE_NAME" + deleteDir() + dir(buildId) { + // Create directory. + } + unstash('caf-sources') + if (STAGE_NAME.contains('Windows')) { + echo "Windows build on $NODE_NAME" + withEnv(['PATH=C:\\Windows\\System32;C:\\Program Files\\CMake\\bin;C:\\Program Files\\Git\\cmd;C:\\Program Files\\Git\\bin']) { + cmakeSteps(buildType, cmakeArgs, buildId) + } + } else { + echo "Unix build on $NODE_NAME" + withEnv(["label_exp=" + STAGE_NAME.toLowerCase(), + "ASAN_OPTIONS=detect_leaks=0"]) { + cmakeSteps(buildType, cmakeArgs, buildId) + } + } +} + +// Builds a stage for given builds. Results in a parallel stage `if builds.size() > 1`. +def makeBuildStages(matrixIndex, builds, lblExpr, settings) { + builds.collectEntries { buildType -> + def id = "$matrixIndex $lblExpr: $buildType" + [ + (id): + { + node(lblExpr) { + stage(id) { + try { + def buildId = "$lblExpr && $buildType" + withEnv(buildEnvironments[lblExpr] ?: []) { + buildSteps(buildType, settings['cmakeArgs'], buildId) + (settings['extraSteps'] ?: []).each { fun -> "$fun"() } + } + } finally { + cleanWs() + } + } + } + } + ] + } +} + +pipeline { + options { + buildDiscarder(logRotator(numToKeepStr: '50', artifactNumToKeepStr: '10')) + } + agent none + environment { + LD_LIBRARY_PATH = "$WORKSPACE/caf-sources/build/lib" + DYLD_LIBRARY_PATH = "$WORKSPACE/caf-sources/build/lib" + PrettyJobBaseName = env.JOB_BASE_NAME.replace('%2F', '/') + PrettyJobName = "CAF build #${env.BUILD_NUMBER} for $PrettyJobBaseName" + } + stages { + stage('Git Checkout') { + agent { label 'master' } + steps { + deleteDir() + dir('caf-sources') { + checkout scm + sh './scripts/get-release-version.sh' + } + stash includes: 'caf-sources/**', name: 'caf-sources' + } + } + stage('Builds') { + steps { + script { + // Create stages for building everything in our build matrix in + // parallel. + def xs = [:] + buildMatrix.eachWithIndex { entry, index -> + def (os, settings) = entry + settings['tools'].eachWithIndex { tool, toolIndex -> + def matrixIndex = "[$index:$toolIndex]" + def builds = settings['builds'] + def labelExpr = "$os && $tool" + xs << makeBuildStages(matrixIndex, builds, labelExpr, settings) + } + } + parallel xs + } + } + } + stage('Documentation') { + agent { label 'pandoc' } + steps { + deleteDir() + unstash('caf-sources') + dir('caf-sources') { + // Configure and build. + cmakeBuild([ + buildDir: 'build', + installation: 'cmake in search path', + sourceDir: '.', + cmakeArgs: '-DCAF_BUILD_TEX_MANUAL=yes', + steps: [[ + args: '--target doc', + withCmake: true, + ]], + ]) + sshagent(['84d71a75-cbb6-489a-8f4c-d0e2793201e9']) { + sh ''' + if [ "$(cat branch.txt)" = "master" ]; then + rsync -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" -r -z --delete build/doc/html/ www.inet.haw-hamburg.de:/users/www/www.actor-framework.org/html/doc + scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null build/doc/manual.pdf www.inet.haw-hamburg.de:/users/www/www.actor-framework.org/html/pdf/manual.pdf + fi + ''' + } + } + dir('read-the-docs') { + git([ + credentialsId: '9b054212-9bb4-41fd-ad8e-b7d47495303f', + url: 'git@github.com:actor-framework/read-the-docs.git', + ]) + sh ''' + if [ "$(cat ../caf-sources/branch.txt)" = "master" ]; then + cp ../caf-sources/build/doc/rst/* . + if [ -n "$(git status --porcelain)" ]; then + git add . + git commit -m "Update Manual" + git push --set-upstream origin master + if [ -z "$(grep 'exp.sha' ../caf-sources/release.txt)" ] ; then + git tag $(cat ../caf-sources/release.txt) + git push origin $(cat ../caf-sources/release.txt) + fi + fi + fi + ''' + } + } + } + } + post { + success { + emailext( + subject: "✅ $PrettyJobName succeeded", + recipientProviders: [culprits(), developers(), requestor(), upstreamDevelopers()], + body: "Check console output at ${env.BUILD_URL}.", + ) + } + failure { + emailext( + subject: "⛔️ $PrettyJobName failed", + attachLog: true, + compressLog: true, + recipientProviders: [culprits(), developers(), requestor(), upstreamDevelopers()], + body: "Check console output at ${env.BUILD_URL} or see attached log.\n", + ) + } + } +} + diff -Nru actor-framework-0.13.2/libcaf_core/caf/abstract_actor.hpp actor-framework-0.16.3/libcaf_core/caf/abstract_actor.hpp --- actor-framework-0.13.2/libcaf_core/caf/abstract_actor.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/abstract_actor.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_ABSTRACT_ACTOR_HPP -#define CAF_ABSTRACT_ACTOR_HPP +#pragma once #include #include @@ -27,9 +25,7 @@ #include #include #include -#include #include -#include #include "caf/fwd.hpp" #include "caf/node_id.hpp" @@ -37,286 +33,194 @@ #include "caf/message_id.hpp" #include "caf/exit_reason.hpp" #include "caf/intrusive_ptr.hpp" +#include "caf/execution_unit.hpp" +#include "caf/mailbox_element.hpp" #include "caf/abstract_channel.hpp" +#include "caf/detail/disposer.hpp" #include "caf/detail/type_traits.hpp" #include "caf/detail/functor_attachable.hpp" namespace caf { -/** - * A unique actor ID. - * @relates abstract_actor - */ -using actor_id = uint32_t; - -/** - * Denotes an ID that is never used by an actor. - */ -constexpr actor_id invalid_actor_id = 0; +/// A unique actor ID. +/// @relates abstract_actor +using actor_id = uint64_t; -using abstract_actor_ptr = intrusive_ptr; +/// Denotes an ID that is never used by an actor. +constexpr actor_id invalid_actor_id = 0; -/** - * Base class for all actor implementations. - */ +/// Base class for all actor implementations. class abstract_actor : public abstract_channel { - public: - /** - * Attaches `ptr` to this actor. The actor will call `ptr->detach(...)` on - * exit, or immediately if it already finished execution. - */ - 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. - */ - template - void attach_functor(F f) { - attach(attachable_ptr{new detail::functor_attachable(std::move(f))}); +public: + // allow placement new (only) + inline void* operator new(std::size_t, void* ptr) { + return ptr; } - /** - * Returns the logical actor address. - */ - actor_addr address() const; + actor_control_block* ctrl() const; - /** - * Detaches the first attached object that matches `what`. - */ - size_t detach(const attachable::token& what); - - /** - * Links this actor to `whom`. - */ - inline void link_to(const actor_addr& whom) { - link_impl(establish_link_op, whom); - } + ~abstract_actor() override; - /** - * Links this actor to `whom`. - */ - template - void link_to(const ActorHandle& whom) { - link_to(whom.address()); - } + /// Cleans up any remaining state before the destructor is called. + /// This function makes sure it is safe to call virtual functions + /// in sub classes before destroying the object, because calling + /// virtual function in the destructor itself is not safe. Any override + /// implementation is required to call `super::destroy()` at the end. + virtual void on_destroy(); - /** - * Unlinks this actor from `whom`. - */ - inline void unlink_from(const actor_addr& other) { - link_impl(remove_link_op, other); - } + void enqueue(strong_actor_ptr sender, message_id mid, + message msg, execution_unit* host) override; - /** - * Unlinks this actor from `whom`. - */ - template - void unlink_from(const ActorHandle& other) { - unlink_from(other.address()); - } + /// Enqueues a new message wrapped in a `mailbox_element` to the actor. + /// This `enqueue` variant allows to define forwarding chains. + virtual void enqueue(mailbox_element_ptr what, execution_unit* host) = 0; - /** - * Establishes a link relation between this actor and `other` - * and returns whether the operation succeeded. - */ - inline bool establish_backlink(const actor_addr& other) { - return link_impl(establish_backlink_op, other); - } + /// Attaches `ptr` to this actor. The actor will call `ptr->detach(...)` on + /// exit, or immediately if it already finished execution. + virtual void attach(attachable_ptr ptr) = 0; - /** - * Removes the link relation between this actor and `other` - * and returns whether the operation succeeded. - */ - inline bool remove_backlink(const actor_addr& other) { - return link_impl(remove_backlink_op, other); + /// Convenience function that attaches the functor `f` to this actor. The + /// actor executes `f()` on exit or immediatley if it is not running. + template + void attach_functor(F f) { + attach(attachable_ptr{new detail::functor_attachable(std::move(f))}); } - /** - * Returns the unique ID of this actor. - */ - inline uint32_t id() const { - return m_id; - } + /// Returns the logical actor address. + actor_addr address() const; - /** - * Returns the actor's exit reason or - * `exit_reason::not_exited` if it's still alive. - */ - inline uint32_t exit_reason() const { - return m_exit_reason; - } + /// Detaches the first attached object that matches `what`. + virtual size_t detach(const attachable::token& what) = 0; - /** - * Returns the set of accepted messages types as strings or - * an empty set if this actor is untyped. - */ + /// Returns the set of accepted messages types as strings or + /// an empty set if this actor is untyped. virtual std::set message_types() const; - /** - * Returns the execution unit currently used by this actor. - * @warning not thread safe - */ - inline execution_unit* host() const { - return m_host; - } + /// Returns the ID of this actor. + actor_id id() const noexcept; - /** - * Sets the execution unit for this actor. - */ - inline void host(execution_unit* new_host) { - m_host = new_host; - } + /// Returns the node this actor is living on. + node_id node() const noexcept; - protected: - /** - * Creates a non-proxy instance. - */ - abstract_actor(); - - /** - * Creates a proxy instance for a proxy running on `nid`. - */ - abstract_actor(actor_id aid, node_id nid); - - /** - * Called by the runtime system to perform cleanup actions for this actor. - * Subtypes should always call this member function when overriding it. - */ - void cleanup(uint32_t reason); - - /** - * Returns `exit_reason() != exit_reason::not_exited`. - */ - inline bool exited() const { - return exit_reason() != exit_reason::not_exited; - } + /// Returns the system that created this actor (or proxy). + actor_system& home_system() const noexcept; /**************************************************************************** * here be dragons: end of public interface * ****************************************************************************/ - public: - /** @cond PRIVATE */ + /// @cond PRIVATE - enum linking_operation { - establish_link_op, - establish_backlink_op, - remove_link_op, - remove_backlink_op - }; - - // used by ... - static constexpr int trap_exit_flag = 0x01; // local_actor - static constexpr int has_timeout_flag = 0x02; // single_timeout - static constexpr int is_registered_flag = 0x04; // (several actors) - static constexpr int is_initialized_flag = 0x08; // event-based actors - static constexpr int is_blocking_flag = 0x10; // blocking_actor - static constexpr int is_detached_flag = 0x20; // local_actor - static constexpr int is_priority_aware_flag = 0x40; // local_actor + template + void eq_impl(message_id mid, strong_actor_ptr sender, + execution_unit* ctx, Ts&&... xs) { + enqueue(make_mailbox_element(std::move(sender), mid, + {}, std::forward(xs)...), + ctx); + } + + // flags storing runtime information used by ... + static constexpr int has_timeout_flag = 0x0004; // single_timeout + static constexpr int is_registered_flag = 0x0008; // (several actors) + static constexpr int is_initialized_flag = 0x0010; // event-based actors + static constexpr int is_blocking_flag = 0x0020; // blocking_actor + static constexpr int is_detached_flag = 0x0040; // local_actor + static constexpr int is_serializable_flag = 0x0100; // local_actor + static constexpr int is_migrated_from_flag = 0x0200; // local_actor + static constexpr int has_used_aout_flag = 0x0400; // local_actor + static constexpr int is_terminated_flag = 0x0800; // local_actor + static constexpr int is_cleaned_up_flag = 0x1000; // monitorable_actor + static constexpr int is_shutting_down_flag = 0x2000; // scheduled_actor - inline void set_flag(bool enable_flag, int mask) { + inline void setf(int flag) { auto x = flags(); - flags(enable_flag ? x | mask : x & ~mask); - } - - inline bool get_flag(int mask) const { - return static_cast(flags() & mask); - } - - inline bool has_timeout() const { - return get_flag(has_timeout_flag); - } - - inline void has_timeout(bool value) { - set_flag(value, has_timeout_flag); + flags(x | flag); } - inline bool is_registered() const { - return get_flag(is_registered_flag); + inline void unsetf(int flag) { + auto x = flags(); + flags(x & ~flag); } - void is_registered(bool value); - - inline bool is_initialized() const { - return get_flag(is_initialized_flag); + inline bool getf(int flag) const { + return (flags() & flag) != 0; } - inline void is_initialized(bool value) { - set_flag(value, is_initialized_flag); - } + /// Sets `is_registered_flag` and calls `system().registry().inc_running()`. + void register_at_system(); - inline bool is_blocking() const { - return get_flag(is_blocking_flag); - } + /// Unsets `is_registered_flag` and calls `system().registry().dec_running()`. + void unregister_from_system(); - inline void is_blocking(bool value) { - set_flag(value, is_blocking_flag); - } + /// Causes the actor to establish a link to `other`. + virtual void add_link(abstract_actor* other) = 0; - inline bool is_detached() const { - return get_flag(is_detached_flag); - } + /// Causes the actor to remove any established link to `other`. + virtual void remove_link(abstract_actor* other) = 0; - inline void is_detached(bool value) { - set_flag(value, is_detached_flag); - } + /// Adds an entry to `other` to the link table of this actor. + /// @warning Must be called inside a critical section, i.e., + /// while holding `mtx_`. + virtual bool add_backlink(abstract_actor* other) = 0; - inline bool is_priority_aware() const { - return get_flag(is_priority_aware_flag); - } + /// Removes an entry to `other` from the link table of this actor. + /// @warning Must be called inside a critical section, i.e., + /// while holding `mtx_`. + virtual bool remove_backlink(abstract_actor* other) = 0; - inline void is_priority_aware(bool value) { - set_flag(value, is_priority_aware_flag); + /// Calls `fun` with exclusive access to an actor's state. + template + auto exclusive_critical_section(F fun) -> decltype(fun()) { + std::unique_lock guard{mtx_}; + return fun(); } - // Tries to run a custom exception handler for `eptr`. - optional handle(const std::exception_ptr& eptr); - - protected: - virtual bool link_impl(linking_operation op, const actor_addr& other); - - bool establish_link_impl(const actor_addr& other); - - bool remove_link_impl(const actor_addr& other); - - bool establish_backlink_impl(const actor_addr& other); - - bool remove_backlink_impl(const actor_addr& other); - - inline void attach_impl(attachable_ptr& ptr) { - ptr->next.swap(m_attachables_head); - m_attachables_head.swap(ptr); + /// Calls `fun` with readonly access to an actor's state. + template + auto shared_critical_section(F fun) -> decltype(fun()) { + std::unique_lock guard{mtx_}; + return fun(); } - static size_t detach_impl(const attachable::token& what, - attachable_ptr& ptr, - bool stop_on_first_hit = false, - bool dry_run = false); - - // cannot be changed after construction - const actor_id m_id; - - // initially set to exit_reason::not_exited - std::atomic m_exit_reason; - - // guards access to m_exit_reason, m_attachables, m_links, - // and enqueue operations if actor is thread-mapped - mutable std::mutex m_mtx; - - // only used in blocking and thread-mapped actors - mutable std::condition_variable m_cv; - - // attached functors that are executed on cleanup (monitors, links, etc) - attachable_ptr m_attachables_head; - - // identifies the execution unit this actor is currently executed by - execution_unit* m_host; - - /** @endcond */ + /// Calls `fun` with exclusive access to the state of both `p1` and `p2`. This + /// function guarantees that the order of acquiring the locks is always + /// identical, independently from the order of `p1` and `p2`. + template + static auto joined_exclusive_critical_section(abstract_actor* p1, + abstract_actor* p2, + F fun) + -> decltype(fun()) { + // Make sure to allocate locks always in the same order by starting on the + // actor with the lowest address. + CAF_ASSERT(p1 != p2 && p1 != nullptr && p2 != nullptr); + if (p1 < p2) { + std::unique_lock guard1{p1->mtx_}; + std::unique_lock guard2{p2->mtx_}; + return fun(); + } + std::unique_lock guard1{p2->mtx_}; + std::unique_lock guard2{p1->mtx_}; + return fun(); + } + + /// @endcond + +protected: + /// Creates a new actor instance. + explicit abstract_actor(actor_config& cfg); + + // Guards potentially concurrent access to the state. For example, + // `exit_state_`, `attachables_`, and `links_` in a `monitorable_actor`. + mutable std::mutex mtx_; + +private: + // prohibit copies, assigments, and heap allocations + void* operator new(size_t); + void* operator new[](size_t); + abstract_actor(const abstract_actor&) = delete; + abstract_actor& operator=(const abstract_actor&) = delete; }; } // namespace caf -#endif // CAF_ABSTRACT_ACTOR_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/abstract_channel.hpp actor-framework-0.16.3/libcaf_core/caf/abstract_channel.hpp --- actor-framework-0.13.2/libcaf_core/caf/abstract_channel.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/abstract_channel.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,60 +16,40 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_ABSTRACT_CHANNEL_HPP -#define CAF_ABSTRACT_CHANNEL_HPP +#pragma once #include #include "caf/fwd.hpp" -#include "caf/node_id.hpp" #include "caf/message_id.hpp" -#include "caf/ref_counted.hpp" namespace caf { -/** - * Interface for all message receivers. * This interface describes an - * entity that can receive messages and is implemented by {@link actor} - * and {@link group}. - */ -class abstract_channel : public ref_counted { - public: +/// Interface for all message receivers. * This interface describes an +/// entity that can receive messages and is implemented by {@link actor} +/// and {@link group}. +class abstract_channel { +public: friend class abstract_actor; friend class abstract_group; virtual ~abstract_channel(); - /** - * Enqueues a new message to the channel. - */ - virtual void enqueue(const actor_addr& sender, message_id mid, - message content, execution_unit* host) = 0; - - /** - * Enqueues a new message wrapped in a `mailbox_element` to the channel. - * This variant is used by actors whenever it is possible to allocate - * mailbox element and message on the same memory block and is thus - * more efficient. Non-actors use the default implementation which simply - * calls the pure virtual version. - */ - virtual void enqueue(mailbox_element_ptr what, execution_unit* host); - - /** - * Returns the ID of the node this actor is running on. - */ - inline node_id node() const { - return m_node; - } + /// Enqueues a new message without forwarding stack to the channel. + virtual void enqueue(strong_actor_ptr sender, message_id mid, message content, + execution_unit* host = nullptr) = 0; + + static constexpr int is_abstract_actor_flag = 0x01000000; + + static constexpr int is_abstract_group_flag = 0x02000000; + + static constexpr int is_actor_bind_decorator_flag = 0x04000000; - /** - * Returns true if {@link node_ptr} returns - */ - bool is_remote() const; + static constexpr int is_actor_dot_decorator_flag = 0x08000000; - static constexpr int is_abstract_actor_flag = 0x100000; + static constexpr int is_actor_decorator_mask = 0x0C000000; - static constexpr int is_abstract_group_flag = 0x200000; + static constexpr int is_hidden_flag = 0x10000000; inline bool is_abstract_actor() const { return static_cast(flags() & is_abstract_actor_flag); @@ -80,7 +59,11 @@ return static_cast(flags() & is_abstract_group_flag); } - protected: + inline bool is_actor_decorator() const { + return static_cast(flags() & is_actor_decorator_mask); + } + +protected: // note: *both* operations use relaxed memory order, this is because // only the actor itself is granted write access while all access // from other actors or threads is always read-only; further, only @@ -88,34 +71,22 @@ // read by others, i.e., there is no acquire/release semantic between // setting and reading flags inline int flags() const { - return m_flags.load(std::memory_order_relaxed); + return flags_.load(std::memory_order_relaxed); } inline void flags(int new_value) { - m_flags.store(new_value, std::memory_order_relaxed); + flags_.store(new_value, std::memory_order_relaxed); } private: // can only be called from abstract_actor and abstract_group - abstract_channel(int init_flags); - abstract_channel(int init_flags, node_id nid); + abstract_channel(int fs); - /* - * Accumulates several state and type flags. Subtypes may use only the - * first 20 bits, i.e., the bitmask 0xFFF00000 is reserved for - * channel-related flags. - */ - std::atomic m_flags; - // identifies the node of this channel - node_id m_node; + // Accumulates several state and type flags. Subtypes may use only the + // first 20 bits, i.e., the bitmask 0xFFF00000 is reserved for + // channel-related flags. + std::atomic flags_; }; -/** - * A smart pointer to an abstract channel. - * @relates abstract_channel_ptr - */ -using abstract_channel_ptr = intrusive_ptr; - } // namespace caf -#endif // CAF_ABSTRACT_CHANNEL_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/abstract_composable_behavior.hpp actor-framework-0.16.3/libcaf_core/caf/abstract_composable_behavior.hpp --- actor-framework-0.13.2/libcaf_core/caf/abstract_composable_behavior.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/abstract_composable_behavior.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,36 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/fwd.hpp" + +namespace caf { + +/// Marker type that allows CAF to spawn actors from composable states. +class abstract_composable_behavior { +public: + virtual ~abstract_composable_behavior(); + + virtual void init_behavior(message_handler& x) = 0; +}; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/abstract_event_based_actor.hpp actor-framework-0.16.3/libcaf_core/caf/abstract_event_based_actor.hpp --- actor-framework-0.13.2/libcaf_core/caf/abstract_event_based_actor.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/abstract_event_based_actor.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_ABSTRACT_EVENT_BASED_ACTOR_HPP -#define CAF_ABSTRACT_EVENT_BASED_ACTOR_HPP - -#include - -#include "caf/message_id.hpp" -#include "caf/local_actor.hpp" -#include "caf/typed_behavior.hpp" -#include "caf/behavior_policy.hpp" -#include "caf/response_handle.hpp" - -#include "caf/mixin/sync_sender.hpp" - -namespace caf { - -/* - * Base type for typed and untyped event-based actors. - * @tparam BehaviorType Denotes the expected type for become(). - * @tparam HasSyncSend Configures whether this base class extends `sync_sender`. - * @extends local_actor - */ -template -class abstract_event_based_actor : public - std::conditional< - HasSyncSend, - extend - ::with::template impl>, - local_actor - >::type { - public: - using behavior_type = BehaviorType; - - /**************************************************************************** - * become() member function family * - ****************************************************************************/ - - void become(behavior_type bhvr) { - this->do_become(std::move(unbox(bhvr)), true); - } - - void become(const keep_behavior_t&, behavior_type bhvr) { - this->do_become(std::move(unbox(bhvr)), false); - } - - template - typename std::enable_if< - !std::is_same::type>::value, - void - >::type - become(T&& x, Ts&&... xs) { - behavior_type bhvr{std::forward(x), std::forward(xs)...}; - this->do_become(std::move(unbox(bhvr)), true); - } - - template - void become(const keep_behavior_t&, Ts&&... xs) { - behavior_type bhvr{std::forward(xs)...}; - this->do_become(std::move(unbox(bhvr)), false); - } - - void unbecome() { - this->m_bhvr_stack.pop_back(); - } - - private: - template - static behavior& unbox(typed_behavior& x) { - return x.unbox(); - } - - static inline behavior& unbox(behavior& x) { - return x; - } -}; - -} // namespace caf - -#endif // CAF_ABSTRACT_EVENT_BASED_ACTOR_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/abstract_group.hpp actor-framework-0.16.3/libcaf_core/caf/abstract_group.hpp --- actor-framework-0.13.2/libcaf_core/caf/abstract_group.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/abstract_group.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,162 +16,77 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_ABSTRACT_GROUP_HPP -#define CAF_ABSTRACT_GROUP_HPP +#pragma once #include #include +#include "caf/fwd.hpp" #include "caf/actor_addr.hpp" #include "caf/attachable.hpp" #include "caf/ref_counted.hpp" #include "caf/abstract_channel.hpp" namespace caf { -namespace detail { -class group_manager; -class peer_connection; +/// A multicast group. +class abstract_group : public ref_counted, public abstract_channel { +public: + // -- member types ----------------------------------------------------------- -} // namespace detail -} // namespace caf + friend class local_actor; + friend class subscription; + friend class detail::group_manager; -namespace caf { + // -- constructors, destructors, and assignment operators -------------------- -class group; -class serializer; -class local_actor; -class deserializer; - -/** - * A multicast group. - */ -class abstract_group : public abstract_channel { - public: - friend class detail::group_manager; - friend class detail::peer_connection; - friend class local_actor; + ~abstract_group() override; - ~abstract_group(); + // -- pure virtual member functions ------------------------------------------ - class subscription; + /// Serialize this group to `sink`. + virtual error save(serializer& sink) const = 0; - struct subscription_token { - intrusive_ptr group; - static constexpr size_t token_type = attachable::token::subscription; - }; - - class subscription_predicate { - public: - inline subscription_predicate(intrusive_ptr group) - : m_group(std::move(group)) { - // nop - } - inline bool operator()(const attachable_ptr& ptr) { - return ptr->matches(subscription_token{m_group}); - } - private: - intrusive_ptr m_group; - }; + /// Subscribes `who` to this group and returns `true` on success + /// or `false` if `who` is already subscribed. + virtual bool subscribe(strong_actor_ptr who) = 0; - // needs access to unsubscribe() - friend class subscription; + /// Unsubscribes `who` from this group. + virtual void unsubscribe(const actor_control_block* who) = 0; - // unsubscribes its channel from the group on destruction - class subscription : public attachable { - public: - subscription(const intrusive_ptr& g); - - void actor_exited(abstract_actor* self, uint32_t reason) override; - - bool matches(const token& what) override; - - static inline attachable_ptr make(intrusive_ptr ptr) { - return attachable_ptr{new subscription(std::move(ptr))}; - } - - const intrusive_ptr& group() const { - return m_group; - } - - private: - intrusive_ptr m_group; - }; - - /** - * Interface for user-defined multicast implementations. - */ - class module { - public: - module(std::string module_name); - - virtual ~module(); - - /** - * Stops all groups from this module. - */ - virtual void stop() = 0; - - /** - * Returns the name of this module implementation. - * @threadsafe - */ - const std::string& name(); - - /** - * Returns a pointer to the group associated with the name `group_name`. - * @threadsafe - */ - virtual group get(const std::string& group_name) = 0; - - virtual group deserialize(deserializer* source) = 0; - - private: - std::string m_name; - }; - - using module_ptr = module*; - using unique_module_ptr = std::unique_ptr; - - virtual void serialize(serializer* sink) = 0; - - /** - * Returns a string representation of the group identifier, e.g., - * "224.0.0.1" for IPv4 multicast or a user-defined string for local groups. - */ - const std::string& identifier() const; - - module_ptr get_module() const; - - /** - * Returns the name of the module. - */ - const std::string& module_name() const; - - /** - * Subscribes `who` to this group and returns a subscription object. - */ - virtual attachable_ptr subscribe(const actor_addr& who) = 0; - - /** - * Stops any background actors or threads and IO handles. - */ + /// Stops any background actors or threads and IO handles. virtual void stop() = 0; - protected: - abstract_group(module_ptr module, std::string group_id); - // called by subscription objects - virtual void unsubscribe(const actor_addr& who) = 0; - module_ptr m_module; - std::string m_identifier; + // -- observers -------------------------------------------------------------- + + /// Returns the parent module. + inline group_module& module() const { + return parent_; + } + + /// Returns the hosting system. + inline actor_system& system() const { + return system_; + } + + /// Returns a string representation of the group identifier, e.g., + /// "224.0.0.1" for IPv4 multicast or a user-defined string for local groups. + const std::string& identifier() const { + return identifier_; + } + +protected: + abstract_group(group_module& mod, std::string id, node_id nid); + + actor_system& system_; + group_module& parent_; + std::string identifier_; + node_id origin_; }; -/** - * A smart pointer type that manages instances of {@link group}. - * @relates group - */ +/// A smart pointer type that manages instances of {@link group}. +/// @relates group using abstract_group_ptr = intrusive_ptr; } // namespace caf -#endif // CAF_ABSTRACT_GROUP_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_addr.hpp actor-framework-0.16.3/libcaf_core/caf/actor_addr.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_addr.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_addr.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,100 +16,149 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_ACTOR_ADDR_HPP -#define CAF_ACTOR_ADDR_HPP +#pragma once #include #include #include #include -#include "caf/intrusive_ptr.hpp" - #include "caf/fwd.hpp" #include "caf/abstract_actor.hpp" +#include "caf/actor_control_block.hpp" +#include "caf/unsafe_actor_handle_init.hpp" #include "caf/detail/comparable.hpp" namespace caf { -struct invalid_actor_addr_t { - constexpr invalid_actor_addr_t() {} - -}; - -/** - * Identifies an invalid {@link actor_addr}. - * @relates actor_addr - */ -constexpr invalid_actor_addr_t invalid_actor_addr = invalid_actor_addr_t{}; - -/** - * Stores the address of typed as well as untyped actors. - */ +/// Stores the address of typed as well as untyped actors. class actor_addr : detail::comparable, - detail::comparable, - detail::comparable { + detail::comparable, + detail::comparable, + detail::comparable, + detail::comparable { +public: + // -- friend types that need access to private ctors - friend class actor; friend class abstract_actor; - template - friend T actor_cast(const U&); + // allow conversion via actor_cast + template + friend class actor_cast_access; - public: + // tell actor_cast which semantic this type uses + static constexpr bool has_weak_ptr_semantics = true; actor_addr() = default; - actor_addr(actor_addr&&) = default; - actor_addr(const actor_addr&) = default; - actor_addr& operator=(actor_addr&&) = default; - actor_addr& operator=(const actor_addr&) = default; - actor_addr(const invalid_actor_addr_t&); + actor_addr(std::nullptr_t); + actor_addr(const unsafe_actor_handle_init_t&); + + actor_addr& operator=(std::nullptr_t); + + /// Returns the ID of this actor. + inline actor_id id() const noexcept { + return ptr_->id(); + } + + /// Returns the origin node of this actor. + inline node_id node() const noexcept { + return ptr_->node(); + } + + /// Returns the hosting actor system. + inline actor_system& home_system() const noexcept { + return *ptr_->home_system; + } + + /// Exchange content of `*this` and `other`. + void swap(actor_addr& other) noexcept; - actor_addr operator=(const invalid_actor_addr_t&); + inline explicit operator bool() const { + return static_cast(ptr_); + } + + /// @cond PRIVATE - inline explicit operator bool() const { return static_cast(m_ptr); } + static intptr_t compare(const actor_control_block* lhs, + const actor_control_block* rhs); - inline bool operator!() const { return !m_ptr; } + intptr_t compare(const actor_addr& other) const noexcept; - intptr_t compare(const actor_addr& other) const; + intptr_t compare(const abstract_actor* other) const noexcept; - intptr_t compare(const abstract_actor* other) const; + intptr_t compare(const actor_control_block* other) const noexcept; + + inline intptr_t compare(const weak_actor_ptr& other) const noexcept { + return compare(other.get()); + } - inline intptr_t compare(const abstract_actor_ptr& other) const { + inline intptr_t compare(const strong_actor_ptr& other) const noexcept { return compare(other.get()); } - actor_id id() const; + friend inline std::string to_string(const actor_addr& x) { + return to_string(x.ptr_); + } + + friend inline void append_to_string(std::string& x, const actor_addr& y) { + return append_to_string(x, y.ptr_); + } + + template + friend typename Inspector::result_type inspect(Inspector& f, actor_addr& x) { + return inspect(f, x.ptr_); + } - node_id node() const; + /// Releases the reference held by handle `x`. Using the + /// handle after invalidating it is undefined behavior. + friend void destroy(actor_addr& x) { + x.ptr_.reset(); + } - /** - * Returns whether this is an address of a remote actor. - */ - bool is_remote() const; + actor_addr(actor_control_block*, bool); - /** - * Returns the set of accepted messages types as strings or - * an empty set if this actor is untyped. - */ - std::set message_types() const; + inline actor_control_block* get() const noexcept { + return ptr_.get(); + } - private: + /// @endcond - inline abstract_actor* get() const { return m_ptr.get(); } +private: + inline actor_control_block* release() noexcept { + return ptr_.release(); + } - explicit actor_addr(abstract_actor*); + inline actor_control_block* get_locked() const noexcept { + return ptr_.get_locked(); + } - abstract_actor_ptr m_ptr; + actor_addr(actor_control_block*); + weak_actor_ptr ptr_; }; +inline bool operator==(const actor_addr& x, std::nullptr_t) { + return x.get() == nullptr; +} + +inline bool operator==(std::nullptr_t, const actor_addr& x) { + return x.get() == nullptr; +} + +inline bool operator!=(const actor_addr& x, std::nullptr_t) { + return x.get() != nullptr; +} + +inline bool operator!=(std::nullptr_t, const actor_addr& x) { + return x.get() != nullptr; +} + } // namespace caf // allow actor_addr to be used in hash maps @@ -120,8 +168,6 @@ inline size_t operator()(const caf::actor_addr& ref) const { return static_cast(ref.id()); } - }; } // namespace std -#endif // CAF_ACTOR_ADDR_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_cast.hpp actor-framework-0.16.3/libcaf_core/caf/actor_cast.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_cast.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_cast.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,19 +16,166 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_ACTOR_CAST_HPP -#define CAF_ACTOR_CAST_HPP +#pragma once + +#include + +#include "caf/fwd.hpp" +#include "caf/abstract_actor.hpp" +#include "caf/actor_control_block.hpp" namespace caf { -/** - * Converts actor handle `what` to a different actor handle of type `T`. - */ -template -T actor_cast(const U& what) { - return what.get(); +namespace { + +// The function actor_cast<> computes the type of the cast for +// actor_cast_access via the following formula: +// x = 0 if To is a raw pointer +// = 1 if To is a strong pointer +// = 2 if To is a weak pointer +// y = 0 if From is a raw pointer +// = 6 if From is a strong pointer +// = 2 if From is a weak pointer +// the result of x * y + z then denotes which operation the cast is performing: +// raw <- raw = 0 +// raw <- weak = 0 +// raw <- strong = 0 +// weak <- raw = 0 +// weak <- weak = 6 +// weak <- strong = 12 +// strong <- raw = 0 +// strong <- weak = 3 +// strong <- strong = 6 +// x * y is then interpreted as follows: +// - 0 is a conversion to or from a raw pointer +// - 6 is a conversion between pointers with same semantics +// - 3 is a conversion from a weak pointer to a strong pointer +// - 12 is a conversion from a strong pointer to a weak pointer + +constexpr int raw_ptr_cast = 0; // either To or From is a raw pointer +constexpr int weak_ptr_downgrade_cast = 12; // To is weak, From is strong +constexpr int weak_ptr_upgrade_cast = 3; // To is strong, From is weak +constexpr int neutral_cast = 6; // To and From are both weak or both strong + +template +struct is_weak_ptr { + static constexpr bool value = T::has_weak_ptr_semantics; +}; + +template +struct is_weak_ptr : std::false_type {}; + +template +struct is_weak_ptr> : std::false_type {}; + +} // namespace + +template +class actor_cast_access; + +template +class actor_cast_access { +public: + To operator()(actor_control_block* x) const { + return x; + } + + To operator()(abstract_actor* x) const { + return x->ctrl(); + } + + template ::value>::type> + To operator()(const T& x) const { + return x.get(); + } +}; + +template +class actor_cast_access { +public: + To* operator()(actor_control_block* x) const { + return static_cast(x->get()); + } + + To* operator()(abstract_actor* x) const { + return static_cast(x); + } + + template ::value>::type> + To* operator()(const T& x) const { + return (*this)(x.get()); + } +}; + +template +class actor_cast_access { +public: + actor_control_block* operator()(actor_control_block* x) const { + return x; + } + + actor_control_block* operator()(abstract_actor* x) const { + return x->ctrl(); + } + + template ::value>::type> + actor_control_block* operator()(const T& x) const { + return x.get(); + } +}; + +template +class actor_cast_access { +public: + To operator()(const From& x) const { + return x.get(); + } +}; + +template +class actor_cast_access { +public: + To operator()(const From& x) const { + return {x.get_locked(), false}; + } +}; + +template +class actor_cast_access { +public: + To operator()(const From& x) const { + return x.get(); + } + + To operator()(From&& x) const { + return {x.release(), false}; + } +}; + +/// Converts actor handle `what` to a different actor +/// handle or raw pointer of type `T`. +template +T actor_cast(U&& what) { + using from_type = + typename std::remove_const< + typename std::remove_reference::type + >::type; + // query traits for T + constexpr bool to_raw = std::is_pointer::value; + constexpr bool to_weak = is_weak_ptr::value; + // query traits for U + constexpr bool from_raw = std::is_pointer::value; + constexpr bool from_weak = is_weak_ptr::value; + // calculate x and y + constexpr int x = to_raw ? 0 : (to_weak ? 2 : 1); + constexpr int y = from_raw ? 0 : (from_weak ? 3 : 6); + // perform cast + actor_cast_access f; + return f(std::forward(what)); } } // namespace caf -#endif // CAF_ACTOR_CAST_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_clock.hpp actor-framework-0.16.3/libcaf_core/caf/actor_clock.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_clock.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_clock.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,92 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/fwd.hpp" + +namespace caf { + +/// A monotonic clock for scheduling timeouts and delayed messages. +class actor_clock { +public: + // -- member types ----------------------------------------------------------- + + /// Underlying clock type. + using clock_type = std::chrono::steady_clock; + + /// Discrete point in time. + using time_point = typename clock_type::time_point; + + /// Difference between two points in time. + using duration_type = typename clock_type::duration; + + // -- constructors, destructors, and assignment operators -------------------- + + virtual ~actor_clock(); + + // -- observers -------------------------------------------------------------- + + /// Returns the current wall-clock time. + virtual time_point now() const noexcept; + + /// Returns the difference between `t0` and `t1`, allowing the clock to + /// return an arbitrary value depending on the measurement that took place + /// and the units measured. + virtual duration_type difference(atom_value measurement, long units, + time_point t0, time_point t1) const noexcept; + + /// Schedules a `timeout_msg` for `self` at time point `t`, overriding any + /// previous receive timeout. + virtual void set_ordinary_timeout(time_point t, abstract_actor* self, + atom_value type, uint64_t id) = 0; + + /// Schedules a `timeout_msg` for `self` at time point `t`. + virtual void set_multi_timeout(time_point t, abstract_actor* self, + atom_value type, uint64_t id) = 0; + + /// Schedules a `sec::request_timeout` for `self` at time point `t`. + virtual void set_request_timeout(time_point t, abstract_actor* self, + message_id id) = 0; + + /// Cancels a pending receive timeout. + virtual void cancel_ordinary_timeout(abstract_actor* self, + atom_value type) = 0; + + /// Cancels the pending request timeout for `id`. + virtual void cancel_request_timeout(abstract_actor* self, message_id id) = 0; + + /// Cancels all timeouts for `self`. + virtual void cancel_timeouts(abstract_actor* self) = 0; + + /// Schedules an arbitrary message to `receiver` for time point `t`. + virtual void schedule_message(time_point t, strong_actor_ptr receiver, + mailbox_element_ptr content) = 0; + + /// Schedules an arbitrary message to `target` for time point `t`. + virtual void schedule_message(time_point t, group target, + strong_actor_ptr sender, message content) = 0; + + /// Cancels all timeouts and scheduled messages. + virtual void cancel_all() = 0; +}; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_companion.hpp actor-framework-0.16.3/libcaf_core/caf/actor_companion.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_companion.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_companion.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,68 +16,97 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_ACTOR_COMPANION_HPP -#define CAF_ACTOR_COMPANION_HPP +#pragma once #include #include -#include "caf/local_actor.hpp" +#include "caf/fwd.hpp" +#include "caf/extend.hpp" +#include "caf/scheduled_actor.hpp" #include "caf/mailbox_element.hpp" -#include "caf/abstract_event_based_actor.hpp" -#include "caf/mixin/sync_sender.hpp" +#include "caf/mixin/sender.hpp" +#include "caf/mixin/subscriber.hpp" +#include "caf/mixin/behavior_changer.hpp" #include "caf/detail/disposer.hpp" #include "caf/detail/shared_spinlock.hpp" namespace caf { -/** - * An co-existing forwarding all messages through a user-defined - * callback to another object, thus serving as gateway to - * allow any object to interact with other actors. - * @extends local_actor - */ -class actor_companion : public abstract_event_based_actor { - public: +template <> +class behavior_type_of { +public: + using type = behavior; +}; + +/// An co-existing actor forwarding all messages through a user-defined +/// callback to another object, thus serving as gateway to +/// allow any object to interact with other actors. +/// @extends local_actor +class actor_companion : public extend:: + with { +public: + // -- member types ----------------------------------------------------------- + + /// Required by `spawn` for type deduction. + using signatures = none_t; + + /// Required by `spawn` for type deduction. + using behavior_type = behavior; + + /// A shared lockable. using lock_type = detail::shared_spinlock; - using message_pointer = std::unique_ptr; - using enqueue_handler = std::function; - /** - * Removes the handler for incoming messages and terminates - * the companion for exit reason @ rsn. - */ - void disconnect(std::uint32_t rsn = exit_reason::normal); - - /** - * Sets the handler for incoming messages. - * @warning `handler` needs to be thread-safe - */ - void on_enqueue(enqueue_handler handler); + /// Delegates incoming messages to user-defined event loop. + using enqueue_handler = std::function; + + /// Callback for actor termination. + using on_exit_handler = std::function; + + // -- constructors, destructors ---------------------------------------------- + + actor_companion(actor_config& cfg); + + ~actor_companion() override; - void enqueue(mailbox_element_ptr what, execution_unit* host) override; + // -- overridden functions --------------------------------------------------- - void enqueue(const actor_addr& sender, message_id mid, - message content, execution_unit* host) override; + void enqueue(mailbox_element_ptr ptr, execution_unit* host) override; - void initialize(); + void enqueue(strong_actor_ptr src, message_id mid, message content, + execution_unit* eu) override; - private: + void launch(execution_unit* eu, bool lazy, bool hide) override; + + void on_exit() override; + + // -- modifiers -------------------------------------------------------------- + + /// Removes the handler for incoming messages and terminates + /// the companion for exit reason `rsn`. + void disconnect(exit_reason rsn = exit_reason::normal); + + /// Sets the handler for incoming messages. + /// @warning `handler` needs to be thread-safe + void on_enqueue(enqueue_handler handler); + + /// Sets the handler for incoming messages. + void on_exit(on_exit_handler handler); + +private: // set by parent to define custom enqueue action - enqueue_handler m_on_enqueue; + enqueue_handler on_enqueue_; - // guards access to m_handler - lock_type m_lock; -}; + // custom code for on_exit() + on_exit_handler on_exit_; -/** - * A pointer to a co-existing (actor) object. - * @relates actor_companion - */ -using actor_companion_ptr = intrusive_ptr; + // guards access to handler_ + lock_type lock_; +}; } // namespace caf -#endif // CAF_ACTOR_COMPANION_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_config.hpp actor-framework-0.16.3/libcaf_core/caf/actor_config.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_config.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_config.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,51 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include + +#include "caf/fwd.hpp" +#include "caf/behavior.hpp" +#include "caf/input_range.hpp" +#include "caf/abstract_channel.hpp" + +namespace caf { + +/// Stores spawn-time flags and groups. +class actor_config { +public: + execution_unit* host; + int flags; + input_range* groups; + std::function init_fun; + + explicit actor_config(execution_unit* ptr = nullptr); + + inline actor_config& add_flag(int x) { + flags |= x; + return *this; + } +}; + +/// @relates actor_config +std::string to_string(const actor_config& x); + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_control_block.hpp actor-framework-0.16.3/libcaf_core/caf/actor_control_block.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_control_block.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_control_block.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,252 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/fwd.hpp" +#include "caf/error.hpp" +#include "caf/node_id.hpp" +#include "caf/intrusive_ptr.hpp" +#include "caf/weak_intrusive_ptr.hpp" + +#include "caf/meta/type_name.hpp" +#include "caf/meta/save_callback.hpp" +#include "caf/meta/load_callback.hpp" +#include "caf/meta/omittable_if_none.hpp" + +namespace caf { + +/// Actors are always allocated with a control block that stores its identity +/// as well as strong and weak reference counts to it. Unlike +/// "common" weak pointer designs, the goal is not to allocate the data +/// separately. Instead, the only goal is to break cycles. For +/// example, linking two actors automatically creates a cycle when using +/// strong reference counts only. +/// +/// When allocating a new actor, CAF will always embed the user-defined +/// actor in an `actor_storage` with the control block prefixing the +/// actual actor type, as shown below. +/// +/// +----------------------------------------+ +/// | actor_storage | +/// +----------------------------------------+ +/// | +-----------------+------------------+ | +/// | | control block | actor data (T) | | +/// | +-----------------+------------------+ | +/// | | ref count | mailbox | | +/// | | weak ref count | . | | +/// | | actor ID | . | | +/// | | node ID | . | | +/// | +-----------------+------------------+ | +/// +----------------------------------------+ +/// +/// Actors start with a strong reference count of 1. This count is transferred +/// to the first `actor` or `typed_actor` handle used to store the actor. +/// Actors will also start with a weak reference count of 1. This count +/// is decremenated once the strong reference count drops to 0. +/// +/// The data block is destructed by calling the destructor of `T` when the +/// last strong reference expires. The storage itself is destroyed when +/// the last weak reference expires. +class actor_control_block { +public: + using data_destructor = void (*)(abstract_actor*); + using block_destructor = void (*)(actor_control_block*); + + actor_control_block(actor_id x, node_id& y, actor_system* sys, + data_destructor ddtor, block_destructor bdtor) + : strong_refs(1), + weak_refs(1), + aid(x), + nid(std::move(y)), + home_system(sys), + data_dtor(ddtor), + block_dtor(bdtor) { + // nop + } + + actor_control_block(const actor_control_block&) = delete; + actor_control_block& operator=(const actor_control_block&) = delete; + + std::atomic strong_refs; + std::atomic weak_refs; + const actor_id aid; + const node_id nid; + actor_system* const home_system; + const data_destructor data_dtor; + const block_destructor block_dtor; + + static_assert(sizeof(std::atomic) == sizeof(void*), + "std::atomic not lockfree on this platform"); + + static_assert(sizeof(intrusive_ptr) == sizeof(void*), + "intrusive_ptr and T* have different size"); + + static_assert(sizeof(node_id) == sizeof(void*), + "sizeof(node_id) != sizeof(size_t)"); + + static_assert(sizeof(data_destructor) == sizeof(void*), + "functiion pointer and regular pointers have different size"); + + /// Returns a pointer to the actual actor instance. + inline abstract_actor* get() { + // this pointer arithmetic is compile-time checked in actor_storage's ctor + return reinterpret_cast( + reinterpret_cast(this) + CAF_CACHE_LINE_SIZE); + } + + /// Returns a pointer to the control block that stores + /// identity and reference counts for this actor. + static actor_control_block* from(const abstract_actor* ptr) { + // this pointer arithmetic is compile-time checked in actor_storage's ctor + return reinterpret_cast( + reinterpret_cast(ptr) - CAF_CACHE_LINE_SIZE); + } + + /// @cond PRIVATE + + actor_addr address(); + + inline actor_id id() const noexcept { + return aid; + } + + inline const node_id& node() const noexcept { + return nid; + } + + void enqueue(strong_actor_ptr sender, message_id mid, + message content, execution_unit* host); + + void enqueue(mailbox_element_ptr what, execution_unit* host); + + /// @endcond +}; + +/// @relates actor_control_block +bool intrusive_ptr_upgrade_weak(actor_control_block* x); + +/// @relates actor_control_block +inline void intrusive_ptr_add_weak_ref(actor_control_block* x) { + x->weak_refs.fetch_add(1, std::memory_order_relaxed); +} + +/// @relates actor_control_block +void intrusive_ptr_release_weak(actor_control_block* x); + +/// @relates actor_control_block +inline void intrusive_ptr_add_ref(actor_control_block* x) { + x->strong_refs.fetch_add(1, std::memory_order_relaxed); +} + +/// @relates actor_control_block +void intrusive_ptr_release(actor_control_block* x); + +/// @relates abstract_actor +/// @relates actor_control_block +using strong_actor_ptr = intrusive_ptr; + +/// @relates strong_actor_ptr +bool operator==(const strong_actor_ptr&, const abstract_actor*); + +/// @relates strong_actor_ptr +bool operator==(const abstract_actor*, const strong_actor_ptr&); + +/// @relates strong_actor_ptr +inline bool operator!=(const strong_actor_ptr& x, const abstract_actor* y) { + return !(x == y); +} + +/// @relates strong_actor_ptr +inline bool operator!=(const abstract_actor* x, const strong_actor_ptr& y) { + return !(x == y); +} + +/// @relates abstract_actor +/// @relates actor_control_block +using weak_actor_ptr = weak_intrusive_ptr; + +error load_actor(strong_actor_ptr& storage, execution_unit*, + actor_id aid, const node_id& nid); + +error save_actor(strong_actor_ptr& storage, execution_unit*, + actor_id aid, const node_id& nid); + +template +auto context_of(Inspector* f) -> decltype(f->context()) { + return f->context(); +} + +inline execution_unit* context_of(void*) { + return nullptr; +} + +std::string to_string(const strong_actor_ptr& x); + +void append_to_string(std::string& x, const strong_actor_ptr& y); + +std::string to_string(const weak_actor_ptr& x); + +void append_to_string(std::string& x, const weak_actor_ptr& y); + +template +typename Inspector::result_type inspect(Inspector& f, strong_actor_ptr& x) { + actor_id aid = 0; + node_id nid; + if (x) { + aid = x->aid; + nid = x->nid; + } + auto load = [&] { return load_actor(x, context_of(&f), aid, nid); }; + auto save = [&] { return save_actor(x, context_of(&f), aid, nid); }; + return f(meta::type_name("actor"), aid, + meta::omittable_if_none(), nid, + meta::load_callback(load), meta::save_callback(save)); +} + +template +typename Inspector::result_type inspect(Inspector& f, weak_actor_ptr& x) { + // inspect as strong pointer, then write back to weak pointer on save + auto tmp = x.lock(); + auto load = [&]() -> error { x.reset(tmp.get()); return none; }; + return f(tmp, meta::load_callback(load)); +} + +} // namespace caf + +// allow actor pointers to be used in hash maps +namespace std { + +template <> +struct hash { + inline size_t operator()(const caf::strong_actor_ptr& ptr) const { + return ptr ? static_cast(ptr->id()) : 0; + } +}; + +template <> +struct hash { + inline size_t operator()(const caf::weak_actor_ptr& ptr) const { + return ptr ? static_cast(ptr->id()) : 0; + } +}; + +} // namespace std + diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_factory.hpp actor-framework-0.16.3/libcaf_core/caf/actor_factory.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_factory.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_factory.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,204 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include + +#include "caf/actor_addr.hpp" +#include "caf/actor_system.hpp" +#include "caf/infer_handle.hpp" +#include "caf/execution_unit.hpp" + +#include "caf/detail/type_traits.hpp" + +namespace caf { + +using actor_factory_result = std::pair>; + +using actor_factory = std::function; + +using selfptr_mode_token = spawn_mode_token; + +using void_mode_token = spawn_mode_token; + +template +class fun_decorator; + +template +class fun_decorator> { +public: + fun_decorator(F f, T*) : f_(std::move(f)) { + // nop + } + + behavior operator()(Ts... xs) { + detail::type_list token; + return apply(token, xs...); + } + + template + typename std::enable_if< + std::is_convertible::value, + behavior + >::type + apply(detail::type_list, Ts... xs) { + auto bhvr = f_(xs...); + return std::move(bhvr.unbox()); + } + + template + typename std::enable_if< + !std::is_convertible::value, + behavior + >::type + apply(detail::type_list, Ts... xs) { + f_(xs...); + return {}; + } + +private: + F f_; +}; + +template +class fun_decorator> { +public: + fun_decorator(F f, T* ptr) : f_(std::move(f)), ptr_(ptr) { + // nop + } + + behavior operator()(Ts... xs) { + detail::type_list token; + return apply(token, xs...); + } + + template + typename std::enable_if< + std::is_convertible::value, + behavior + >::type + apply(detail::type_list, Ts... xs) { + auto bhvr = f_(ptr_, xs...); + return std::move(bhvr.unbox()); + } + + template + typename std::enable_if< + !std::is_convertible::value, + behavior + >::type + apply(detail::type_list, Ts... xs) { + f_(ptr_, xs...); + return {}; + } + +private: + F f_; + T* ptr_; +}; + +template +struct message_verifier; + +template <> +struct message_verifier> { + bool operator()(message& msg, void_mode_token) { + return msg.empty(); + } +}; + +template +struct message_verifier> { + bool operator()(message& msg, void_mode_token) { + return msg.match_elements(); + } + bool operator()(message& msg, selfptr_mode_token) { + return msg.match_elements(); + } +}; + +template +actor_factory make_actor_factory(F fun) { + return [fun](actor_config& cfg, message& msg) -> actor_factory_result { + using trait = infer_handle_from_fun; + using handle = typename trait::type; + using impl = typename trait::impl; + using behavior_t = typename trait::behavior_type; + spawn_mode_token tk; + message_verifier mv; + if (!mv(msg, tk)) + return {}; + cfg.init_fun = [=](local_actor* x) -> behavior { + CAF_ASSERT(cfg.host); + using ctrait = typename detail::get_callable_trait::type; + using fd = fun_decorator; + fd f{fun, static_cast(x)}; + empty_type_erased_tuple dummy_; + auto& ct = msg.empty() ? dummy_ + : const_cast(msg).content(); + auto opt = ct.apply(f); + if (!opt) + return {}; + return std::move(*opt); + }; + handle hdl = cfg.host->system().spawn_class(cfg); + return {actor_cast(std::move(hdl)), + cfg.host->system().message_types()}; + }; +} + +template +struct dyn_spawn_class_helper { + Handle& result; + actor_config& cfg; + void operator()(Ts... xs) { + CAF_ASSERT(cfg.host); + result = cfg.host->system().spawn_class(cfg, xs...); + } +}; + +template +actor_factory_result dyn_spawn_class(actor_config& cfg, message& msg) { + CAF_ASSERT(cfg.host); + using handle = typename infer_handle_from_class::type; + handle hdl; + dyn_spawn_class_helper factory{hdl, cfg}; + msg.apply(factory); + return {actor_cast(std::move(hdl)), + cfg.host->system().message_types()}; +} + +template +actor_factory make_actor_factory() { + static_assert(detail::conjunction< + std::is_lvalue_reference::value... + >::value, + "all Ts must be lvalue references"); + static_assert(std::is_base_of::value, + "T is not derived from local_actor"); + return &dyn_spawn_class; +} + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor.hpp actor-framework-0.16.3/libcaf_core/caf/actor.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,81 +16,81 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_ACTOR_HPP -#define CAF_ACTOR_HPP +#pragma once +#include #include #include #include #include -#include "caf/intrusive_ptr.hpp" +#include "caf/config.hpp" #include "caf/fwd.hpp" +#include "caf/message.hpp" +#include "caf/actor_marker.hpp" #include "caf/abstract_actor.hpp" +#include "caf/actor_control_block.hpp" +#include "caf/unsafe_actor_handle_init.hpp" #include "caf/detail/comparable.hpp" #include "caf/detail/type_traits.hpp" namespace caf { -class scoped_actor; - -struct invalid_actor_t { - constexpr invalid_actor_t() {} +template +struct is_convertible_to_actor { + static constexpr bool value = + !std::is_base_of::value + && (std::is_base_of::value + || std::is_base_of::value); }; -/** - * Identifies an invalid {@link actor}. - * @relates actor - */ -constexpr invalid_actor_t invalid_actor = invalid_actor_t{}; +template <> +struct is_convertible_to_actor : std::true_type { + // nop +}; template -struct is_convertible_to_actor { - using type = typename std::remove_pointer::type; - static constexpr bool value = std::is_base_of::value - || std::is_base_of::value - || std::is_same::value; -}; +struct is_convertible_to_actor : is_convertible_to_actor {}; -/** - * Identifies an untyped actor. Can be used with derived types - * of `event_based_actor`, `blocking_actor`, and `actor_proxy`. - */ +/// Identifies an untyped actor. Can be used with derived types +/// of `event_based_actor`, `blocking_actor`, and `actor_proxy`. class actor : detail::comparable, detail::comparable, - detail::comparable, - detail::comparable { - + detail::comparable { +public: + // -- friend types that need access to private ctors friend class local_actor; - template - friend T actor_cast(const U&); + using signatures = none_t; - public: + // allow conversion via actor_cast + template + friend class actor_cast_access; - actor() = default; + // tell actor_cast which semantic this type uses + static constexpr bool has_weak_ptr_semantics = false; + actor() = default; actor(actor&&) = default; - actor(const actor&) = default; + actor& operator=(actor&&) = default; + actor& operator=(const actor&) = default; - template - actor(intrusive_ptr ptr, - typename std::enable_if::value>::type* = 0) - : m_ptr(std::move(ptr)) {} - - template - actor(T* ptr, - typename std::enable_if::value>::type* = 0) - : m_ptr(ptr) {} + actor(std::nullptr_t); - actor(const invalid_actor_t&); + actor(const scoped_actor&); - actor& operator=(actor&&) = default; + explicit actor(const unsafe_actor_handle_init_t&) CAF_DEPRECATED; - actor& operator=(const actor&) = default; + template ::value + >::type> + actor(T* ptr) : ptr_(ptr->ctrl()) { + CAF_ASSERT(ptr != nullptr); + } template typename std::enable_if::value, actor&>::type @@ -109,65 +108,120 @@ return *this; } - actor& operator=(const invalid_actor_t&); + actor& operator=(std::nullptr_t); + + actor& operator=(const scoped_actor& x); - inline operator bool() const { - return static_cast(m_ptr); + /// Queries whether this actor handle is valid. + inline explicit operator bool() const { + return static_cast(ptr_); } + /// Queries whether this actor handle is invalid. inline bool operator!() const { - return !m_ptr; + return !ptr_; } - /** - * Returns a handle that grants access to actor operations such as enqueue. - */ - inline abstract_actor* operator->() const { - return m_ptr.get(); + /// Returns the address of the stored actor. + actor_addr address() const noexcept; + + /// Returns the ID of this actor. + inline actor_id id() const noexcept { + return ptr_->id(); } - inline abstract_actor& operator*() const { - return *m_ptr; + /// Returns the origin node of this actor. + inline node_id node() const noexcept { + return ptr_->node(); } - intptr_t compare(const actor& other) const; + /// Returns the hosting actor system. + inline actor_system& home_system() const noexcept { + return *ptr_->home_system; + } - intptr_t compare(const actor_addr&) const; + /// Exchange content of `*this` and `other`. + void swap(actor& other) noexcept; - inline intptr_t compare(const invalid_actor_t&) const { - return m_ptr ? 1 : 0; + /// Queries whether this object was constructed using + /// `unsafe_actor_handle_init` or is in moved-from state. + bool unsafe() const CAF_DEPRECATED { + return !ptr_; } - inline intptr_t compare(const invalid_actor_addr_t&) const { - return compare(invalid_actor); + /// @cond PRIVATE + + inline abstract_actor* operator->() const noexcept { + CAF_ASSERT(ptr_); + return ptr_->get(); } - /** - * Returns the address of the stored actor. - */ - actor_addr address() const; + intptr_t compare(const actor&) const noexcept; + + intptr_t compare(const actor_addr&) const noexcept; + + intptr_t compare(const strong_actor_ptr&) const noexcept; - /** - * Returns whether this is an handle to a remote actor. - */ - bool is_remote() const; + static actor splice_impl(std::initializer_list xs); - actor_id id() const; + actor(actor_control_block*, bool); - void swap(actor& other); + /// @endcond - private: + friend inline std::string to_string(const actor& x) { + return to_string(x.ptr_); + } - inline abstract_actor* get() const { - return m_ptr.get(); + friend inline void append_to_string(std::string& x, const actor& y) { + return append_to_string(x, y.ptr_); } - actor(abstract_actor*); + template + friend typename Inspector::result_type inspect(Inspector& f, actor& x) { + return inspect(f, x.ptr_); + } - abstract_actor_ptr m_ptr; + /// Releases the reference held by handle `x`. Using the + /// handle after invalidating it is undefined behavior. + friend void destroy(actor& x) { + x.ptr_.reset(); + } + +private: + inline actor_control_block* get() const noexcept { + return ptr_.get(); + } + inline actor_control_block* release() noexcept { + return ptr_.release(); + } + + actor(actor_control_block*); + + strong_actor_ptr ptr_; }; +/// Combine `f` and `g` so that `(f*g)(x) = f(g(x))`. +actor operator*(actor f, actor g); + +/// @relates actor +template +actor splice(const actor& x, const actor& y, const Ts&... zs) { + return actor::splice_impl({x, y, zs...}); +} + +/// @relates actor +bool operator==(const actor& lhs, abstract_actor* rhs); + +/// @relates actor +bool operator==(abstract_actor* lhs, const actor& rhs); + +/// @relates actor +bool operator!=(const actor& lhs, abstract_actor* rhs); + +/// @relates actor +bool operator!=(abstract_actor* lhs, const actor& rhs); + } // namespace caf // allow actor to be used in hash maps @@ -175,10 +229,8 @@ template <> struct hash { inline size_t operator()(const caf::actor& ref) const { - return ref ? static_cast(ref->id()) : 0; + return static_cast(ref ? ref->id() : 0); } - }; } // namespace std -#endif // CAF_ACTOR_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_marker.hpp actor-framework-0.16.3/libcaf_core/caf/actor_marker.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_marker.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_marker.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,50 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include "caf/fwd.hpp" + +namespace caf { + +class statically_typed_actor_base { + // used as marker only +}; + +class dynamically_typed_actor_base { + // used as marker only +}; + +template +struct actor_marker { + using type = statically_typed_actor_base; +}; + +template <> +struct actor_marker { + using type = dynamically_typed_actor_base; +}; + +template +using is_statically_typed = std::is_base_of; + +template +using is_dynamically_typed = std::is_base_of; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_namespace.hpp actor-framework-0.16.3/libcaf_core/caf/actor_namespace.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_namespace.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_namespace.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,130 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_ACTOR_NAMESPACE_HPP -#define CAF_ACTOR_NAMESPACE_HPP - -#include -#include -#include - -#include "caf/node_id.hpp" -#include "caf/actor_cast.hpp" -#include "caf/actor_proxy.hpp" - -namespace caf { - -class serializer; -class deserializer; - -/** - * Groups a (distributed) set of actors and allows actors - * in the same namespace to exchange messages. - */ -class actor_namespace { - public: - using key_type = node_id; - - /** - * The backend of an actor namespace is responsible for creating proxy actors. - */ - class backend { - public: - virtual ~backend(); - - /** - * Creates a new proxy instance. - */ - virtual actor_proxy_ptr make_proxy(const key_type&, actor_id) = 0; - }; - - actor_namespace(backend& mgm); - - /** - * Writes an actor address to `sink` and adds the actor - * to the list of known actors for a later deserialization. - */ - void write(serializer* sink, const actor_addr& ptr); - - /** - * Reads an actor address from `source,` creating - * addresses for remote actors on the fly if needed. - */ - actor_addr read(deserializer* source); - - /** - * A map that stores all proxies for known remote actors. - */ - using proxy_map = std::map; - - /** - * Returns the number of proxies for `node`. - */ - size_t count_proxies(const key_type& node); - - /** - * Returns all proxies for `node`. - */ - std::vector get_all(); - - /** - * Returns all proxies for `node`. - */ - std::vector get_all(const key_type& node); - - /** - * Returns the proxy instance identified by `node` and `aid` - * or `nullptr` if the actor either unknown or expired. - */ - actor_proxy_ptr get(const key_type& node, actor_id aid); - - /** - * Returns the proxy instance identified by `node` and `aid` - * or creates a new (default) proxy instance. - */ - actor_proxy_ptr get_or_put(const key_type& node, actor_id aid); - - /** - * Deletes all proxies for `node`. - */ - void erase(const key_type& node); - - /** - * Deletes the proxy with id `aid` for `node`. - */ - void erase(const key_type& node, actor_id aid); - - /** - * Queries whether there are any proxies left. - */ - bool empty() const; - - /** - * Deletes all proxies. - */ - void clear(); - - private: - backend& m_backend; - std::map m_proxies; -}; - -} // namespace caf - -#endif diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_ostream.hpp actor-framework-0.16.3/libcaf_core/caf/actor_ostream.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_ostream.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_ostream.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,70 +16,94 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_ACTOR_OSTREAM_HPP -#define CAF_ACTOR_OSTREAM_HPP +#pragma once #include "caf/actor.hpp" -#include "caf/message.hpp" -#include "caf/to_string.hpp" +#include "caf/deep_to_string.hpp" +#include "caf/typed_actor_pointer.hpp" namespace caf { -class local_actor; -class scoped_actor; - +/// Provides support for thread-safe output operations on character streams. The +/// stream operates on a per-actor basis and will print only complete lines or +/// when explicitly forced to flush its buffer. The stream will convert *any* +/// operation to a message received by a printer actor. This actor is a sequence +/// point that ensures output appears never interleaved. class actor_ostream { - - public: - +public: using fun_type = actor_ostream& (*)(actor_ostream&); actor_ostream(actor_ostream&&) = default; actor_ostream(const actor_ostream&) = default; - actor_ostream& operator=(actor_ostream&&) = default; actor_ostream& operator=(const actor_ostream&) = default; - explicit actor_ostream(actor self); + /// Open redirection file in append mode. + static constexpr int append = 0x01; + + explicit actor_ostream(local_actor* self); + explicit actor_ostream(scoped_actor& self); + + template + explicit actor_ostream(const typed_actor_pointer& ptr) + : actor_ostream(ptr.internal_ptr()) { + // nop + } + + /// Writes `arg` to the buffer allocated for the calling actor. actor_ostream& write(std::string arg); + /// Flushes the buffer allocated for the calling actor. actor_ostream& flush(); - inline actor_ostream& operator<<(std::string arg) { - return write(std::move(arg)); - } + /// Redirects all further output from `self` to `file_name`. + static void redirect(abstract_actor* self, std::string fn, int flags = 0); - inline actor_ostream& operator<<(const message& arg) { - return write(caf::to_string(arg)); - } + /// Redirects all further output from any actor that did not + /// redirect its output to `fname`. + static void redirect_all(actor_system& sys, std::string fn, int flags = 0); - // disambiguate between conversion to string and to message + /// Writes `arg` to the buffer allocated for the calling actor. inline actor_ostream& operator<<(const char* arg) { - return *this << std::string{arg}; + return write(arg); } + /// Writes `arg` to the buffer allocated for the calling actor. + inline actor_ostream& operator<<(std::string arg) { + return write(std::move(arg)); + } + + /// Writes `to_string(arg)` to the buffer allocated for the calling actor, + /// calling either `std::to_string` or `caf::to_string` depending on + /// the argument. template - inline typename std::enable_if< - !std::is_convertible::value && - !std::is_convertible::value, actor_ostream& - >::type operator<<(T&& arg) { - return write(std::to_string(std::forward(arg))); + inline actor_ostream& operator<<(const T& arg) { + return write(deep_to_string(arg)); } + /// Apply `f` to `*this`. inline actor_ostream& operator<<(actor_ostream::fun_type f) { return f(*this); } - private: - - actor m_self; - actor m_printer; +private: + void init(abstract_actor*); + actor_id self_; + actor printer_; }; -inline actor_ostream aout(actor self) { - return actor_ostream{self}; +/// Convenience factory function for creating an actor output stream. +actor_ostream aout(local_actor* self); + +/// Convenience factory function for creating an actor output stream. +actor_ostream aout(scoped_actor& self); + +/// Convenience factory function for creating an actor output stream. +template +actor_ostream aout(const typed_actor_pointer& ptr) { + return actor_ostream{ptr}; } } // namespace caf @@ -91,4 +114,3 @@ caf::actor_ostream& flush(caf::actor_ostream& o); } // namespace std -#endif // CAF_ACTOR_OSTREAM_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_pool.hpp actor-framework-0.16.3/libcaf_core/caf/actor_pool.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_pool.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_pool.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,139 +16,110 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_ACTOR_POOL_HPP -#define CAF_ACTOR_POOL_HPP +#pragma once -#include -#include #include #include #include "caf/locks.hpp" #include "caf/actor.hpp" -#include "caf/abstract_actor.hpp" +#include "caf/execution_unit.hpp" #include "caf/mailbox_element.hpp" +#include "caf/monitorable_actor.hpp" #include "caf/detail/split_join.hpp" #include "caf/detail/shared_spinlock.hpp" namespace caf { -/** - * An actor poool is a lightweight abstraction for a set of workers. - * The pool itself is an actor, meaning that it can be passed - * around in an actor system to hide the actual set of workers. - * - * After construction, new workers can be added via `{'SYS', 'PUT', actor}` - * messages, e.g., `send(my_pool, sys_atom::value, put_atom::value, worker)`. - * `{'SYS', 'DELETE', actor}` messages remove a worker from the set, - * whereas `{'SYS', 'GET'}` returns a `vector` containing all workers. - * - * Note that the pool *always* sends exit messages to all of its workers - * when forced to quit. The pool monitors all of its workers. Messages queued - * up in a worker's mailbox are lost, i.e., the pool itself does not buffer - * and resend messages. Advanced caching or resend strategies can be - * implemented in a policy. - * - * It is wort mentioning that the pool is *not* an event-based actor. - * Neither does it live in its own thread. Messages are dispatched immediately - * during the enqueue operation. Any user-defined policy thus has to dispatch - * messages with as little overhead as possible, because the dispatching - * runs in the context of the sender. - */ -class actor_pool : public abstract_actor { - public: +/// An actor poool is a lightweight abstraction for a set of workers. +/// The pool itself is an actor, meaning that it can be passed +/// around in an actor system to hide the actual set of workers. +/// +/// After construction, new workers can be added via `{'SYS', 'PUT', actor}` +/// messages, e.g., `send(my_pool, sys_atom::value, put_atom::value, worker)`. +/// `{'SYS', 'DELETE', actor}` messages remove a specific worker from the set, +/// `{'SYS', 'DELETE'}` removes all workers, and `{'SYS', 'GET'}` returns a +/// `vector` containing all workers. +/// +/// Note that the pool *always* sends exit messages to all of its workers +/// when forced to quit. The pool monitors all of its workers. Messages queued +/// up in a worker's mailbox are lost, i.e., the pool itself does not buffer +/// and resend messages. Advanced caching or resend strategies can be +/// implemented in a policy. +/// +/// It is worth mentioning that the pool is *not* an event-based actor. +/// Neither does it live in its own thread. Messages are dispatched immediately +/// during the enqueue operation. Any user-defined policy thus has to dispatch +/// messages with as little overhead as possible, because the dispatching +/// runs in the context of the sender. +/// @experimental +class actor_pool : public monitorable_actor { +public: using uplock = upgrade_lock; using actor_vec = std::vector; using factory = std::function; - using policy = std::function; - /** - * Default policy class implementing simple round robin dispatching. - */ - class round_robin { - public: - round_robin(); - round_robin(const round_robin&); - void operator()(uplock&, const actor_vec&, - mailbox_element_ptr&, execution_unit*); - - private: - std::atomic m_pos; - }; - - /** - * Default policy class implementing broadcast dispatching. - */ - class broadcast { - public: - void operator()(uplock&, const actor_vec&, - mailbox_element_ptr&, execution_unit*); - }; - - /** - * Default policy class implementing random dispatching. - */ - class random { - public: - random(); - random(const random&); - void operator()(uplock&, const actor_vec&, - mailbox_element_ptr&, execution_unit*); - - private: - std::random_device m_rd; - }; - - /** - * Default policy class implementing broadcast dispatching (split step) - * followed by a join operation `F` combining all individual results to - * a single result of type `T`. - * @tparam T Result type received by the original sender. - * @tparam Join Functor with signature `void (T&, message&)`. - * @tparam Split Functor with signature - * `void (vector>&, message&)`. - */ + /// Returns a simple round robin dispatching policy. + static policy round_robin(); + + /// Returns a broadcast dispatching policy. + static policy broadcast(); + + /// Returns a random dispatching policy. + static policy random(); + + /// Returns a split/join dispatching policy. The function object `sf` + /// distributes a work item to all workers (split step) and the function + /// object `jf` joins individual results into a single one with `init` + /// as initial value of the operation. + /// @tparam T Result type of the join step. + /// @tparam Join Function object with signature `void (T&, message&)`. + /// @tparam Split Function object with signature + /// `void (vector>&, message&)`. The first + /// argument is a mapping from actors (workers) to tasks + /// (messages). The second argument is the input message. + /// The default split policy broadcasts the work item to all + /// workers. template static policy split_join(Join jf, Split sf = Split(), T init = T()) { using impl = detail::split_join; return impl{std::move(init), std::move(sf), std::move(jf)}; } - ~actor_pool(); + ~actor_pool() override; + + /// Returns an actor pool without workers using the dispatch policy `pol`. + static actor make(execution_unit* eu, policy pol); - /** - * Returns an actor pool without workers using the dispatch policy `pol`. - */ - static actor make(policy pol); + /// Returns an actor pool with `n` workers created by the factory + /// function `fac` using the dispatch policy `pol`. + static actor make(execution_unit* eu, size_t num_workers, const factory& fac, policy pol); - /** - * Returns an actor pool with `n` workers created by the factory - * function `fac` using the dispatch policy `pol`. - */ - static actor make(size_t n, factory fac, policy pol); + void enqueue(mailbox_element_ptr what, execution_unit* eu) override; - void enqueue(const actor_addr& sender, message_id mid, - message content, execution_unit* host) override; + actor_pool(actor_config& cfg); - void enqueue(mailbox_element_ptr what, execution_unit* host) override; + void on_destroy() override; - actor_pool(); +protected: + void on_cleanup(const error& reason) override; - private: - bool filter(upgrade_lock&, const actor_addr& sender, - message_id mid, const message& content, execution_unit* host); +private: + bool filter(upgrade_lock&, + const strong_actor_ptr& sender, message_id mid, + message_view& mv, execution_unit* eu); - // call without m_mtx held - void quit(); + // call without workers_mtx_ held + void quit(execution_unit* host); - detail::shared_spinlock m_mtx; - std::vector m_workers; - policy m_policy; - uint32_t m_planned_reason; + detail::shared_spinlock workers_mtx_; + std::vector workers_; + policy policy_; + exit_reason planned_reason_; }; } // namespace caf -#endif // CAF_ACTOR_POOL_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_proxy.hpp actor-framework-0.16.3/libcaf_core/caf/actor_proxy.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_proxy.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_proxy.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,96 +16,29 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_ACTOR_PROXY_HPP -#define CAF_ACTOR_PROXY_HPP +#pragma once #include #include #include "caf/abstract_actor.hpp" +#include "caf/monitorable_actor.hpp" #include "caf/detail/shared_spinlock.hpp" namespace caf { -class actor_proxy; +/// Represents an actor running on a remote machine, +/// or different hardware, or in a separate process. +class actor_proxy : public monitorable_actor { +public: + explicit actor_proxy(actor_config& cfg); -/** - * A smart pointer to an {@link actor_proxy} instance. - * @relates actor_proxy - */ -using actor_proxy_ptr = intrusive_ptr; - -/** - * Represents an actor running on a remote machine, - * or different hardware, or in a separate process. - */ -class actor_proxy : public abstract_actor { - public: - /** - * An anchor points to a proxy instance without sharing - * ownership to it, i.e., models a weak ptr. - */ - class anchor : public ref_counted { - public: - friend class actor_proxy; - - anchor(actor_proxy* instance = nullptr); - - ~anchor(); - - /** - * Queries whether the proxy was already deleted. - */ - bool expired() const; - - /** - * Gets a pointer to the proxy or `nullptr` - * if the instance is {@link expired()}. - */ - actor_proxy_ptr get(); - - private: - /* - * Tries to expire this anchor. Fails if reference - * count of the proxy is nonzero. - */ - bool try_expire() noexcept; - std::atomic m_ptr; - detail::shared_spinlock m_lock; - }; - - using anchor_ptr = intrusive_ptr; - - ~actor_proxy(); - - /** - * Establishes a local link state that's not synchronized back - * to the remote instance. - */ - virtual void local_link_to(const actor_addr& other) = 0; - - /** - * Removes a local link state. - */ - virtual void local_unlink_from(const actor_addr& other) = 0; - - /** - * Invokes cleanup code. - */ - virtual void kill_proxy(uint32_t reason) = 0; - - void request_deletion(bool decremented_ref_count) noexcept override; - - inline anchor_ptr get_anchor() { - return m_anchor; - } - - protected: - actor_proxy(actor_id aid, node_id nid); - anchor_ptr m_anchor; + ~actor_proxy() override; + + /// Invokes cleanup code. + virtual void kill_proxy(execution_unit* ctx, error reason) = 0; }; } // namespace caf -#endif // CAF_ACTOR_PROXY_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_registry.hpp actor-framework-0.16.3/libcaf_core/caf/actor_registry.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_registry.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_registry.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,136 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "caf/fwd.hpp" +#include "caf/actor.hpp" +#include "caf/actor_cast.hpp" +#include "caf/abstract_actor.hpp" +#include "caf/actor_control_block.hpp" + +#include "caf/detail/shared_spinlock.hpp" + +namespace caf { + +/// A registry is used to associate actors to IDs or atoms (names). This +/// allows a middleman to lookup actor handles after receiving actor IDs +/// via the network and enables developers to use well-known names to +/// identify important actors independent from their ID at runtime. +/// Note that the registry does *not* contain all actors of an actor system. +/// The middleman registers actors as needed. +class actor_registry { +public: + friend class actor_system; + + ~actor_registry(); + + /// Returns the local actor associated to `key`. + template + T get(actor_id key) const { + return actor_cast(get_impl(key)); + } + + /// Associates a local actor with its ID. + template + void put(actor_id key, const T& val) { + put_impl(key, actor_cast(val)); + } + + /// Removes an actor from this registry, + /// leaving `reason` for future reference. + void erase(actor_id key); + + /// Increases running-actors-count by one. + void inc_running(); + + /// Decreases running-actors-count by one. + void dec_running(); + + /// Returns the number of currently running actors. + size_t running() const; + + /// Blocks the caller until running-actors-count becomes `expected` + /// (must be either 0 or 1). + void await_running_count_equal(size_t expected) const; + + /// Returns the actor associated with `key` or `invalid_actor`. + template + T get(atom_value key) const { + return actor_cast(get_impl(key)); + } + + /// Associates given actor to `key`. + template + void put(atom_value key, const T& value) { + // using reference here and before to allow putting a scoped_actor without calling .ptr() + put_impl(key, actor_cast(value)); + } + + /// Removes a name mapping. + void erase(atom_value key); + + using name_map = std::unordered_map; + + name_map named_actors() const; + +private: + // Starts this component. + void start(); + + // Stops this component. + void stop(); + + /// Returns the local actor associated to `key`. + strong_actor_ptr get_impl(actor_id key) const; + + /// Associates a local actor with its ID. + void put_impl(actor_id key, strong_actor_ptr val); + + /// Returns the actor associated with `key` or `invalid_actor`. + strong_actor_ptr get_impl(atom_value key) const; + + /// Associates given actor to `key`. + void put_impl(atom_value key, strong_actor_ptr value); + + using entries = std::unordered_map; + + actor_registry(actor_system& sys); + + std::atomic running_; + mutable std::mutex running_mtx_; + mutable std::condition_variable running_cv_; + + mutable detail::shared_spinlock instances_mtx_; + entries entries_; + + name_map named_entries_; + mutable detail::shared_spinlock named_entries_mtx_; + + actor_system& system_; +}; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_storage.hpp actor-framework-0.16.3/libcaf_core/caf/actor_storage.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_storage.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_storage.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,144 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include + +#include "caf/config.hpp" +#include "caf/abstract_actor.hpp" +#include "caf/actor_control_block.hpp" + +#ifdef CAF_GCC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif + +namespace caf { + +template +class actor_storage { +public: + template + actor_storage(actor_id x, node_id y, actor_system* sys, Us&&... zs) + : ctrl(x, y, sys, data_dtor, block_dtor) { + // construct data member + new (&data) T(std::forward(zs)...); + } + + ~actor_storage() { + // 1) make sure control block fits into a single cache line + static_assert(sizeof(actor_control_block) < CAF_CACHE_LINE_SIZE, + "actor_control_block exceeds a single cache line"); + // Clang in combination with libc++ on Linux complains about offsetof: + // error: 'actor_storage' does not refer to a value + // Until we have found a reliable solution, we disable this safety check. + #if !(defined(CAF_CLANG) && defined(CAF_LINUX)) + // 2) make sure reinterpret cast of the control block to the storage works + static_assert(offsetof(actor_storage, ctrl) == 0, + "control block is not at the start of the storage"); + // 3) make sure we can obtain a data pointer by jumping one cache line + static_assert(offsetof(actor_storage, data) == CAF_CACHE_LINE_SIZE, + "data is not at cache line size boundary"); + #else + // 4) make sure static_cast and reinterpret_cast + // between T* and abstract_actor* are identical + constexpr abstract_actor* dummy = nullptr; + constexpr T* derived_dummy = static_cast(dummy); + static_assert(derived_dummy == nullptr, + "actor subtype has illegal memory alignment " + "(probably due to virtual inheritance)"); + #endif + } + + actor_storage(const actor_storage&) = delete; + actor_storage& operator=(const actor_storage&) = delete; + + static_assert(sizeof(actor_control_block) < CAF_CACHE_LINE_SIZE, + "actor_control_block exceeds 64 bytes"); + + actor_control_block ctrl; + char pad[CAF_CACHE_LINE_SIZE - sizeof(actor_control_block)]; + union { T data; }; + +private: + static void data_dtor(abstract_actor* ptr) { + // safe due to static assert #3 + ptr->on_destroy(); + static_cast(ptr)->~T(); + } + + static void block_dtor(actor_control_block* ptr) { + // safe due to static assert #2 + delete reinterpret_cast(ptr); + } +}; + +/// @relates actor_storage +template +bool intrusive_ptr_upgrade_weak(actor_storage* x) { + auto count = x->ctrl.strong_refs.load(); + while (count != 0) { + if (x->ctrl.strong_refs.compare_exchange_weak(count, count + 1, + std::memory_order_relaxed)) + return true; + } + return false; +} + +/// @relates actor_storage +template +void intrusive_ptr_add_weak_ref(actor_storage* x) { + x->ctrl.weak_refs.fetch_add(1, std::memory_order_relaxed); +} + +/// @relates actor_storage +template +void intrusive_ptr_release_weak(actor_storage* x) { + // destroy object if last weak pointer expires + if (x->ctrl.weak_refs == 1 + || x->ctrl.weak_refs.fetch_sub(1, std::memory_order_acq_rel) == 1) + delete x; +} + +/// @relates actor_storage +template +void intrusive_ptr_add_ref(actor_storage* x) { + x->ctrl.strong_refs.fetch_add(1, std::memory_order_relaxed); +} + +/// @relates actor_storage +template +void intrusive_ptr_release(actor_storage* x) { + // release implicit weak pointer if the last strong ref expires + // and destroy the data block + if (x->ctrl.strong_refs.fetch_sub(1, std::memory_order_acq_rel) == 1) { + x->destroy_data(); + intrusive_ptr_relase_weak(x); + } +} + +} // namespace caf + +#ifdef CAF_GCC +#pragma GCC diagnostic pop +#endif + diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_system_config.hpp actor-framework-0.16.3/libcaf_core/caf/actor_system_config.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_system_config.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_system_config.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,395 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "caf/actor_factory.hpp" +#include "caf/config_option.hpp" +#include "caf/config_option_adder.hpp" +#include "caf/config_option_set.hpp" +#include "caf/config_value.hpp" +#include "caf/dictionary.hpp" +#include "caf/fwd.hpp" +#include "caf/is_typed_actor.hpp" +#include "caf/named_actor_config.hpp" +#include "caf/stream.hpp" +#include "caf/thread_hook.hpp" +#include "caf/type_erased_value.hpp" + +#include "caf/detail/safe_equal.hpp" +#include "caf/detail/type_traits.hpp" + +namespace caf { + +/// Configures an `actor_system` on startup. +class actor_system_config { +public: + // -- member types ----------------------------------------------------------- + + using hook_factory = std::function; + + using hook_factory_vector = std::vector; + + using thread_hooks = std::vector>; + + template + using hash_map = std::unordered_map; + + using module_factory = std::function; + + using module_factory_vector = std::vector; + + using value_factory = std::function; + + using value_factory_string_map = hash_map; + + using value_factory_rtti_map = hash_map; + + using actor_factory_map = hash_map; + + using portable_name_map = hash_map; + + using error_renderer = std::function; + + using error_renderer_map = hash_map; + + using group_module_factory = std::function; + + using group_module_factory_vector = std::vector; + + using config_map = dictionary; + + using string_list = std::vector; + + using named_actor_config_map = hash_map; + + using opt_group = config_option_adder; + + // -- constructors, destructors, and assignment operators -------------------- + + virtual ~actor_system_config(); + + actor_system_config(); + + actor_system_config(actor_system_config&&) = default; + + actor_system_config(const actor_system_config&) = delete; + actor_system_config& operator=(const actor_system_config&) = delete; + + // -- properties ------------------------------------------------------------- + + /// @private + dictionary content; + + /// Sets a config by using its INI name `config_name` to `config_value`. + template + actor_system_config& set(string_view name, T&& value) { + return set_impl(name, config_value{std::forward(value)}); + } + + // -- modifiers -------------------------------------------------------------- + + /// Parses `args` as tuple of strings containing CLI options + /// and `ini_stream` as INI formatted input stream. + actor_system_config& parse(string_list args, std::istream& ini); + + /// Parses `args` as tuple of strings containing CLI options and tries to + /// open `ini_file_cstr` as INI formatted config file. The parsers tries to + /// open `caf-application.ini` if `ini_file_cstr` is `nullptr`. + actor_system_config& parse(string_list args, + const char* ini_file_cstr = nullptr); + + /// Parses the CLI options `{argc, argv}` and + /// `ini_stream` as INI formatted input stream. + actor_system_config& parse(int argc, char** argv, std::istream& ini); + + /// Parses the CLI options `{argc, argv}` and tries to open `ini_file_cstr` + /// as INI formatted config file. The parsers tries to open + /// `caf-application.ini` if `ini_file_cstr` is `nullptr`. + actor_system_config& parse(int argc, char** argv, + const char* ini_file_cstr = nullptr); + + actor_system_config& + parse(message& args, const char* ini_file_cstr = nullptr) CAF_DEPRECATED; + + actor_system_config& parse(message& args, std::istream& ini) CAF_DEPRECATED; + + /// Allows other nodes to spawn actors created by `fun` + /// dynamically by using `name` as identifier. + /// @experimental + actor_system_config& add_actor_factory(std::string name, actor_factory fun); + + /// Allows other nodes to spawn actors of type `T` + /// dynamically by using `name` as identifier. + /// @experimental + template + actor_system_config& add_actor_type(std::string name) { + using handle = typename infer_handle_from_class::type; + if (!std::is_same::value) + add_message_type(name); + return add_actor_factory(std::move(name), make_actor_factory()); + } + + /// Allows other nodes to spawn actors implemented by function `f` + /// dynamically by using `name` as identifier. + /// @experimental + template + actor_system_config& add_actor_type(std::string name, F f) { + using handle = typename infer_handle_from_fun::type; + if (!std::is_same::value) + add_message_type(name); + return add_actor_factory(std::move(name), make_actor_factory(std::move(f))); + } + + /// Adds message type `T` with runtime type info `name`. + template + actor_system_config& add_message_type(std::string name) { + static_assert(std::is_empty::value + || std::is_same::value // silence add_actor_type err + || is_typed_actor::value + || (std::is_default_constructible::value + && std::is_copy_constructible::value), + "T must provide default and copy constructors"); + std::string stream_name = "stream<"; + stream_name += name; + stream_name += ">"; + add_message_type_impl>(std::move(stream_name)); + std::string vec_name = "std::vector<"; + vec_name += name; + vec_name += ">"; + add_message_type_impl>(std::move(vec_name)); + add_message_type_impl(std::move(name)); + return *this; + } + + /// Enables the actor system to convert errors of this error category + /// to human-readable strings via `renderer`. + actor_system_config& add_error_category(atom_value x, + error_renderer y); + + /// Enables the actor system to convert errors of this error category + /// to human-readable strings via `to_string(T)`. + template + actor_system_config& add_error_category(atom_value category) { + auto f = [=](uint8_t val, const std::string& ctx) -> std::string { + std::string result; + result = to_string(category); + result += ": "; + result += to_string(static_cast(val)); + if (!ctx.empty()) { + result += " ("; + result += ctx; + result += ")"; + } + return result; + }; + return add_error_category(category, f); + } + + /// Loads module `T` with optional template parameters `Ts...`. + template + actor_system_config& load() { + module_factories.push_back([](actor_system& sys) -> actor_system::module* { + return T::make(sys, detail::type_list{}); + }); + return *this; + } + + /// Adds a factory for a new hook type to the middleman (if loaded). + template + actor_system_config& add_hook_factory(Factory f) { + hook_factories.push_back(f); + return *this; + } + + /// Adds a hook type to the middleman (if loaded). + template + actor_system_config& add_hook_type() { + return add_hook_factory([](actor_system& sys) -> Hook* { + return new Hook(sys); + }); + } + + /// Adds a hook type to the scheduler. + template + actor_system_config& add_thread_hook(Ts&&... ts) { + thread_hooks_.emplace_back(new Hook(std::forward(ts)...)); + return *this; + } + + // -- parser and CLI state --------------------------------------------------- + + /// Stores whether the help text was printed. If set to `true`, the + /// application should not use this config to initialize an `actor_system` + /// and instead return from `main` immediately. + bool cli_helptext_printed; + + /// Stores CLI arguments that were not consumed by CAF. + message args_remainder CAF_DEPRECATED; + + /// Stores CLI arguments that were not consumed by CAF. + string_list remainder; + + // -- caf-run parameters ----------------------------------------------------- + + /// Stores whether this node was started in slave mode. + bool slave_mode; + + /// Name of this node when started in slave mode. + std::string slave_name; + + /// Credentials for connecting to the bootstrap node. + std::string bootstrap_node; + + // -- stream parameters ------------------------------------------------------ + + /// @private + timespan stream_desired_batch_complexity; + + /// @private + timespan stream_max_batch_delay; + + /// @private + timespan stream_credit_round_interval; + + /// @private + timespan stream_tick_duration() const noexcept; + + timespan streaming_credit_round_interval() const noexcept CAF_DEPRECATED; + + // -- scheduling parameters -------------------------------------------------- + + atom_value scheduler_policy CAF_DEPRECATED; + size_t scheduler_max_threads CAF_DEPRECATED; + size_t scheduler_max_throughput CAF_DEPRECATED; + bool scheduler_enable_profiling CAF_DEPRECATED; + size_t scheduler_profiling_ms_resolution CAF_DEPRECATED; + std::string scheduler_profiling_output_file CAF_DEPRECATED; + + // -- work-stealing parameters ----------------------------------------------- + + size_t work_stealing_aggressive_poll_attempts CAF_DEPRECATED; + size_t work_stealing_aggressive_steal_interval CAF_DEPRECATED; + size_t work_stealing_moderate_poll_attempts CAF_DEPRECATED; + size_t work_stealing_moderate_steal_interval CAF_DEPRECATED; + size_t work_stealing_moderate_sleep_duration_us CAF_DEPRECATED; + size_t work_stealing_relaxed_steal_interval CAF_DEPRECATED; + size_t work_stealing_relaxed_sleep_duration_us CAF_DEPRECATED; + + // -- logger parameters ------------------------------------------------------ + + std::string logger_file_name CAF_DEPRECATED; + std::string logger_file_format CAF_DEPRECATED; + atom_value logger_console CAF_DEPRECATED; + std::string logger_console_format CAF_DEPRECATED; + std::string logger_component_filter CAF_DEPRECATED; + atom_value logger_verbosity CAF_DEPRECATED; + bool logger_inline_output CAF_DEPRECATED; + + // -- middleman parameters --------------------------------------------------- + + atom_value middleman_network_backend CAF_DEPRECATED; + std::string middleman_app_identifier CAF_DEPRECATED; + bool middleman_enable_automatic_connections CAF_DEPRECATED; + size_t middleman_max_consecutive_reads CAF_DEPRECATED; + size_t middleman_heartbeat_interval CAF_DEPRECATED; + bool middleman_detach_utility_actors CAF_DEPRECATED; + bool middleman_detach_multiplexer CAF_DEPRECATED; + size_t middleman_cached_udp_buffers CAF_DEPRECATED; + size_t middleman_max_pending_msgs CAF_DEPRECATED; + + // -- OpenCL parameters ------------------------------------------------------ + + std::string opencl_device_ids; + + // -- OpenSSL parameters ----------------------------------------------------- + + std::string openssl_certificate; + std::string openssl_key; + std::string openssl_passphrase; + std::string openssl_capath; + std::string openssl_cafile; + + // -- factories -------------------------------------------------------------- + + value_factory_string_map value_factories_by_name; + value_factory_rtti_map value_factories_by_rtti; + actor_factory_map actor_factories; + module_factory_vector module_factories; + hook_factory_vector hook_factories; + group_module_factory_vector group_module_factories; + + // -- hooks ------------------------------------------------------------------ + + thread_hooks thread_hooks_; + + // -- run-time type information ---------------------------------------------- + + portable_name_map type_names_by_rtti; + + // -- rendering of user-defined types ---------------------------------------- + + error_renderer_map error_renderers; + + // -- parsing parameters ----------------------------------------------------- + + /// Configures the file path for the INI file, `caf-application.ini` per + /// default. + std::string config_file_path; + + // -- utility for caf-run ---------------------------------------------------- + + // Config parameter for individual actor types. + named_actor_config_map named_actor_configs; + + int (*slave_mode_fun)(actor_system&, const actor_system_config&); + +protected: + virtual std::string make_help_text(const std::vector&); + + config_option_set custom_options_; + +private: + template + void add_message_type_impl(std::string name) { + type_names_by_rtti.emplace(std::type_index(typeid(T)), name); + value_factories_by_name.emplace(std::move(name), &make_type_erased_value); + value_factories_by_rtti.emplace(std::type_index(typeid(T)), + &make_type_erased_value); + } + + actor_system_config& set_impl(string_view name, config_value value); + + static std::string render_sec(uint8_t, atom_value, const message&); + + static std::string render_exit_reason(uint8_t, atom_value, const message&); + + void extract_config_file_path(string_list& args); +}; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/actor_system.hpp actor-framework-0.16.3/libcaf_core/caf/actor_system.hpp --- actor-framework-0.13.2/libcaf_core/caf/actor_system.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/actor_system.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,639 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "caf/abstract_actor.hpp" +#include "caf/actor_cast.hpp" +#include "caf/actor_clock.hpp" +#include "caf/actor_config.hpp" +#include "caf/actor_marker.hpp" +#include "caf/actor_registry.hpp" +#include "caf/composable_behavior_based_actor.hpp" +#include "caf/detail/init_fun_factory.hpp" +#include "caf/detail/spawn_fwd.hpp" +#include "caf/detail/spawnable.hpp" +#include "caf/fwd.hpp" +#include "caf/group_manager.hpp" +#include "caf/infer_handle.hpp" +#include "caf/is_typed_actor.hpp" +#include "caf/logger.hpp" +#include "caf/make_actor.hpp" +#include "caf/prohibit_top_level_spawn_marker.hpp" +#include "caf/runtime_settings_map.hpp" +#include "caf/scoped_execution_unit.hpp" +#include "caf/spawn_options.hpp" +#include "caf/string_algorithms.hpp" +#include "caf/uniform_type_info_map.hpp" + +namespace caf { + +using rtti_pair = std::pair; + +using rtti_pair_vec = std::vector; + +using rtti_pair_vec_triple = std::tuple; + +template +struct mpi_field_access { + std::string operator()(const uniform_type_info_map& types) { + auto nr = type_nr::value; + if (nr != 0) + return *types.portable_name(nr, nullptr); + auto ptr = types.portable_name(0, &typeid(T)); + if (ptr != nullptr) + return *ptr; + std::string result = " +struct mpi_field_access> { + std::string operator()(const uniform_type_info_map&) { + return to_string(X); + } +}; + +template <> +struct mpi_field_access { + std::string operator()(const uniform_type_info_map&) { + return "void"; + } +}; +template +std::string get_mpi_field(const uniform_type_info_map& types) { + mpi_field_access f; + return f(types); +} + +template +struct typed_mpi_access; + +template +struct typed_mpi_access, + output_tuple>> { + std::string operator()(const uniform_type_info_map& types) const { + static_assert(sizeof...(Is) > 0, "typed MPI without inputs"); + static_assert(sizeof...(Ls) > 0, "typed MPI without outputs"); + std::vector inputs{get_mpi_field(types)...}; + std::vector outputs1{get_mpi_field(types)...}; + std::string result = "caf::replies_to<"; + result += join(inputs, ","); + result += ">::with<"; + result += join(outputs1, ","); + result += ">"; + return result; + } +}; + +template +std::string get_rtti_from_mpi(const uniform_type_info_map& types) { + typed_mpi_access f; + return f(types); +} + +/// Actor environment including scheduler, registry, and optional components +/// such as a middleman. +class actor_system { +public: + friend class logger; + friend class io::middleman; + friend class abstract_actor; + + /// The number of actors implictly spawned by the actor system on startup. + static constexpr size_t num_internal_actors = 2; + + /// Returns the ID of an internal actor by its name. + /// @pre x in {'SpawnServ', 'ConfigServ', 'StreamServ'} + static constexpr size_t internal_actor_id(atom_value x) { + return x == atom("SpawnServ") ? 0 : (x == atom("ConfigServ") ? 1 : 2); + } + + /// Returns the internal actor for dynamic spawn operations. + const strong_actor_ptr& spawn_serv() const { + return internal_actors_[internal_actor_id(atom("SpawnServ"))]; + } + + /// Returns the internal actor for storing the runtime configuration + /// for this actor system. + const strong_actor_ptr& config_serv() const { + return internal_actors_[internal_actor_id(atom("ConfigServ"))]; + } + + actor_system() = delete; + actor_system(const actor_system&) = delete; + actor_system& operator=(const actor_system&) = delete; + + /// An (optional) component of the actor system. + class module { + public: + enum id_t { + scheduler, + middleman, + opencl_manager, + openssl_manager, + num_ids + }; + + virtual ~module(); + + /// Returns the human-redable name of the module. + const char* name() const noexcept; + + /// Starts any background threads needed by the module. + virtual void start() = 0; + + /// Stops all background threads of the module. + virtual void stop() = 0; + + /// Allows the module to change the + /// configuration of the actor system during startup. + virtual void init(actor_system_config&) = 0; + + /// Returns the identifier of this module. + virtual id_t id() const = 0; + + /// Returns a pointer to the subtype. + virtual void* subtype_ptr() = 0; + }; + + using module_ptr = std::unique_ptr; + + using module_array = std::array; + + /// @warning The system stores a reference to `cfg`, which means the + /// config object must outlive the actor system. + explicit actor_system(actor_system_config& cfg); + + virtual ~actor_system(); + + /// A message passing interface (MPI) in run-time checkable representation. + using mpi = std::set; + + template ::value>::type> + mpi message_types(detail::type_list) const { + return mpi{}; + } + + template + mpi message_types(detail::type_list>) const { + static_assert(sizeof...(Ts) > 0, "empty typed actor handle given"); + mpi result{get_rtti_from_mpi(types())...}; + return result; + } + + template ::value>::type> + mpi message_types(const T&) const { + detail::type_list token; + return message_types(token); + } + + /// Returns a string representation of the messaging + /// interface using portable names; + template + mpi message_types() const { + detail::type_list token; + return message_types(token); + } + + /// Returns whether actor handles described by `xs` + /// can be assigned to actor handles described by `ys`. + /// @experimental + bool assignable(const mpi& xs, const mpi& ys) const { + if (ys.empty()) + return xs.empty(); + if (xs.size() == ys.size()) + return xs == ys; + return std::includes(xs.begin(), xs.end(), ys.begin(), ys.end()); + } + + /// Returns whether actor handles described by `xs` + /// can be assigned to actor handles of type `T`. + /// @experimental + template + bool assignable(const std::set& xs) const { + return assignable(xs, message_types()); + } + + /// Returns the host-local identifier for this system. + const node_id& node() const; + + /// Returns the scheduler instance. + scheduler::abstract_coordinator& scheduler(); + + /// Returns the system-wide event logger. + caf::logger& logger(); + + /// Returns the system-wide actor registry. + actor_registry& registry(); + + /// Returns the system-wide factory for custom types and actors. + const uniform_type_info_map& types() const; + + /// Returns a string representation for `err`. + std::string render(const error& x) const; + + /// Returns the system-wide group manager. + group_manager& groups(); + + /// Returns `true` if the I/O module is available, `false` otherwise. + bool has_middleman() const; + + /// Returns the middleman instance from the I/O module. + /// @throws `std::logic_error` if module is not loaded. + io::middleman& middleman(); + + /// Returns `true` if the opencl module is available, `false` otherwise. + bool has_opencl_manager() const; + + /// Returns the manager instance from the OpenCL module. + /// @throws `std::logic_error` if module is not loaded. + opencl::manager& opencl_manager() const; + + /// Returns `true` if the openssl module is available, `false` otherwise. + bool has_openssl_manager() const; + + /// Returns the manager instance from the OpenSSL module. + /// @throws `std::logic_error` if module is not loaded. + openssl::manager& openssl_manager() const; + + /// Returns a dummy execution unit that forwards + /// everything to the scheduler. + scoped_execution_unit* dummy_execution_unit(); + + /// Returns a new actor ID. + actor_id next_actor_id(); + + /// Returns the last given actor ID. + actor_id latest_actor_id() const; + + /// Blocks this caller until all actors are done. + void await_all_actors_done() const; + + /// Called by `spawn` when used to create a class-based actor to + /// apply automatic conversions to `xs` before spawning the actor. + /// Should not be called by users of the library directly. + /// @param cfg To-be-filled config for the actor. + /// @param xs Constructor arguments for `C`. + template + infer_handle_from_class_t + spawn_class(actor_config& cfg, Ts&&... xs) { + return spawn_impl(cfg, detail::spawn_fwd(xs)...); + } + + /// Returns a new actor of type `C` using `xs...` as constructor + /// arguments. The behavior of `spawn` can be modified by setting `Os`, e.g., + /// to opt-out of the cooperative scheduling. + /// @param xs Constructor arguments for `C`. + template + infer_handle_from_class_t spawn(Ts&&... xs) { + check_invariants(); + actor_config cfg; + return spawn_impl(cfg, detail::spawn_fwd(xs)...); + } + + template + infer_handle_from_state_t spawn() { + return spawn, Os>(); + } + + /// Called by `spawn` when used to create a functor-based actor to select a + /// proper implementation and then delegates to `spawn_impl`. + /// @param cfg To-be-filled config for the actor. + /// @param fun Function object for the actor's behavior; will be moved. + /// @param xs Arguments for `fun`. + /// @private + template + infer_handle_from_fun_t spawn_functor(std::true_type, actor_config& cfg, + F& fun, Ts&&... xs) { + using impl = infer_impl_from_fun_t; + detail::init_fun_factory fac; + cfg.init_fun = fac(std::move(fun), std::forward(xs)...); + return spawn_impl(cfg); + } + + /// Fallback no-op overload. + /// @private + template + infer_handle_from_fun_t spawn_functor(std::false_type, actor_config&, F&, + Ts&&...) { + return {}; + } + + /// Returns a new functor-based actor. The first argument must be the functor, + /// the remainder of `xs...` is used to invoke the functor. + /// The behavior of `spawn` can be modified by setting `Os`, e.g., + /// to opt-out of the cooperative scheduling. + template + infer_handle_from_fun_t + spawn(F fun, Ts&&... xs) { + using impl = infer_impl_from_fun_t; + check_invariants(); + static constexpr bool spawnable = detail::spawnable(); + static_assert(spawnable, + "cannot spawn function-based actor with given arguments"); + actor_config cfg; + return spawn_functor(detail::bool_token{}, cfg, fun, + std::forward(xs)...); + } + + /// Returns a new actor with run-time type `name`, constructed + /// with the arguments stored in `args`. + /// @experimental + template ::value>::type> + expected spawn(const std::string& name, message args, + execution_unit* ctx = nullptr, + bool check_interface = true, + const mpi* expected_ifs = nullptr) { + mpi tmp; + if (check_interface && !expected_ifs) { + tmp = message_types(); + expected_ifs = &tmp; + } + auto res = dyn_spawn_impl(name, args, ctx, check_interface, expected_ifs); + if (!res) + return std::move(res.error()); + return actor_cast(std::move(*res)); + } + + /// Spawns a class-based actor `T` immediately joining the groups in + /// range `[first, last)`. + /// @private + template + infer_handle_from_class_t + spawn_class_in_groups(actor_config& cfg, Iter first, Iter last, Ts&&... xs) { + static_assert(std::is_same, actor>::value, + "only dynamically-typed actors can be spawned in a group"); + check_invariants(); + auto irange = make_input_range(first, last); + cfg.groups = &irange; + return spawn_class(cfg, std::forward(xs)...); + } + + /// Spawns a class-based actor `T` immediately joining the groups in + /// range `[first, last)`. + /// @private + template + infer_handle_from_fun_t + spawn_fun_in_groups(actor_config& cfg, Iter first, Iter second, + F& fun, Ts&&... xs) { + using impl = infer_impl_from_fun_t; + check_invariants(); + static constexpr bool dynamically_typed = is_dynamically_typed::value; + static_assert(dynamically_typed, + "only dynamically-typed actors can join groups"); + static constexpr bool spawnable = detail::spawnable(); + static_assert(spawnable, + "cannot spawn function-based actor with given arguments"); + static constexpr bool enabled = dynamically_typed && spawnable; + auto irange = make_input_range(first, second); + cfg.groups = &irange; + return spawn_functor(detail::bool_token{}, cfg, fun, + std::forward(xs)...); + } + + /// Returns a new functor-based actor subscribed to all groups in `gs`. + template + infer_handle_from_fun_t + spawn_in_groups(std::initializer_list gs, F fun, Ts&&... xs) { + actor_config cfg; + return spawn_fun_in_groups(cfg, gs.begin(), gs.end(), fun, + std::forward(xs)...); + } + + /// Returns a new functor-based actor subscribed to all groups in `gs`. + template + infer_handle_from_fun_t + spawn_in_groups(const Gs& gs, F fun, Ts&&... xs) { + actor_config cfg; + return spawn_fun_in_groups(cfg, gs.begin(), gs.end(), fun, + std::forward(xs)...); + } + + /// Returns a new functor-based actor subscribed to all groups in `gs`. + template + infer_handle_from_fun_t + spawn_in_group(const group& grp, F fun, Ts&&... xs) { + return spawn_in_groups({grp}, std::move(fun), + std::forward(xs)...); + } + + /// Returns a new class-based actor subscribed to all groups in `gs`. + template + infer_handle_from_class_t + spawn_in_groups(std::initializer_list gs, Ts&&... xs) { + actor_config cfg; + return spawn_class_in_groups(cfg, gs.begin(), gs.end(), + std::forward(xs)...); + } + + /// Returns a new class-based actor subscribed to all groups in `gs`. + template + infer_handle_from_class_t + spawn_in_groups(const Gs& gs, Ts&&... xs) { + actor_config cfg; + return spawn_class_in_groups(cfg, gs.begin(), gs.end(), + std::forward(xs)...); + } + + /// Returns a new class-based actor subscribed to all groups in `gs`. + template + infer_handle_from_class_t + spawn_in_group(const group& grp, Ts&&... xs) { + return spawn_in_groups({grp}, std::forward(xs)...); + } + + /// Returns whether this actor system calls `await_all_actors_done` + /// in its destructor before shutting down. + bool await_actors_before_shutdown() const { + return await_actors_before_shutdown_; + } + + /// Configures whether this actor system calls `await_all_actors_done` + /// in its destructor before shutting down. + void await_actors_before_shutdown(bool x) { + await_actors_before_shutdown_ = x; + } + + /// Returns the configuration of this actor system. + const actor_system_config& config() const { + return cfg_; + } + + /// Returns the system-wide clock. + actor_clock& clock() noexcept; + + /// Returns application-specific, system-wide runtime settings. + runtime_settings_map& runtime_settings() { + return settings_; + } + + /// Returns application-specific, system-wide runtime settings. + const runtime_settings_map& runtime_settings() const { + return settings_; + } + + /// Returns the number of detached actors. + size_t detached_actors() { + return detached_.load(); + } + + /// @cond PRIVATE + + /// Increases running-detached-threads-count by one. + void inc_detached_threads(); + + /// Decreases running-detached-threads-count by one. + void dec_detached_threads(); + + /// Blocks the caller until all detached threads are done. + void await_detached_threads(); + + /// Calls all thread started hooks + /// @warning must be called by thread which is about to start + void thread_started(); + + /// Calls all thread terminates hooks + /// @warning must be called by thread which is about to terminate + void thread_terminates(); + + template + infer_handle_from_class_t + spawn_impl(actor_config& cfg, Ts&&... xs) { + static_assert(is_unbound(Os), + "top-level spawns cannot have monitor or link flag"); + // TODO: use `if constexpr` when switching to C++17 + if (has_detach_flag(Os) || std::is_base_of::value) + cfg.flags |= abstract_actor::is_detached_flag; + if (has_hide_flag(Os)) + cfg.flags |= abstract_actor::is_hidden_flag; + if (cfg.host == nullptr) + cfg.host = dummy_execution_unit(); + CAF_SET_LOGGER_SYS(this); + auto res = make_actor(next_actor_id(), node(), this, + cfg, std::forward(xs)...); + auto ptr = static_cast(actor_cast(res)); + ptr->launch(cfg.host, has_lazy_init_flag(Os), has_hide_flag(Os)); + return res; + } + + /// @endcond + +private: + template + void check_invariants() { + static_assert(!std::is_base_of::value, + "This actor type cannot be spawned throught an actor system. " + "Probably you have tried to spawn a broker or opencl actor."); + } + + expected dyn_spawn_impl(const std::string& name, + message& args, + execution_unit* ctx, + bool check_interface, + optional expected_ifs); + + /// Sets the internal actor for dynamic spawn operations. + void spawn_serv(strong_actor_ptr x) { + internal_actors_[internal_actor_id(atom("SpawnServ"))] = std::move(x); + } + + /// Sets the internal actor for storing the runtime configuration. + void config_serv(strong_actor_ptr x) { + internal_actors_[internal_actor_id(atom("ConfigServ"))] = std::move(x); + } + + // -- member variables ------------------------------------------------------- + + /// Used to generate ascending actor IDs. + std::atomic ids_; + + /// Stores runtime type information for builtin and user-defined types. + uniform_type_info_map types_; + + /// Identifies this actor system in a distributed setting. + node_id node_; + + /// Manages log output. + intrusive_ptr logger_; + + /// Maps well-known actor names to actor handles. + actor_registry registry_; + + /// Maps well-known group names to group handles. + group_manager groups_; + + /// Stores optional actor system components. + module_array modules_; + + /// Provides pseudo scheduling context to actors. + scoped_execution_unit dummy_execution_unit_; + + /// Stores whether the system should wait for running actors on shutdown. + bool await_actors_before_shutdown_; + + /// Stores SpawnServ, ConfigServ, and StreamServ. + std::array internal_actors_; + + /// Counts the number of detached actors. + std::atomic detached_; + + /// Guards `detached`. + mutable std::mutex detached_mtx_; + + /// Allows waiting on specific values for `detached`. + mutable std::condition_variable detached_cv_; + + /// The system-wide, user-provided configuration. + actor_system_config& cfg_; + + /// Stores whether the logger has run its destructor and stopped any thread, + /// file handle, etc. + std::atomic logger_dtor_done_; + + /// Guards `logger_dtor_done_`. + mutable std::mutex logger_dtor_mtx_; + + /// Allows waiting on specific values for `logger_dtor_done_`. + mutable std::condition_variable logger_dtor_cv_; + + /// Stores custom, system-wide key-value pairs. + runtime_settings_map settings_; +}; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/after.hpp actor-framework-0.16.3/libcaf_core/caf/after.hpp --- actor-framework-0.13.2/libcaf_core/caf/after.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/after.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,56 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include + +#include "caf/timeout_definition.hpp" + +namespace caf { + +class timeout_definition_builder { +public: + constexpr timeout_definition_builder(duration d) : tout_(d) { + // nop + } + + template + timeout_definition operator>>(F f) const { + return {tout_, std::move(f)}; + } + +private: + duration tout_; +}; + +/// Returns a generator for timeouts. +constexpr timeout_definition_builder after(duration d) { + return {d}; +} + +/// Returns a generator for timeouts. +template +constexpr timeout_definition_builder +after(std::chrono::duration d) { + return after(duration{d}); +} + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/all.hpp actor-framework-0.16.3/libcaf_core/caf/all.hpp --- actor-framework-0.13.2/libcaf_core/caf/all.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/all.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,32 +16,34 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_ALL_HPP -#define CAF_ALL_HPP +#pragma once -#include "caf/on.hpp" +#include "caf/config.hpp" + +#include "caf/sec.hpp" #include "caf/atom.hpp" #include "caf/send.hpp" +#include "caf/skip.hpp" #include "caf/unit.hpp" +#include "caf/term.hpp" #include "caf/actor.hpp" +#include "caf/after.hpp" +#include "caf/error.hpp" #include "caf/group.hpp" -#include "caf/spawn.hpp" -#include "caf/config.hpp" -#include "caf/either.hpp" #include "caf/extend.hpp" -#include "caf/channel.hpp" +#include "caf/logger.hpp" +#include "caf/others.hpp" +#include "caf/result.hpp" +#include "caf/stream.hpp" #include "caf/message.hpp" #include "caf/node_id.hpp" -#include "caf/announce.hpp" -#include "caf/anything.hpp" #include "caf/behavior.hpp" +#include "caf/defaults.hpp" #include "caf/duration.hpp" -#include "caf/sb_actor.hpp" -#include "caf/shutdown.hpp" -#include "caf/exception.hpp" +#include "caf/expected.hpp" +#include "caf/exec_main.hpp" #include "caf/resumable.hpp" -#include "caf/scheduler.hpp" -#include "caf/spawn_fwd.hpp" +#include "caf/streambuf.hpp" #include "caf/to_string.hpp" #include "caf/actor_addr.hpp" #include "caf/actor_pool.hpp" @@ -50,27 +51,36 @@ #include "caf/message_id.hpp" #include "caf/replies_to.hpp" #include "caf/serializer.hpp" +#include "caf/actor_clock.hpp" #include "caf/actor_proxy.hpp" #include "caf/exit_reason.hpp" -#include "caf/from_string.hpp" #include "caf/local_actor.hpp" +#include "caf/raise_error.hpp" #include "caf/ref_counted.hpp" +#include "caf/stream_slot.hpp" +#include "caf/thread_hook.hpp" #include "caf/typed_actor.hpp" +#include "caf/actor_system.hpp" +#include "caf/config_value.hpp" #include "caf/deserializer.hpp" #include "caf/scoped_actor.hpp" -#include "caf/skip_message.hpp" +#include "caf/upstream_msg.hpp" #include "caf/actor_ostream.hpp" +#include "caf/config_option.hpp" +#include "caf/function_view.hpp" +#include "caf/index_mapping.hpp" #include "caf/spawn_options.hpp" #include "caf/abstract_actor.hpp" #include "caf/abstract_group.hpp" #include "caf/blocking_actor.hpp" +#include "caf/deep_to_string.hpp" #include "caf/execution_unit.hpp" #include "caf/memory_managed.hpp" +#include "caf/stateful_actor.hpp" #include "caf/typed_behavior.hpp" -#include "caf/actor_namespace.hpp" +#include "caf/proxy_registry.hpp" +#include "caf/downstream_msg.hpp" #include "caf/behavior_policy.hpp" -#include "caf/continue_helper.hpp" -#include "caf/mailbox_element.hpp" #include "caf/message_builder.hpp" #include "caf/message_handler.hpp" #include "caf/response_handle.hpp" @@ -78,300 +88,323 @@ #include "caf/abstract_channel.hpp" #include "caf/may_have_timeout.hpp" #include "caf/message_priority.hpp" -#include "caf/response_promise.hpp" +#include "caf/typed_actor_view.hpp" #include "caf/binary_serializer.hpp" +#include "caf/composed_behavior.hpp" #include "caf/event_based_actor.hpp" #include "caf/primitive_variant.hpp" -#include "caf/uniform_type_info.hpp" +#include "caf/make_config_option.hpp" #include "caf/timeout_definition.hpp" +#include "caf/actor_system_config.hpp" #include "caf/binary_deserializer.hpp" -#include "caf/await_all_actors_done.hpp" -#include "caf/typed_continue_helper.hpp" +#include "caf/composable_behavior.hpp" +#include "caf/config_option_adder.hpp" +#include "caf/typed_actor_pointer.hpp" +#include "caf/scoped_execution_unit.hpp" +#include "caf/typed_response_promise.hpp" #include "caf/typed_event_based_actor.hpp" +#include "caf/fused_downstream_manager.hpp" +#include "caf/abstract_composable_behavior.hpp" + +#include "caf/decorator/sequencer.hpp" -/** - * @author Dominik Charousset - * - * @mainpage libcaf - * - * @section Intro Introduction - * - * This library provides an implementation of the actor model for C++. - * It uses a network transparent messaging system to ease development - * of both concurrent and distributed software. - * - * `libcaf` uses a thread pool to schedule actors by default. - * A scheduled actor should not call blocking functions. - * Individual actors can be spawned (created) with a special flag to run in - * an own thread if one needs to make use of blocking APIs. - * - * Writing applications in `libcaf` requires a minimum of gluecode and - * each context is an actor. Even main is implicitly - * converted to an actor if needed. - * - * @section GettingStarted Getting Started - * - * To build `libcaf,` you need `GCC >= 4.7 or Clang >= - *3.2, - * and `CMake`. - * - * The usual build steps on Linux and Mac OS X are: - * - *- `mkdir build - *- `cd build - *- `cmake .. - *- `make - *- `make install (as root, optionally) - * - * Please run the unit tests as well to verify that `libcaf` - * works properly. - * - *- `./bin/unit_tests - * - * Please submit a bug report that includes (a) your compiler version, - * (b) your OS, and (c) the output of the unit tests if an error occurs. - * - * Windows is not supported yet, because MVSC++ doesn't implement the - * C++11 features needed to compile `libcaf`. - * - * Please read the Manual for an introduction to `libcaf`. - * It is available online as HTML at - * http://neverlord.github.com/libcaf/manual/index.html or as PDF at - * http://neverlord.github.com/libcaf/manual/manual.pdf - * - * @section IntroHelloWorld Hello World Example - * - * @include hello_world.cpp - * - * @section IntroMoreExamples More Examples - * - * The {@link math_actor.cpp Math Actor Example} shows the usage - * of {@link receive_loop} and {@link caf::arg_match arg_match}. - * The {@link dining_philosophers.cpp Dining Philosophers Example} - * introduces event-based actors and includes a lot of `libcaf - * features. - * - * @namespace caf - * Root namespace of libcaf. - * - * @namespace caf::mixin - * Contains mixin classes implementing several actor traits. - * - * @namespace caf::exit_reason - * Contains all predefined exit reasons. - * - * @namespace caf::policy - * Contains policies encapsulating characteristics or algorithms. - * - * @namespace caf::io - * Contains all network-related classes and functions. - * - * @defgroup MessageHandling Message handling. - * - * This is the beating heart of `libcaf`. Actor programming is - * all about message handling. - * - * A message in `libcaf` is a n-tuple of values (with size >= 1) - * You can use almost every type in a messages - as long as it is announced, - * i.e., known by the type system of `libcaf`. - * - * @defgroup BlockingAPI Blocking API. - * - * Blocking functions to receive messages. - * - * The blocking API of libcaf is intended to be used for migrating - * previously threaded applications. When writing new code, you should use - * ibcafs nonblocking become/unbecome API. - * - * @section Send Send messages - * - * The function `send` can be used to send a message to an actor. - * The first argument is the receiver of the message followed by any number - * of values: - * - * @code - * // spawn some actors - * auto a1 = spawn(...); - * auto a2 = spawn(...); - * auto a3 = spawn(...); - * - * // send a message to a1 - * send(a1, atom("hello"), "hello a1!"); - * - * // send a message to a1, a2, and a3 - * auto msg = make_message(atom("compute"), 1, 2, 3); - * send(a1, msg); - * send(a2, msg); - * send(a3, msg); - * @endcode - * - * @section Receive Receive messages - * - * The function `receive` takes a `behavior` as argument. The behavior - * is a list of { pattern >> callback } rules. - * - * @code - * receive - * ( - * on(atom("hello"), arg_match) >> [](const std::string& msg) - * { - * cout << "received hello message: " << msg << endl; - * }, - * on(atom("compute"), arg_match) >> [](int i0, int i1, int i2) - * { - * // send our result back to the sender of this messages - * return make_message(atom("result"), i0 + i1 + i2); - * } - * ); - * @endcode - * - * Please read the manual for further details about pattern matching. - * - * @section Atoms Atoms - * - * Atoms are a nice way to add semantic informations to a message. - * Assuming an actor wants to provide a "math sevice" for integers. It - * could provide operations such as addition, subtraction, etc. - * This operations all have two operands. Thus, the actor does not know - * what operation the sender of a message wanted by receiving just two integers. - * - * Example actor: - * @code - * void math_actor() { - * receive_loop ( - * on(atom("plus"), arg_match) >> [](int a, int b) { - * return make_message(atom("result"), a + b); - * }, - * on(atom("minus"), arg_match) >> [](int a, int b) { - * return make_message(atom("result"), a - b); - * } - * ); - * } - * @endcode - * - * @section ReceiveLoops Receive loops - * - * Previous examples using `receive` create behaviors on-the-fly. - * This is inefficient in a loop since the argument passed to receive - * is created in each iteration again. It's possible to store the behavior - * in a variable and pass that variable to receive. This fixes the issue - * of re-creation each iteration but rips apart definition and usage. - * - * There are four convenience functions implementing receive loops to - * declare behavior where it belongs without unnecessary - * copies: `receive_loop,` `receive_while,` `receive_for` and `do_receive`. - * - * `receive_loop` is analogous to `receive` and loops "forever" (until the - * actor finishes execution). - * - * `receive_while` creates a functor evaluating a lambda expression. - * The loop continues until the given lambda returns `false`. A simple example: - * - * @code - * // receive two integers - * vector received_values; - * receive_while([&]() { return received_values.size() < 2; }) ( - * on() >> [](int value) { - * received_values.push_back(value); - * } - * ); - * // ... - * @endcode - * - * `receive_for` is a simple ranged-based loop: - * - * @code - * std::vector vec {1, 2, 3, 4}; - * auto i = vec.begin(); - * receive_for(i, vec.end()) ( - * on(atom("get")) >> [&]() -> message { return {atom("result"), *i}; } - * ); - * @endcode - * - * `do_receive` returns a functor providing the function `until` that - * takes a lambda expression. The loop continues until the given lambda - * returns true. Example: - * - * @code - * // receive ints until zero was received - * vector received_values; - * do_receive ( - * on() >> [](int value) { - * received_values.push_back(value); - * } - * ) - * .until([&]() { return received_values.back() == 0 }); - * // ... - * @endcode - * - * @section FutureSend Send delayed messages - * - * The function `delayed_send` provides a simple way to delay a message. - * This is particularly useful for recurring events, e.g., periodical polling. - * Usage example: - * - * @code - * delayed_send(self, std::chrono::seconds(1), atom("poll")); - * receive_loop ( - * // ... - * on(atom("poll")) >> [] { - * // ... poll something ... - * // and do it again after 1sec - * delayed_send(self, std::chrono::seconds(1), atom("poll")); - * } - * ); - * @endcode - * - * See also the {@link dancing_kirby.cpp dancing kirby example}. - * - * @defgroup ImplicitConversion Implicit type conversions. - * - * The message passing of `libcaf` prohibits pointers in messages because - * it enforces network transparent messaging. - * Unfortunately, string literals in `C++` have the type `const char*, - * resp. `const char[]. Since `libcaf` is a user-friendly library, - * it silently converts string literals and C-strings to `std::string` objects. - * It also converts unicode literals to the corresponding STL container. - * - * A few examples: - * @code - * // sends an std::string containing "hello actor!" to itself - * send(self, "hello actor!"); - * - * const char* cstring = "cstring"; - * // sends an std::string containing "cstring" to itself - * send(self, cstring); - * - * // sends an std::u16string containing the UTF16 string "hello unicode world!" - * send(self, u"hello unicode world!"); - * - * // x has the type caf::tuple - * auto x = make_message("hello", "tuple"); - * - * receive ( - * // equal to: on(std::string("hello actor!")) - * on("hello actor!") >> [] { } - * ); - * @endcode - * - * @defgroup ActorCreation Actor creation. - */ +#include "caf/meta/type_name.hpp" +#include "caf/meta/annotation.hpp" +#include "caf/meta/save_callback.hpp" +#include "caf/meta/load_callback.hpp" +#include "caf/meta/omittable_if_empty.hpp" + +#include "caf/scheduler/test_coordinator.hpp" +#include "caf/scheduler/abstract_coordinator.hpp" + +/// +/// @mainpage CAF +/// +/// @section Intro Introduction +/// +/// This library provides an implementation of the actor model for C++. +/// It uses a network transparent messaging system to ease development +/// of both concurrent and distributed software. +/// +/// `libcaf` uses a thread pool to schedule actors by default. +/// A scheduled actor should not call blocking functions. +/// Individual actors can be spawned (created) with a special flag to run in +/// an own thread if one needs to make use of blocking APIs. +/// +/// Writing applications in `libcaf` requires a minimum of gluecode and +/// each context is an actor. Scoped actors allow actor interaction +/// from the context of threads such as main. +/// +/// @section GettingStarted Getting Started +/// +/// To build `libcaf,` you need `GCC >= 4.8 or Clang >= 3.2, +/// and `CMake`. +/// +/// The usual build steps on Linux and macOS are: +/// +///- `./configure +///- `make +///- `make install (as root, optionally) +/// +/// Please run the unit tests as well to verify that `libcaf` +/// works properly. +/// +///- `make test +/// +/// Please submit a bug report that includes (a) your compiler version, +/// (b) your OS, and (c) the output of the unit tests if an error occurs: +/// https://github.com/actor-framework/actor-framework/issues +/// +/// Please read the Manual for an introduction to `libcaf`. +/// It is available online on Read The Docs at +/// https://actor-framework.readthedocs.io or as PDF at +/// http://www.actor-framework.org/pdf/manual.pdf +/// +/// @section IntroHelloWorld Hello World Example +/// +/// @include hello_world.cpp +/// +/// @section IntroMoreExamples More Examples +/// +/// The {@link math_actor.cpp Math Actor Example} shows the usage +/// of {@link receive_loop} and {@link caf::arg_match arg_match}. +/// The {@link dining_philosophers.cpp Dining Philosophers Example} +/// introduces event-based actors covers various features of CAF. +/// +/// @namespace caf +/// Root namespace of libcaf. +/// +/// @namespace caf::mixin +/// Contains mixin classes implementing several actor traits. +/// +/// @namespace caf::exit_reason +/// Contains all predefined exit reasons. +/// +/// @namespace caf::policy +/// Contains policies encapsulating characteristics or algorithms. +/// +/// @namespace caf::io +/// Contains all IO-related classes and functions. +/// +/// @namespace caf::io::network +/// Contains classes and functions used for network abstraction. +/// +/// @namespace caf::io::basp +/// Contains all classes and functions for the Binary Actor Sytem Protocol. +/// +/// @defgroup MessageHandling Message Handling +/// +/// This is the beating heart of CAF, since actor programming is +/// a message oriented programming paradigm. +/// +/// A message in CAF is a n-tuple of values (with size >= 1). +/// You can use almost every type in a messages as long as it is announced, +/// i.e., known by the type system of CAF. +/// +/// @defgroup BlockingAPI Blocking API +/// +/// Blocking functions to receive messages. +/// +/// The blocking API of CAF is intended to be used for migrating +/// previously threaded applications. When writing new code, you should +/// consider the nonblocking API based on `become` and `unbecome` first. +/// +/// @section Send Sending Messages +/// +/// The function `send` can be used to send a message to an actor. +/// The first argument is the receiver of the message followed by any number +/// of values: +/// +/// ~~ +/// // spawn some actors +/// actor_system_config cfg; +/// actor_system system{cfg}; +/// auto a1 = system.spawn(...); +/// auto a2 = system.spawn(...); +/// auto a3 = system.spawn(...); +/// +/// // an actor executed in the current thread +/// scoped_actor self{system}; +/// +/// // define an atom for message annotation +/// using hello_atom = atom_constant; +/// using compute_atom = atom_constant; +/// using result_atom = atom_constant; +/// +/// // send a message to a1 +/// self->send(a1, hello_atom::value, "hello a1!"); +/// +/// // send a message to a1, a2, and a3 +/// auto msg = make_message(compute_atom::value, 1, 2, 3); +/// self->send(a1, msg); +/// self->send(a2, msg); +/// self->send(a3, msg); +/// ~~ +/// +/// @section Receive Receive messages +/// +/// The function `receive` takes a `behavior` as argument. The behavior +/// is a list of { callback } rules where the callback argument types +/// define a pattern for matching messages. +/// +/// ~~ +/// { +/// [](hello_atom, const std::string& msg) { +/// cout << "received hello message: " << msg << endl; +/// }, +/// [](compute_atom, int i0, int i1, int i2) { +/// // send our result back to the sender of this messages +/// return make_message(result_atom::value, i0 + i1 + i2); +/// } +/// } +/// ~~ +/// +/// Blocking actors such as the scoped actor can call their receive member +/// to handle incoming messages. +/// +/// ~~ +/// self->receive( +/// [](result_atom, int i) { +/// cout << "result is: " << i << endl; +/// } +/// ); +/// ~~ +/// +/// Please read the manual for further details about pattern matching. +/// +/// @section Atoms Atoms +/// +/// Atoms are a nice way to add semantic informations to a message. +/// Assuming an actor wants to provide a "math sevice" for integers. It +/// could provide operations such as addition, subtraction, etc. +/// This operations all have two operands. Thus, the actor does not know +/// what operation the sender of a message wanted by receiving just two integers. +/// +/// Example actor: +/// ~~ +/// using plus_atom = atom_constant; +/// using minus_atom = atom_constant; +/// behavior math_actor() { +/// return { +/// [](plus_atom, int a, int b) { +/// return make_message(atom("result"), a + b); +/// }, +/// [](minus_atom, int a, int b) { +/// return make_message(atom("result"), a - b); +/// } +/// }; +/// } +/// ~~ +/// +/// @section ReceiveLoops Receive Loops +/// +/// The previous examples used `receive` to create a behavior on-the-fly. +/// This is inefficient in a loop since the argument passed to receive +/// is created in each iteration again. It's possible to store the behavior +/// in a variable and pass that variable to receive. This fixes the issue +/// of re-creation each iteration but rips apart definition and usage. +/// +/// There are three convenience functions implementing receive loops to +/// declare behavior where it belongs without unnecessary +/// copies: `receive_while,` `receive_for` and `do_receive`. +/// +/// `receive_while` creates a functor evaluating a lambda expression. +/// The loop continues until the given lambda returns `false`. A simple example: +/// +/// ~~ +/// size_t received = 0; +/// receive_while([&] { return received < 10; }) ( +/// [&](int) { +/// ++received; +/// } +/// ); +/// // ... +/// ~~ +/// +/// `receive_for` is a simple ranged-based loop: +/// +/// ~~ +/// std::vector results; +/// size_t i = 0; +/// receive_for(i, 10) ( +/// [&](int value) { +/// results.push_back(value); +/// } +/// ); +/// ~~ +/// +/// `do_receive` returns a functor providing the function `until` that +/// takes a lambda expression. The loop continues until the given lambda +/// returns true. Example: +/// +/// ~~ +/// size_t received = 0; +/// do_receive ( +/// [&](int) { +/// ++received; +/// } +/// ).until([&] { return received >= 10; }); +/// // ... +/// ~~ +/// +/// @section FutureSend Sending Delayed Messages +/// +/// The function `delayed_send` provides a simple way to delay a message. +/// This is particularly useful for recurring events, e.g., periodical polling. +/// Usage example: +/// +/// ~~ +/// scoped_actor self{...}; +/// +/// self->delayed_send(self, std::chrono::seconds(1), poll_atom::value); +/// bool running = true; +/// self->receive_while([&](){ return running; }) ( +/// // ... +/// [&](poll_atom) { +/// // ... poll something ... +/// // and do it again after 1sec +/// self->delayed_send(self, std::chrono::seconds(1), poll_atom::value); +/// } +/// ); +/// ~~ +/// +/// See also the {@link dancing_kirby.cpp dancing kirby example}. +/// +/// @defgroup ImplicitConversion Implicit Type Conversions +/// +/// The message passing of `libcaf` prohibits pointers in messages because +/// it enforces network transparent messaging. +/// Unfortunately, string literals in `C++` have the type `const char*, +/// resp. `const char[]. Since `libcaf` is a user-friendly library, +/// it silently converts string literals and C-strings to `std::string` objects. +/// It also converts unicode literals to the corresponding STL container. +/// +/// A few examples: +/// ~~ +/// // sends an std::string containing "hello actor!" to itself +/// send(self, "hello actor!"); +/// +/// const char* cstring = "cstring"; +/// // sends an std::string containing "cstring" to itself +/// send(self, cstring); +/// +/// // sends an std::u16string containing the UTF16 string "hello unicode world!" +/// send(self, u"hello unicode world!"); +/// +/// // x has the type caf::tuple +/// auto x = make_message("hello", "tuple"); +/// ~~ +/// +/// @defgroup ActorCreation Creating Actors // examples -/** - * A trivial example program. - * @example hello_world.cpp - */ - -/** - * A simple example for a delayed_send based application. - * @example dancing_kirby.cpp - */ - -/** - * An event-based "Dining Philosophers" implementation. - * @example dining_philosophers.cpp - */ +/// A trivial example program. +/// @example hello_world.cpp + +/// A simple example for a delayed_send based application. +/// @example dancing_kirby.cpp + +/// An event-based "Dining Philosophers" implementation. +/// @example dining_philosophers.cpp -#endif // CAF_ALL_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/allowed_unsafe_message_type.hpp actor-framework-0.16.3/libcaf_core/caf/allowed_unsafe_message_type.hpp --- actor-framework-0.13.2/libcaf_core/caf/allowed_unsafe_message_type.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/allowed_unsafe_message_type.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,53 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +// This file is referenced in the manual, do not modify without updating refs! +// ConfiguringActorApplications: 50-54 + +#pragma once + +#include + +namespace caf { + +/// Template specializations can whitelist individual +/// types for unsafe message passing operations. +template +struct allowed_unsafe_message_type : std::false_type {}; + +template +struct is_allowed_unsafe_message_type : allowed_unsafe_message_type {}; + +template +struct is_allowed_unsafe_message_type : allowed_unsafe_message_type {}; + +template +struct is_allowed_unsafe_message_type : allowed_unsafe_message_type {}; + +template +struct is_allowed_unsafe_message_type + : allowed_unsafe_message_type {}; + +} // namespace caf + +#define CAF_ALLOW_UNSAFE_MESSAGE_TYPE(type_name) \ + namespace caf { \ + template <> \ + struct allowed_unsafe_message_type : std::true_type {}; \ + } + diff -Nru actor-framework-0.13.2/libcaf_core/caf/announce.hpp actor-framework-0.16.3/libcaf_core/caf/announce.hpp --- actor-framework-0.13.2/libcaf_core/caf/announce.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/announce.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,148 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_ANNOUNCE_HPP -#define CAF_ANNOUNCE_HPP - -#include -#include - -#include "caf/string_algorithms.hpp" - -#include "caf/config.hpp" -#include "caf/uniform_type_info.hpp" - -#include "caf/detail/abstract_uniform_type_info.hpp" - -#include "caf/detail/safe_equal.hpp" -#include "caf/detail/default_uniform_type_info.hpp" - -namespace caf { - -/** - * @addtogroup TypeSystem - * @{ - */ - -/** - * A simple example for announce with public accessible members. - * The output of this example program is: - * > foo(1, 2)
- * > foo_pair(3, 4) - * @example announce_1.cpp - */ - -/** - * An example for announce with getter and setter member functions. - * The output of this example program is: - * - * > foo(1, 2) - * @example announce_2.cpp - */ - -/** - * An example for announce with overloaded getter and setter member functions. - * The output of this example program is: - * - * > foo(1, 2) - * @example announce_3.cpp - */ - -/** - * An example for announce with non-primitive members. - * The output of this example program is: - * - * > bar(foo(1, 2), 3) - * @example announce_4.cpp - */ - -/** - * An advanced example for announce implementing serialization - * for a user-defined tree data type. - * @example announce_5.cpp - */ - -/** - * 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, - uniform_type_info_ptr utype); - -// deals with member pointer -/** - * Creates meta information for a non-trivial `Member`, - * whereas `xs` are the "sub-members" of `Member`. - * @see {@link announce_4.cpp announce example 4} - */ -template -std::pair*> -compound_member(Member Parent::*memptr, const Ts&... xs) { - return {memptr, new detail::default_uniform_type_info("???", xs...)}; -} - -// deals with getter returning a mutable reference -/** - * Creates meta information for a non-trivial `Member` accessed - * via the getter member function `getter` returning a mutable reference, - * whereas `xs` are the "sub-members" of `Member`. - * @see {@link announce_4.cpp announce example 4} - */ -template -std::pair*> -compound_member(Member& (Parent::*getter)(), const Ts&... xs) { - return {getter, new detail::default_uniform_type_info("???", xs...)}; -} - -// deals with getter/setter pair -/** - * Creates meta information for a non-trivial `Member` accessed - * via the pair of getter and setter member function pointers `gspair`, - * whereas `xs` are the "sub-members" of `Member`. - * @see {@link announce_4.cpp announce example 4} - */ -template -std::pair, - detail::abstract_uniform_type_info::type>*> -compound_member(const std::pair& gspair, - const Ts&... xs) { - using mtype = typename std::decay::type; - return {gspair, new detail::default_uniform_type_info("???", xs...)}; -} - -/** - * Adds a new type mapping for `T` to the type system using `tname` - * as its uniform name and the list of member pointers `xs`. - * @warning `announce` is **not** thead-safe! - */ -template -inline const uniform_type_info* announce(std::string tname, const Ts&... xs) { - auto ptr = new detail::default_uniform_type_info(std::move(tname), xs...); - return announce(typeid(T), uniform_type_info_ptr{ptr}); -} - -/** - * @} - */ - -} // namespace caf - -#endif // CAF_ANNOUNCE_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/anything.hpp actor-framework-0.16.3/libcaf_core/caf/anything.hpp --- actor-framework-0.13.2/libcaf_core/caf/anything.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/anything.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_ANYTHING_HPP -#define CAF_ANYTHING_HPP - -#include - -namespace caf { - -/** - * Acts as wildcard expression in patterns. - */ -struct anything { - // no content -}; - -/** - * @relates anything - */ -inline bool operator==(const anything&, const anything&) { - return true; -} - -/** - * @relates anything - */ -inline bool operator!=(const anything&, const anything&) { - return false; -} - -/** - * @relates anything - */ -template -struct is_anything : std::is_same { - // no content -}; - -} // namespace caf - -#endif // CAF_ANYTHING_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/atom.hpp actor-framework-0.16.3/libcaf_core/caf/atom.hpp --- actor-framework-0.13.2/libcaf_core/caf/atom.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/atom.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,106 +16,198 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_ATOM_HPP -#define CAF_ATOM_HPP +#pragma once #include +#include #include #include "caf/detail/atom_val.hpp" +#include "caf/fwd.hpp" namespace caf { -/** - * The value type of atoms. - */ +/// The value type of atoms. enum class atom_value : uint64_t { - /** @cond PRIVATE */ + /// @cond PRIVATE dirty_little_hack = 31337 - /** @endcond */ + /// @endcond }; -/** - * Creates an atom from given string literal. - */ +/// @relates atom_value +std::string to_string(const atom_value& what); + +/// @relates atom_value +atom_value to_lowercase(atom_value x); + +atom_value atom_from_string(string_view x); + +/// Creates an atom from given string literal. template constexpr atom_value atom(char const (&str)[Size]) { // last character is the NULL terminator static_assert(Size <= 11, "only 10 characters are allowed"); - return static_cast(detail::atom_val(str, 0xF)); + return static_cast(detail::atom_val(str)); +} + +/// Creates an atom from given string literal and return an integer +/// representation of the atom.. +template +constexpr uint64_t atom_uint(char const (&str)[Size]) { + static_assert(Size <= 11, "only 10 characters are allowed"); + return detail::atom_val(str); } -/** - * Lifts an `atom_value` to a compile-time constant. - */ +/// Converts an atom to its integer representation. +constexpr uint64_t atom_uint(atom_value x) { + return static_cast(x); +} + +/// Lifts an `atom_value` to a compile-time constant. template struct atom_constant { constexpr atom_constant() { // nop } - /** - * Returns the wrapped value. - */ + + /// Returns the wrapped value. constexpr operator atom_value() const { return V; } - /** - * Returns an instance *of this constant* (*not* an `atom_value`). - */ + + /// Returns the wrapped value as its base type. + static constexpr uint64_t uint_value() { + return static_cast(V); + } + + /// Returns the wrapped value. + static constexpr atom_value get_value() { + return V; + } + + /// Returns an instance *of this constant* (*not* an `atom_value`). static const atom_constant value; }; +template +struct is_atom_constant { + static constexpr bool value = false; +}; + +template +struct is_atom_constant> { + static constexpr bool value = true; +}; + +template +std::string to_string(const atom_constant&) { + return to_string(V); +} + template const atom_constant atom_constant::value = atom_constant{}; -/** - * Generic 'GET' atom for request operations. - */ -using get_atom = atom_constant; - -/** - * Generic 'PUT' atom for request operations. - */ -using put_atom = atom_constant; - -/** - * Generic 'DELETE' atom for request operations. - */ -using delete_atom = atom_constant; - -/** - * Generic 'OK' atom for response messages. - */ -using ok_atom = atom_constant; - -/** - * Generic 'ERROR' atom for response messages. - */ -using error_atom = atom_constant; - -/** - * Marker 'SYS' atom for prefixing messages to a forwarding chain - * to address an otherwise transparent actor. - */ -using sys_atom = atom_constant; - -/** - * Generic 'JOIN' atom, e.g., for signaling group subscriptions. - */ -using join_atom = atom_constant; - -/** - * Generic 'LEAVE' atom, e.g., for signaling group unsubscriptions. - */ -using leave_atom = atom_constant; - -/** - * Generic 'FORWARD' atom, e.g., for signaling an actor that it - * should drop the first element and forward the remainder to - * a list of predefined receivers. - */ -using forward_atom = atom_constant; +/// Used for request operations. +using add_atom = atom_constant; + +/// Used for request operations. +using get_atom = atom_constant; + +/// Used for request operations. +using put_atom = atom_constant; + +/// Used for signalizing updates, e.g., in a key-value store. +using update_atom = atom_constant; + +/// Used for request operations. +using delete_atom = atom_constant; + +/// Used for response messages. +using ok_atom = atom_constant; + +/// Used for triggering system-level message handling. +using sys_atom = atom_constant; + +/// Used for signaling group subscriptions. +using join_atom = atom_constant; + +/// Used for signaling group unsubscriptions. +using leave_atom = atom_constant; + +/// Used for signaling forwarding paths. +using forward_atom = atom_constant; + +/// Used for buffer management. +using flush_atom = atom_constant; + +/// Used for I/O redirection. +using redirect_atom = atom_constant; + +/// Used for link requests over network. +using link_atom = atom_constant; + +/// Used for removing networked links. +using unlink_atom = atom_constant; + +/// Used for publishing actors at a given port. +using publish_atom = atom_constant; + +/// Used for publishing actors at a given port. +using publish_udp_atom = atom_constant; + +/// Used for removing an actor/port mapping. +using unpublish_atom = atom_constant; + +/// Used for removing an actor/port mapping. +using unpublish_udp_atom = atom_constant; + +/// Used for signalizing group membership. +using subscribe_atom = atom_constant; + +/// Used for withdrawing group membership. +using unsubscribe_atom = atom_constant; + +/// Used for establishing network connections. +using connect_atom = atom_constant; + +/// Used for contacting a remote UDP endpoint +using contact_atom = atom_constant; + +/// Used for opening ports or files. +using open_atom = atom_constant; + +/// Used for closing ports or files. +using close_atom = atom_constant; + +/// Used for spawning remote actors. +using spawn_atom = atom_constant; + +/// Used for migrating actors to other nodes. +using migrate_atom = atom_constant; + +/// Used for triggering periodic operations. +using tick_atom = atom_constant; + +/// Used for pending out of order messages. +using pending_atom = atom_constant; + +/// Used as timeout type for `timeout_msg`. +using receive_atom = atom_constant; + +/// Used as timeout type for `timeout_msg`. +using stream_atom = atom_constant; } // namespace caf -#endif // CAF_ATOM_HPP +namespace std { + +template <> +struct hash { + size_t operator()(caf::atom_value x) const { + hash f; + return f(static_cast(x)); + } +}; + +} // namespace std + diff -Nru actor-framework-0.13.2/libcaf_core/caf/attachable.hpp actor-framework-0.16.3/libcaf_core/caf/attachable.hpp --- actor-framework-0.13.2/libcaf_core/caf/attachable.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/attachable.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,91 +16,67 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_ATTACHABLE_HPP -#define CAF_ATTACHABLE_HPP +#pragma once #include #include #include -#include +#include "caf/error.hpp" #include "caf/optional.hpp" +#include "caf/exit_reason.hpp" +#include "caf/execution_unit.hpp" namespace caf { class abstract_actor; -/** - * Callback utility class. - */ +/// Callback utility class. class attachable { - public: +public: attachable() = default; attachable(const attachable&) = delete; attachable& operator=(const attachable&) = delete; - /** - * Represents a pointer to a value with its subtype as type ID number. - */ + /// Represents a pointer to a value with its subtype as type ID number. struct token { - /** - * Identifies a non-matchable subtype. - */ + /// Identifies a non-matchable subtype. static constexpr size_t anonymous = 0; - /** - * Identifies `abstract_group::subscription`. - */ + /// Identifies `abstract_group::subscription`. static constexpr size_t subscription = 1; - /** - * Identifies `default_attachable::observe_token`. - */ + /// Identifies `default_attachable::observe_token`. static constexpr size_t observer = 2; + /// Identifies `stream_aborter::token`. + static constexpr size_t stream_aborter = 3; + template token(const T& tk) : subtype(T::token_type), ptr(&tk) { // nop } - /** - * Denotes the type of ptr. - */ + /// Denotes the type of ptr. size_t subtype; - /** - * Any value, used to identify attachable instances. - */ + /// Any value, used to identify attachable instances. const void* ptr; - token(size_t subtype, const void* ptr); + token(size_t typenr, const void* vptr); }; virtual ~attachable(); - /** - * Executed if the actor did not handle an exception and must - * not return `none` if this attachable did handle `eptr`. - * Note that the first handler to handle `eptr` "wins" and no other - * handler will be invoked. - * @returns The exit reason the actor should use. - */ - virtual optional handle_exception(const std::exception_ptr& eptr); - - /** - * Executed if the actor finished execution with given `reason`. - * The default implementation does nothing. - */ - virtual void actor_exited(abstract_actor* self, uint32_t reason); - - /** - * Returns `true` if `what` selects this instance, otherwise `false`. - */ + /// Executed if the actor finished execution with given `reason`. + /// The default implementation does nothing. + /// @warning `host` can be `nullptr` + virtual void actor_exited(const error& fail_state, execution_unit* host); + + /// Returns `true` if `what` selects this instance, otherwise `false`. virtual bool matches(const token& what); - /** - * Returns `true` if `what` selects this instance, otherwise `false`. - */ + /// Returns `true` if `what` selects this instance, otherwise `false`. template bool matches(const T& what) { return matches(token{T::token_type, &what}); @@ -110,11 +85,8 @@ std::unique_ptr next; }; -/** - * @relates attachable - */ +/// @relates attachable using attachable_ptr = std::unique_ptr; } // namespace caf -#endif // CAF_ATTACHABLE_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/await_all_actors_done.hpp actor-framework-0.16.3/libcaf_core/caf/await_all_actors_done.hpp --- actor-framework-0.13.2/libcaf_core/caf/await_all_actors_done.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/await_all_actors_done.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_AWAIT_ALL_ACTORS_DONE_HPP -#define CAF_AWAIT_ALL_ACTORS_DONE_HPP - -#include "caf/detail/singletons.hpp" -#include "caf/detail/actor_registry.hpp" - -namespace caf { - -/** - * Blocks execution of this actor until all other actors finished execution. - * @warning This function will cause a deadlock if called from multiple actors. - * @warning Do not call this function in cooperatively scheduled actors. - */ -inline void await_all_actors_done() { - detail::singletons::get_actor_registry()->await_running_count_equal(0); -} - -} // namespace caf - -#endif // CAF_AWAIT_ALL_ACTORS_DONE_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/behavior.hpp actor-framework-0.16.3/libcaf_core/caf/behavior.hpp --- actor-framework-0.13.2/libcaf_core/caf/behavior.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/behavior.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_BEHAVIOR_HPP -#define CAF_BEHAVIOR_HPP +#pragma once #include #include @@ -36,12 +34,10 @@ class message_handler; -/** - * Describes the behavior of an actor, i.e., provides a message - * handler and an optional timeout. - */ +/// Describes the behavior of an actor, i.e., provides a message +/// handler and an optional timeout. class behavior { - public: +public: friend class message_handler; behavior() = default; @@ -50,98 +46,101 @@ behavior& operator=(behavior&&) = default; behavior& operator=(const behavior&) = default; - /** - * Creates a behavior from `fun` without timeout. - */ - behavior(const message_handler& fun); - - /** - * The list of arguments can contain match expressions, message handlers, - * and up to one timeout (if set, the timeout has to be the last argument). - */ + /// Creates a behavior from `fun` without timeout. + behavior(const message_handler& mh); + + /// The list of arguments can contain match expressions, message handlers, + /// and up to one timeout (if set, the timeout has to be the last argument). template - behavior(T x, Ts... xs) { - assign(std::move(x), std::move(xs)...); + behavior(T x, Ts&&... xs) { + assign(std::move(x), std::forward(xs)...); } - /** - * Creates a behavior from `tdef` without message handler. - */ + /// Creates a behavior from `tdef` without message handler. template - behavior(timeout_definition tdef) : m_impl(detail::make_behavior(tdef)) { + behavior(timeout_definition tdef) : impl_(detail::make_behavior(tdef)) { // nop } - /** - * Assigns new handlers. - */ + /// Assigns new handlers. template - void assign(Ts... xs) { + void assign(Ts&&... xs) { static_assert(sizeof...(Ts) > 0, "assign() called without arguments"); - m_impl = detail::make_behavior(xs...); + impl_ = detail::make_behavior(std::forward(xs)...); + } + + inline void swap(behavior& other) { + impl_.swap(other.impl_); } void assign(intrusive_ptr ptr) { - m_impl.swap(ptr); + impl_.swap(ptr); } - /** - * Equal to `*this = other`. - */ + /// Equal to `*this = other`. void assign(message_handler other); - /** - * Equal to `*this = other`. - */ + /// Equal to `*this = other`. void assign(behavior other); - /** - * Invokes the timeout callback if set. - */ + /// Invokes the timeout callback if set. inline void handle_timeout() { - m_impl->handle_timeout(); + impl_->handle_timeout(); } - /** - * Returns the duration after which receive operations - * using this behavior should time out. - */ + /// Returns the duration after which receive operations + /// using this behavior should time out. inline const duration& timeout() const { - return m_impl->timeout(); + return impl_->timeout(); } - /** - * Runs this handler and returns its (optional) result. - */ - inline optional operator()(message& arg) { - return (m_impl) ? m_impl->invoke(arg) : none; + /// Runs this handler and returns its (optional) result. + inline optional operator()(message& xs) { + return impl_ ? impl_->invoke(xs) : none; } - /** - * Checks whether this behavior is not empty. - */ + inline optional operator()(type_erased_tuple& xs) { + return impl_ ? impl_->invoke(xs) : none; + } + + /// Runs this handler with callback. + inline match_case::result operator()(detail::invoke_result_visitor& f, + type_erased_tuple& xs) { + return impl_ ? impl_->invoke(f, xs) : match_case::no_match; + } + + /// Runs this handler with callback. + inline match_case::result operator()(detail::invoke_result_visitor& f, + message& xs) { + return impl_ ? impl_->invoke(f, xs) : match_case::no_match; + } + + /// Checks whether this behavior is not empty. inline operator bool() const { - return static_cast(m_impl); + return static_cast(impl_); } - /** @cond PRIVATE */ + /// @cond PRIVATE using impl_ptr = intrusive_ptr; inline const impl_ptr& as_behavior_impl() const { - return m_impl; + return impl_; } - inline behavior(impl_ptr ptr) : m_impl(std::move(ptr)) { + inline behavior(impl_ptr ptr) : impl_(std::move(ptr)) { // nop } - /** @endcond */ + inline behavior& unbox() { + return *this; + } + + /// @endcond - private: - impl_ptr m_impl; +private: + impl_ptr impl_; }; } // namespace caf -#endif // CAF_BEHAVIOR_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/behavior_policy.hpp actor-framework-0.16.3/libcaf_core/caf/behavior_policy.hpp --- actor-framework-0.13.2/libcaf_core/caf/behavior_policy.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/behavior_policy.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_BEHAVIOR_POLICY_HPP -#define CAF_BEHAVIOR_POLICY_HPP +#pragma once namespace caf { @@ -28,13 +26,10 @@ } }; -/** - * Policy tag that causes {@link event_based_actor::become} to - * keep the current behavior available. - * @relates local_actor - */ +/// Policy tag that causes {@link event_based_actor::become} to +/// keep the current behavior available. +/// @relates local_actor constexpr keep_behavior_t keep_behavior = keep_behavior_t{}; } // namespace caf -#endif // CAF_BEHAVIOR_POLICY_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/binary_deserializer.hpp actor-framework-0.16.3/libcaf_core/caf/binary_deserializer.hpp --- actor-framework-0.13.2/libcaf_core/caf/binary_deserializer.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/binary_deserializer.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,58 +16,16 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_BINARY_DESERIALIZER_HPP -#define CAF_BINARY_DESERIALIZER_HPP +#pragma once -#include "caf/deserializer.hpp" +#include "caf/stream_deserializer.hpp" +#include "caf/streambuf.hpp" namespace caf { -/** - * Implements the deserializer interface with a binary serialization protocol. - */ -class binary_deserializer : public deserializer { - - using super = deserializer; - - public: - - binary_deserializer(const void* buf, size_t buf_size, - actor_namespace* ns = nullptr); - - binary_deserializer(const void* begin, const void* m_end, - actor_namespace* ns = nullptr); - - const uniform_type_info* begin_object() override; - void end_object() override; - size_t begin_sequence() override; - void end_sequence() override; - void read_value(primitive_variant& storage) override; - void read_raw(size_t num_bytes, void* storage) override; - - /** - * Replaces the current read buffer. - */ - void set_rdbuf(const void* buf, size_t buf_size); - - /** - * Replaces the current read buffer. - */ - void set_rdbuf(const void* begin, const void* m_end); - - private: - - const void* m_pos; - const void* m_end; - -}; - -template -inline binary_deserializer& operator>>(binary_deserializer& lhs, T& rhs) { - rhs = lhs.read(); - return lhs; -} +/// A stream serializer that writes into an unbounded contiguous character +/// sequence. +using binary_deserializer = stream_deserializer; } // namespace caf -#endif // CAF_BINARY_DESERIALIZER_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/binary_serializer.hpp actor-framework-0.16.3/libcaf_core/caf/binary_serializer.hpp --- actor-framework-0.13.2/libcaf_core/caf/binary_serializer.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/binary_serializer.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,74 +16,16 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_BINARY_SERIALIZER_HPP -#define CAF_BINARY_SERIALIZER_HPP +#pragma once -#include -#include -#include -#include -#include - -#include "caf/serializer.hpp" -#include "caf/primitive_variant.hpp" - -#include "caf/detail/ieee_754.hpp" -#include "caf/detail/type_traits.hpp" +#include "caf/stream_serializer.hpp" +#include "caf/streambuf.hpp" namespace caf { -/** - * Implements the serializer interface with a binary serialization protocol. - */ -class binary_serializer : public serializer { - - using super = serializer; - - public: - - using write_fun = std::function; - - /** - * Creates a binary serializer writing to given iterator position. - */ - template - binary_serializer(OutIter iter, actor_namespace* ns = nullptr) : super(ns) { - struct fun { - fun(OutIter pos) : m_pos(pos) {} - void operator()(const char* first, const char* last) { - m_pos = std::copy(first, last, m_pos); - } - OutIter m_pos; - }; - m_out = fun{iter}; - } - - void begin_object(const uniform_type_info* uti) override; - - void end_object() override; - - void begin_sequence(size_t list_size) override; - - void end_sequence() override; - - void write_value(const primitive_variant& value) override; - - void write_raw(size_t num_bytes, const void* data) override; - - private: - - write_fun m_out; - -}; - -template ::value>::type> -binary_serializer& operator<<(binary_serializer& bs, const T& value) { - bs.write_value(value); - return bs; -} +/// A stream serializer that writes into an unbounded contiguous character +/// sequence. +using binary_serializer = stream_serializer; } // namespace caf -#endif // CAF_BINARY_SERIALIZER_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/blocking_actor.hpp actor-framework-0.16.3/libcaf_core/caf/blocking_actor.hpp --- actor-framework-0.13.2/libcaf_core/caf/blocking_actor.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/blocking_actor.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,84 +16,200 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_BLOCKING_ACTOR_HPP -#define CAF_BLOCKING_ACTOR_HPP +#pragma once +#include #include #include -#include "caf/none.hpp" - -#include "caf/on.hpp" -#include "caf/extend.hpp" +#include "caf/actor_config.hpp" +#include "caf/actor_marker.hpp" +#include "caf/after.hpp" #include "caf/behavior.hpp" +#include "caf/extend.hpp" +#include "caf/fwd.hpp" +#include "caf/is_timeout_or_catch_all.hpp" #include "caf/local_actor.hpp" -#include "caf/typed_actor.hpp" #include "caf/mailbox_element.hpp" -#include "caf/response_handle.hpp" +#include "caf/none.hpp" +#include "caf/send.hpp" +#include "caf/typed_actor.hpp" +#include "caf/policy/arg.hpp" +#include "caf/policy/categorized.hpp" +#include "caf/policy/downstream_messages.hpp" +#include "caf/policy/normal_messages.hpp" +#include "caf/policy/upstream_messages.hpp" +#include "caf/policy/urgent_messages.hpp" + +#include "caf/detail/apply_args.hpp" +#include "caf/detail/blocking_behavior.hpp" +#include "caf/detail/type_list.hpp" #include "caf/detail/type_traits.hpp" -#include "caf/mixin/sync_sender.hpp" +#include "caf/intrusive/drr_cached_queue.hpp" +#include "caf/intrusive/drr_queue.hpp" +#include "caf/intrusive/fifo_inbox.hpp" +#include "caf/intrusive/wdrr_dynamic_multiplexed_queue.hpp" +#include "caf/intrusive/wdrr_fixed_multiplexed_queue.hpp" + +#include "caf/mixin/requester.hpp" +#include "caf/mixin/sender.hpp" +#include "caf/mixin/subscriber.hpp" namespace caf { +namespace mixin { -/** - * A thread-mapped or context-switching actor using a blocking - * receive rather than a behavior-stack based message processing. - * @extends local_actor - */ +template <> +struct is_blocking_requester : std::true_type { }; + +} // namespace caf +} // namespace mixin + +namespace caf { + +/// A thread-mapped or context-switching actor using a blocking +/// receive rather than a behavior-stack based message processing. +/// @extends local_actor class blocking_actor : public extend:: - with::impl> { - public: - class functor_based; + with, + public dynamically_typed_actor_base { +public: + // -- nested and member types ------------------------------------------------ + + /// Base type. + using super = extended_base; + + /// Stores asynchronous messages with default priority. + using normal_queue = intrusive::drr_cached_queue; + + /// Stores asynchronous messages with hifh priority. + using urgent_queue = intrusive::drr_cached_queue; + + /// Configures the FIFO inbox with two nested queues: + /// + /// 1. Default asynchronous messages + /// 2. High-priority asynchronous messages + struct mailbox_policy { + using deficit_type = size_t; + + using mapped_type = mailbox_element; - blocking_actor(); + using unique_pointer = mailbox_element_ptr; - ~blocking_actor(); + using queue_type = intrusive::wdrr_fixed_multiplexed_queue< + policy::categorized, normal_queue, urgent_queue>; - /************************************************************************** - * utility stuff and receive() member function family * - **************************************************************************/ + static constexpr size_t normal_queue_index = 0; + static constexpr size_t urgent_queue_index = 1; + }; + + /// A queue optimized for single-reader-many-writers. + using mailbox_type = intrusive::fifo_inbox; + + /// Absolute timeout type. using timeout_type = std::chrono::high_resolution_clock::time_point; + /// Supported behavior type. + using behavior_type = behavior; + + /// Declared message passing interface. + using signatures = none_t; + + // -- nested classes --------------------------------------------------------- + + /// Represents pre- and postconditions for receive loops. + class receive_cond { + public: + virtual ~receive_cond(); + + /// Returns whether a precondition for receiving a message still holds. + virtual bool pre(); + + /// Returns whether a postcondition for receiving a message still holds. + virtual bool post(); + }; + + /// Pseudo receive condition modeling a single receive. + class accept_one_cond : public receive_cond { + public: + ~accept_one_cond() override; + bool post() override; + }; + + /// Implementation helper for `blocking_actor::receive_while`. struct receive_while_helper { - std::function m_dq; - std::function m_stmt; + using fun_type = std::function; + + blocking_actor* self; + fun_type stmt_; template void operator()(Ts&&... xs) { static_assert(sizeof...(Ts) > 0, "operator() requires at least one argument"); - behavior bhvr{std::forward(xs)...}; - while (m_stmt()) m_dq(bhvr); + struct cond : receive_cond { + fun_type stmt; + cond(fun_type x) : stmt(std::move(x)) { + // nop + } + bool pre() override { + return stmt(); + } + }; + cond rc{std::move(stmt_)}; + self->varargs_receive(rc, make_message_id(), std::forward(xs)...); } }; + /// Implementation helper for `blocking_actor::receive_for`. template struct receive_for_helper { - std::function m_dq; + blocking_actor* self; T& begin; T end; template void operator()(Ts&&... xs) { - behavior bhvr{std::forward(xs)...}; - for (; begin != end; ++begin) m_dq(bhvr); + struct cond : receive_cond { + receive_for_helper& outer; + cond(receive_for_helper& x) : outer(x) { + // nop + } + bool pre() override { + return outer.begin != outer.end; + } + bool post() override { + ++outer.begin; + return true; + } + }; + cond rc{*this}; + self->varargs_receive(rc, make_message_id(), std::forward(xs)...); } }; + /// Implementation helper for `blocking_actor::do_receive`. struct do_receive_helper { - std::function m_dq; - behavior m_bhvr; + std::function cb; template void until(Statement stmt) { - do { - m_dq(m_bhvr); - } while (stmt() == false); + struct cond : receive_cond { + Statement f; + cond(Statement x) : f(std::move(x)) { + // nop + } + bool post() override { + return !f(); + } + }; + cond rc{std::move(stmt)}; + cb(rc); } void until(const bool& bvalue) { @@ -102,150 +217,241 @@ } }; - /** - * Dequeues the next message from the mailbox that is - * matched by given behavior. - */ + struct mailbox_visitor { + blocking_actor* self; + bool& done; + receive_cond& rcc; + message_id mid; + detail::blocking_behavior& bhvr; + + // Dispatches messages with high and normal priority to the same handler. + template + intrusive::task_result operator()(size_t, Queue&, mailbox_element& x) { + return (*this)(x); + } + + // Consumes `x`. + intrusive::task_result operator()(mailbox_element& x); + }; + + // -- constructors and destructors ------------------------------------------- + + blocking_actor(actor_config& cfg); + + ~blocking_actor() override; + + // -- overridden functions of abstract_actor --------------------------------- + + void enqueue(mailbox_element_ptr, execution_unit*) override; + + // -- overridden functions of local_actor ------------------------------------ + + const char* name() const override; + + void launch(execution_unit* eu, bool lazy, bool hide) override; + + // -- virtual modifiers ------------------------------------------------------ + + /// Implements the actor's behavior. + virtual void act(); + + // -- modifiers -------------------------------------------------------------- + + /// Dequeues the next message from the mailbox that is + /// matched by given behavior. template void receive(Ts&&... xs) { - static_assert(sizeof...(Ts), "at least one argument required"); - behavior bhvr{std::forward(xs)...}; - dequeue(bhvr); + accept_one_cond rc; + varargs_receive(rc, make_message_id(), std::forward(xs)...); } - /** - * Semantically equal to: `for (;;) { receive(...); }`, but does - * not cause a temporary behavior object per iteration. - */ - template - void receive_loop(Ts&&... xs) { - behavior bhvr{std::forward(xs)...}; - for (;;) dequeue(bhvr); - } - - /** - * Receives messages for range `[begin, first)`. - * Semantically equal to: - * `for ( ; begin != end; ++begin) { receive(...); }`. - * - * **Usage example:** - * ~~~ - * int i = 0; - * receive_for(i, 10) ( - * on(atom("get")) >> [&]() -> message { - * return {"result", i}; - * } - * ); - * ~~~ - */ + /// Receives messages for range `[begin, first)`. + /// Semantically equal to: + /// `for ( ; begin != end; ++begin) { receive(...); }`. + /// + /// **Usage example:** + /// ~~~ + /// int i = 0; + /// receive_for(i, 10) ( + /// [&](get_atom) { + /// return i; + /// } + /// ); + /// ~~~ template - receive_for_helper receive_for(T& begin, const T& end) { - return {make_dequeue_callback(), begin, end}; + receive_for_helper receive_for(T& begin, T end) { + return {this, begin, std::move(end)}; } - /** - * Receives messages as long as `stmt` returns true. - * Semantically equal to: `while (stmt()) { receive(...); }`. - * - * **Usage example:** - * ~~~ - * int i = 0; - * receive_while([&]() { return (++i <= 10); }) - * ( - * on() >> int_fun, - * on() >> float_fun - * ); - * ~~~ - */ - template - receive_while_helper receive_while(Statement stmt) { - static_assert(std::is_same::value, - "functor or function does not return a boolean"); - return {make_dequeue_callback(), stmt}; - } - - /** - * Receives messages until `stmt` returns true. - * - * Semantically equal to: - * `do { receive(...); } while (stmt() == false);` - * - * **Usage example:** - * ~~~ - * int i = 0; - * do_receive - * ( - * on() >> int_fun, - * on() >> float_fun - * ) - * .until([&]() { return (++i >= 10); }; - * ~~~ - */ + /// Receives messages as long as `stmt` returns true. + /// Semantically equal to: `while (stmt()) { receive(...); }`. + /// + /// **Usage example:** + /// ~~~ + /// int i = 0; + /// receive_while([&]() { return (++i <= 10); }) ( + /// ... + /// ); + /// ~~~ + receive_while_helper receive_while(std::function stmt); + + /// Receives messages as long as `ref` is true. + /// Semantically equal to: `while (ref) { receive(...); }`. + /// + /// **Usage example:** + /// ~~~ + /// bool running = true; + /// receive_while(running) ( + /// ... + /// ); + /// ~~~ + receive_while_helper receive_while(const bool& ref); + + + /// Receives messages until `stmt` returns true. + /// + /// Semantically equal to: + /// `do { receive(...); } while (stmt() == false);` + /// + /// **Usage example:** + /// ~~~ + /// int i = 0; + /// do_receive + /// ( + /// on() >> int_fun, + /// on() >> float_fun + /// ) + /// .until([&]() { return (++i >= 10); }; + /// ~~~ template do_receive_helper do_receive(Ts&&... xs) { - return {make_dequeue_callback(), behavior{std::forward(xs)...}}; + auto tup = std::make_tuple(std::forward(xs)...); + auto cb = [=](receive_cond& rc) mutable { + varargs_tup_receive(rc, make_message_id(), tup); + }; + return {cb}; } - /** - * Blocks this actor until all other actors are done. - */ + /// Blocks this actor until all other actors are done. void await_all_other_actors_done(); - /** - * Implements the actor's behavior. - */ - virtual void act() = 0; + /// Blocks this actor until all `xs...` have terminated. + template + void wait_for(Ts&&... xs) { + using wait_for_atom = atom_constant; + size_t expected = 0; + size_t i = 0; + size_t attach_results[] = {attach_functor(xs)...}; + for (auto res : attach_results) + expected += res; + receive_for(i, expected)( + [](wait_for_atom) { + // nop + } + ); + } - /** @cond PRIVATE */ + /// Sets a user-defined exit reason `err`. This reason + /// is signalized to other actors after `act()` returns. + void fail_state(error err); - void initialize() override; + // -- customization points --------------------------------------------------- - void dequeue(behavior& bhvr, message_id mid = invalid_message_id); + /// Blocks until at least one message is in the mailbox. + virtual void await_data(); - /** @endcond */ + /// Blocks until at least one message is in the mailbox or + /// the absolute `timeout` was reached. + virtual bool await_data(timeout_type timeout); - protected: - // helper function to implement receive_(for|while) and do_receive - std::function make_dequeue_callback() { - return [=](behavior& bhvr) { dequeue(bhvr); }; + /// Returns the next element from the mailbox or `nullptr`. + virtual mailbox_element_ptr dequeue(); + + /// Returns the queue for storing incoming messages. + inline mailbox_type& mailbox() { + return mailbox_; } -}; + /// @cond PRIVATE -class blocking_actor::functor_based : public blocking_actor { - public: - using act_fun = std::function; + /// Receives messages until either a pre- or postcheck of `rcc` fails. + template + void varargs_tup_receive(receive_cond& rcc, message_id mid, + std::tuple& tup) { + using namespace detail; + static_assert(sizeof...(Ts), "at least one argument required"); + // extract how many arguments are actually the behavior part, + // i.e., neither `after(...) >> ...` nor `others >> ...`. + using filtered = + typename tl_filter_not< + type_list::type...>, + is_timeout_or_catch_all + >::type; + filtered tk; + behavior bhvr{apply_moved_args(make_behavior_impl, get_indices(tk), tup)}; + using tail_indices = typename il_range< + tl_size::value, sizeof...(Ts) + >::type; + make_blocking_behavior_t factory; + auto fun = apply_moved_args_prefixed(factory, tail_indices{}, tup, &bhvr); + receive_impl(rcc, mid, fun); + } + + /// Receives messages until either a pre- or postcheck of `rcc` fails. + void varargs_tup_receive(receive_cond& rcc, message_id mid, + std::tuple& tup); + + /// Receives messages until either a pre- or postcheck of `rcc` fails. + template + void varargs_receive(receive_cond& rcc, message_id mid, Ts&&... xs) { + auto tup = std::forward_as_tuple(std::forward(xs)...); + varargs_tup_receive(rcc, mid, tup); + } + + /// Receives messages until either a pre- or postcheck of `rcc` fails. + void receive_impl(receive_cond& rcc, message_id mid, + detail::blocking_behavior& bhvr); - template - functor_based(F f, Ts&&... xs) { - using trait = typename detail::get_callable_trait::type; - using arg0 = typename detail::tl_head::type; - blocking_actor* dummy = nullptr; - std::integral_constant::value> tk; - create(dummy, tk, f, std::forward(xs)...); + bool cleanup(error&& fail_state, execution_unit* host) override; + + sec build_pipeline(stream_slot in, stream_slot out, stream_manager_ptr mgr); + + // -- backwards compatibility ------------------------------------------------ + + inline mailbox_element_ptr next_message() { + return dequeue(); + } + + inline bool has_next_message() { + return !mailbox_.empty(); } - void cleanup(uint32_t reason); + /// @endcond + +private: + size_t attach_functor(const actor&); - protected: - void act() override; + size_t attach_functor(const actor_addr&); - private: - void create(blocking_actor*, act_fun); + size_t attach_functor(const strong_actor_ptr&); - template - void create(Actor* dummy, std::true_type, F f, Ts&&... xs) { - create(dummy, std::bind(f, std::placeholders::_1, std::forward(xs)...)); + template + size_t attach_functor(const typed_actor& x) { + return attach_functor(actor_cast(x)); } - template - void create(Actor* dummy, std::false_type, F f, Ts&&... xs) { - std::function fun = std::bind(f, std::forward(xs)...); - create(dummy, [fun](Actor*) { fun(); }); + template + size_t attach_functor(const Container& xs) { + size_t res = 0; + for (auto& x : xs) + res += attach_functor(x); + return res; } - act_fun m_act; + // -- member variables ------------------------------------------------------- + + // used by both event-based and blocking actors + mailbox_type mailbox_; }; } // namespace caf -#endif // CAF_BLOCKING_ACTOR_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/broadcast_downstream_manager.hpp actor-framework-0.16.3/libcaf_core/caf/broadcast_downstream_manager.hpp --- actor-framework-0.13.2/libcaf_core/caf/broadcast_downstream_manager.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/broadcast_downstream_manager.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,300 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/buffered_downstream_manager.hpp" +#include "caf/outbound_path.hpp" +#include "caf/raise_error.hpp" + +#include "caf/detail/algorithms.hpp" +#include "caf/detail/path_state.hpp" +#include "caf/detail/select_all.hpp" +#include "caf/detail/unordered_flat_map.hpp" + +namespace caf { + +template +class broadcast_downstream_manager : public buffered_downstream_manager { +public: + // -- member types ----------------------------------------------------------- + + /// Base type. + using super = buffered_downstream_manager; + + /// Type of `paths_`. + using typename super::map_type; + + /// Unique pointer to an outbound path. + using typename super::unique_path_ptr; + + /// Enables or disables output per path. + using filter_type = Filter; + + /// Function object for evaluating filters. + using select_type = Select; + + /// Container for caching `T`s per path with active filter. + using path_state = detail::path_state; + + /// Maps slot IDs to caches. + using state_map_type = detail::unordered_flat_map; + + // -- constructors, destructors, and assignment operators -------------------- + + broadcast_downstream_manager(stream_manager* parent) : super(parent) { + // nop + } + + // -- properties ------------------------------------------------------------- + + size_t buffered() const noexcept override { + // We have a central buffer, but also an additional buffer at each path. We + // return the maximum size to reflect the current worst case. + size_t central_buf = this->buf_.size(); + size_t max_path_buf = 0; + for (auto& kvp : state_map_) + max_path_buf = std::max(max_path_buf, kvp.second.buf.size()); + return central_buf + max_path_buf; + } + + size_t buffered(stream_slot slot) const noexcept override { + auto i = state_map_.find(slot); + return this->buf_.size() + + (i != state_map_.end() ? i->second.buf.size() : 0u); + } + + int32_t max_capacity() const noexcept override { + // The maximum capacity is limited by the slowest downstream path. + auto result = std::numeric_limits::max(); + for (auto& kvp : this->paths_) { + auto mc = kvp.second->max_capacity; + // max_capacity is 0 if and only if we didn't receive an ack_batch yet. + if (mc > 0) + result = std::min(result, mc); + } + return result; + } + + /// Sets the filter for `slot` to `filter`. Inserts a new element if `slot` + /// is a new path. + void set_filter(stream_slot slot, filter_type new_filter) { + CAF_LOG_TRACE(CAF_ARG(slot) << CAF_ARG(new_filter)); + filter(slot) = std::move(new_filter); + } + + /// Returns the filter for `slot`. Inserts a new element if `slot` is a new + /// path. + filter_type& filter(stream_slot slot) { + auto i = state_map_.find(slot); + if (i != state_map_.end()) + return i->second.filter; + CAF_RAISE_ERROR("invalid slot"); + } + + /// Returns whether all filters satisfy the predicate as if applying + /// `std::all_of`. + template + bool all_filters(UnaryPredicate predicate) { + return std::all_of(state_map_.begin(), state_map_.end(), + [&](const typename state_map_type::value_type& kvp) { + return predicate(kvp.second.filter); + }); + } + + /// Returns whether any filter satisfies the predicate as if applying + /// `std::any_of`. + template + bool any_filter(UnaryPredicate predicate) { + return std::any_of(state_map_.begin(), state_map_.end(), + [&](const typename state_map_type::value_type& kvp) { + return predicate(kvp.second.filter); + }); + } + + /// Returns whether no filter satisfies the predicate as if applying + /// `std::none_of`. + template + bool no_filter(UnaryPredicate predicate) { + return std::none_of(state_map_.begin(), state_map_.end(), + [&](const typename state_map_type::value_type& kvp) { + return predicate(kvp.second.filter); + }); + } + + /// Returns the broadcast states for all paths. + state_map_type& states() { + return state_map_; + } + + /// Returns the broadcast states for all paths. + const state_map_type& states() const { + return state_map_; + } + + /// Returns the selector for filtering outgoing data. + select_type& selector() { + return select_; + } + + /// Returns the selector for filtering outgoing data. + const select_type& selector() const { + return select_; + } + + // -- overridden functions --------------------------------------------------- + + bool insert_path(unique_path_ptr ptr) override { + CAF_LOG_TRACE(CAF_ARG(ptr)); + // Make sure state_map_ and paths_ are always equally sorted, otherwise + // we'll run into UB when calling `zip_foreach`. + CAF_ASSERT(state_map_.size() == this->paths_.size()); + auto slot = ptr->slots.sender; + // Append to the regular path map. + if (!super::insert_path(std::move(ptr))) { + CAF_LOG_DEBUG("unable to insert path at slot" << slot); + return false; + } + // Append to the state map. + if (!state_map_.emplace(slot, path_state{}).second) { + CAF_LOG_DEBUG("unable to add state for slot" << slot); + super::remove_path(slot, none, true); + return false; + } + return true; + } + + void emit_batches() override { + CAF_LOG_TRACE(CAF_ARG2("buffered", this->buffered()) + << CAF_ARG2("paths", this->paths_.size())); + emit_batches_impl(false); + } + + void force_emit_batches() override { + CAF_LOG_TRACE(CAF_ARG2("buffered", this->buffered()) + << CAF_ARG2("paths", this->paths_.size())); + emit_batches_impl(true); + } + + /// Forces the manager flush its buffer to the individual path buffers. + void fan_out_flush() { + auto& buf = this->buf_; + auto f = [&](typename map_type::value_type& x, + typename state_map_type::value_type& y) { + // Don't push new data into a closing path. + if (x.second->closing) + return; + // Push data from the global buffer to path buffers. + auto& st = y.second; + // TODO: replace with `if constexpr` when switching to C++17 + if (std::is_same::value) { + st.buf.insert(st.buf.end(), buf.begin(), buf.end()); + } else { + for (auto& piece : buf) + if (select_(st.filter, piece)) + st.buf.emplace_back(piece); + } + }; + detail::zip_foreach(f, this->paths_.container(), state_map_.container()); + buf.clear(); + } + +protected: + void about_to_erase(outbound_path* ptr, bool silent, + error* reason) override { + CAF_ASSERT(ptr != nullptr); + CAF_LOG_TRACE(CAF_ARG2("slot", ptr->slots.sender) << CAF_ARG(silent) << + CAF_ARG(reason)); + state_map_.erase(ptr->slots.sender); + super::about_to_erase(ptr, silent, reason); + } + +private: + void emit_batches_impl(bool force_underfull) { + CAF_ASSERT(this->paths_.size() <= state_map_.size()); + if (this->paths_.empty()) + return; + // Calculate the chunk size, i.e., how many more items we can put to our + // caches at the most. + auto not_closing = [&](typename map_type::value_type& x, + typename state_map_type::value_type&) { + return !x.second->closing; + }; + // Returns the minimum of `interim` and `get_credit(x) - get_cache_size(y)`. + auto f = [&](size_t interim, typename map_type::value_type& x, + typename state_map_type::value_type& y) { + auto credit = static_cast(x.second->open_credit); + auto cache_size = y.second.buf.size(); + return std::min(interim, credit > cache_size ? credit - cache_size : 0u); + }; + auto chunk_size = detail::zip_fold_if(f, not_closing, + std::numeric_limits::max(), + this->paths_.container(), + state_map_.container()); + if (chunk_size == std::numeric_limits::max()) { + // All paths are closing, simply try forcing out more data and return. + auto g = [&](typename map_type::value_type& x, + typename state_map_type::value_type& y) { + // Always force batches on closing paths. + x.second->emit_batches(this->self(), y.second.buf, true); + }; + detail::zip_foreach(g, this->paths_.container(), state_map_.container()); + return; + } + + auto chunk = this->get_chunk(chunk_size); + if (chunk.empty()) { + auto g = [&](typename map_type::value_type& x, + typename state_map_type::value_type& y) { + // Always force batches on closing paths. + x.second->emit_batches(this->self(), y.second.buf, + force_underfull || x.second->closing); + }; + detail::zip_foreach(g, this->paths_.container(), state_map_.container()); + } else { + auto g = [&](typename map_type::value_type& x, + typename state_map_type::value_type& y) { + auto& st = y.second; + // Don't enqueue new data into a closing path. + if (!x.second->closing) { + // Push data from the global buffer to path buffers. + // TODO: replace with `if constexpr` when switching to C++17 + if (std::is_same::value) { + st.buf.insert(st.buf.end(), chunk.begin(), chunk.end()); + } else { + for (auto& piece : chunk) + if (select_(st.filter, piece)) + st.buf.emplace_back(piece); + } + } + // Always force batches on closing paths. + x.second->emit_batches(this->self(), st.buf, + force_underfull || x.second->closing); + }; + detail::zip_foreach(g, this->paths_.container(), state_map_.container()); + } + } + + state_map_type state_map_; + select_type select_; +}; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/buffered_downstream_manager.hpp actor-framework-0.16.3/libcaf_core/caf/buffered_downstream_manager.hpp --- actor-framework-0.13.2/libcaf_core/caf/buffered_downstream_manager.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/buffered_downstream_manager.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,113 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include + +#include "caf/downstream_manager_base.hpp" +#include "caf/logger.hpp" + +namespace caf { + +/// Mixin for streams with any number of downstreams. `Subtype` must provide a +/// member function `buf()` returning a queue with `std::deque`-like interface. +template +class buffered_downstream_manager : public downstream_manager_base { +public: + // -- member types ----------------------------------------------------------- + + using super = downstream_manager_base; + + using output_type = T; + + using buffer_type = std::deque; + + using chunk_type = std::vector; + + // -- constructors, destructors, and assignment operators -------------------- + + explicit buffered_downstream_manager(stream_manager* parent) : super(parent) { + // nop + } + + template + void push(T0&& x, Ts&&... xs) { + buf_.emplace_back(std::forward(x), std::forward(xs)...); + } + + /// @pre `n <= buf_.size()` + static chunk_type get_chunk(buffer_type& buf, size_t n) { + CAF_LOG_TRACE(CAF_ARG(buf) << CAF_ARG(n)); + chunk_type xs; + if (!buf.empty() && n > 0) { + xs.reserve(std::min(n, buf.size())); + if (n < buf.size()) { + auto first = buf.begin(); + auto last = first + static_cast(n); + std::move(first, last, std::back_inserter(xs)); + buf.erase(first, last); + } else { + std::move(buf.begin(), buf.end(), std::back_inserter(xs)); + buf.clear(); + } + } + return xs; + } + + chunk_type get_chunk(size_t n) { + return get_chunk(buf_, n); + } + + bool terminal() const noexcept override { + return false; + } + + size_t capacity() const noexcept override { + // Our goal is to cache up to 2 full batches, whereby we pick the highest + // batch size available to us (optimistic estimate). + size_t desired = 1; + for (auto& kvp : this->paths_) + desired = std::max(static_cast(kvp.second->desired_batch_size), + desired); + desired *= 2; + auto stored = buffered(); + return stored < desired ? desired - stored : 0u; + } + + size_t buffered() const noexcept override { + return buf_.size(); + } + + buffer_type& buf() { + return buf_; + } + + const buffer_type& buf() const { + return buf_; + } + +protected: + buffer_type buf_; +}; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/byte_address.hpp actor-framework-0.16.3/libcaf_core/caf/byte_address.hpp --- actor-framework-0.13.2/libcaf_core/caf/byte_address.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/byte_address.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,137 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include + +#include "caf/config.hpp" +#include "caf/detail/comparable.hpp" + +namespace caf { + +/// Base type for addresses based on a byte representation such as IP or +/// Ethernet addresses. +template +class byte_address : detail::comparable { +public: + // -- element access --------------------------------------------------------- + + /// Returns the byte at given index. + uint8_t& operator[](size_t index) noexcept { + return dref().bytes()[index]; + } + + /// Returns the byte at given index. + const uint8_t& operator[](size_t index) const noexcept { + return dref().bytes()[index]; + } + + // -- properties ------------------------------------------------------------- + + /// Returns the number of bytes of the address. + size_t size() const noexcept { + return dref().bytes().size(); + } + + // -- comparison ------------------------------------------------------------- + + /// Returns a negative number if `*this < other`, zero if `*this == other` + /// and a positive number if `*this > other`. + int compare(const Derived& other) const noexcept { + auto& buf = dref().bytes(); + return memcmp(buf.data(), other.bytes().data(), Derived::num_bytes); + } + + // -- transformations -------------------------------------------------------- + + Derived network_address(size_t prefix_length) const noexcept { + static constexpr uint8_t netmask_tbl[] = {0x00, 0x80, 0xC0, 0xE0, + 0xF0, 0xF8, 0xFC, 0xFE}; + prefix_length = std::min(prefix_length, Derived::num_bytes * 8); + Derived netmask; + auto bytes_to_keep = prefix_length / 8; + auto remainder = prefix_length % 8; + size_t i = 0; + for (; i < bytes_to_keep; ++i) + netmask[i] = 0xFF; + if (remainder != 0) + netmask[i] = netmask_tbl[remainder]; + Derived result{dref()}; + result &= netmask; + return result; + } + + // -- bitwise member operators ----------------------------------------------- + + /// Bitwise ANDs `*this` and `other`. + Derived& operator&=(const Derived& other) { + auto& buf = dref().bytes(); + for (size_t index = 0; index < Derived::num_bytes; ++index) + buf[index] &= other[index]; + return dref(); + } + + /// Bitwise ORs `*this` and `other`. + Derived& operator|=(const Derived& other) { + auto& buf = dref().bytes(); + for (size_t index = 0; index < Derived::num_bytes; ++index) + buf[index] |= other[index]; + return dref(); + } + + /// Bitwise XORs `*this` and `other`. + Derived& operator^=(const Derived& other) { + auto& buf = dref().bytes(); + for (size_t index = 0; index < Derived::num_bytes; ++index) + buf[index] ^= other[index]; + return dref(); + } + + // -- bitwise free operators ------------------------------------------------- + + friend Derived operator&(const Derived& x, const Derived& y) { + Derived result{x}; + result &= y; + return result; + } + + friend Derived operator|(const Derived& x, const Derived& y) { + Derived result{x}; + result |= y; + return result; + } + + friend Derived operator^(const Derived& x, const Derived& y) { + Derived result{x}; + result ^= y; + return result; + } + +private: + Derived& dref() noexcept { + return *static_cast(this); + } + + const Derived& dref() const noexcept { + return *static_cast(this); + } +}; + +} // namespace caf diff -Nru actor-framework-0.13.2/libcaf_core/caf/callback.hpp actor-framework-0.16.3/libcaf_core/caf/callback.hpp --- actor-framework-0.13.2/libcaf_core/caf/callback.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/callback.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,84 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include "caf/error.hpp" +#include "caf/config.hpp" + +#include "caf/detail/type_traits.hpp" + +// The class `callback` intentionally has no virtual destructor, because +// the lifetime of callback objects is never managed via base pointers. +CAF_PUSH_NON_VIRTUAL_DTOR_WARNING + +namespace caf { + +/// Describes a simple callback, usually implemented via lambda expression. +/// Callbacks are used as "type-safe function objects" wherever an interface +/// requires dynamic dispatching. The alternative would be to store the lambda +/// in a `std::function`, which adds another layer of indirection and +/// requires a heap allocation. With the callback implementation of CAF, +/// the object remains on the stack and does not cause more overhead +/// than necessary. +template +class callback { +public: + virtual error operator()(Ts...) = 0; +}; + +/// Utility class for wrapping a function object of type `Base`. +template +class callback_impl : public callback { +public: + callback_impl(F&& f) : f_(std::move(f)) { + // nop + } + + callback_impl(callback_impl&&) = default; + callback_impl& operator=(callback_impl&&) = default; + + error operator()(Ts... xs) override { + return f_(xs...); + } + +private: + F f_; +}; + +/// Utility class for selecting a `callback_impl`. +template ::arg_types> +struct select_callback; + +template +struct select_callback> { + using type = callback_impl; +}; + +/// Creates a callback from a lambda expression. +/// @relates callback +template +typename select_callback::type make_callback(F fun) { + return {std::move(fun)}; +} + +} // namespace caf + +CAF_POP_WARNINGS + diff -Nru actor-framework-0.13.2/libcaf_core/caf/catch_all.hpp actor-framework-0.16.3/libcaf_core/caf/catch_all.hpp --- actor-framework-0.13.2/libcaf_core/caf/catch_all.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/catch_all.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,61 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include + +#include "caf/result.hpp" +#include "caf/message.hpp" +#include "caf/message_view.hpp" + +namespace caf { + +template +struct catch_all { + using fun_type = std::function (message_view&)>; + + F handler; + + catch_all(catch_all&& x) : handler(std::move(x.handler)) { + // nop + } + + template + catch_all(T&& x) : handler(std::forward(x)) { + // nop + } + + static_assert(std::is_convertible::value, + "catch-all handler must have signature " + "result (message_view&)"); + + fun_type lift() const { + return handler; + } +}; + +template +struct is_catch_all : std::false_type {}; + +template +struct is_catch_all> : std::true_type {}; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/channel.hpp actor-framework-0.16.3/libcaf_core/caf/channel.hpp --- actor-framework-0.13.2/libcaf_core/caf/channel.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/channel.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_CHANNEL_HPP -#define CAF_CHANNEL_HPP - -#include -#include - -#include "caf/intrusive_ptr.hpp" - -#include "caf/fwd.hpp" -#include "caf/abstract_channel.hpp" - -#include "caf/detail/comparable.hpp" - -namespace caf { - -class actor; -class group; -class execution_unit; - -struct invalid_actor_t; -struct invalid_group_t; - -/** - * A handle to instances of `abstract_channel`. - */ -class channel : detail::comparable, - detail::comparable, - detail::comparable { - public: - template - friend T actor_cast(const U&); - - channel() = default; - - channel(const actor&); - - channel(const group&); - - channel(const invalid_actor_t&); - - channel(const invalid_group_t&); - - template - channel(intrusive_ptr ptr, - typename std::enable_if< - std::is_base_of::value - >::type* = 0) - : m_ptr(ptr) { - // nop - } - - channel(abstract_channel* ptr); - - inline explicit operator bool() const { - return static_cast(m_ptr); - } - - inline bool operator!() const { - return !m_ptr; - } - - inline abstract_channel* operator->() const { - return m_ptr.get(); - } - - inline abstract_channel& operator*() const { - return *m_ptr; - } - - intptr_t compare(const channel& other) const; - - intptr_t compare(const actor& other) const; - - intptr_t compare(const abstract_channel* other) const; - - static intptr_t compare(const abstract_channel* lhs, - const abstract_channel* rhs); - - private: - inline abstract_channel* get() const { - return m_ptr.get(); - } - - abstract_channel_ptr m_ptr; -}; - -} // namespace caf - -#endif // CAF_CHANNEL_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/check_typed_input.hpp actor-framework-0.16.3/libcaf_core/caf/check_typed_input.hpp --- actor-framework-0.13.2/libcaf_core/caf/check_typed_input.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/check_typed_input.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,36 +16,50 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_CHECK_TYPED_INPUT_HPP -#define CAF_CHECK_TYPED_INPUT_HPP +#pragma once -#include "caf/typed_actor.hpp" +#include "caf/fwd.hpp" +#include "caf/replies_to.hpp" #include "caf/detail/type_list.hpp" -#include "caf/detail/typed_actor_util.hpp" namespace caf { -/** - * Checks whether `R` does support an input of type `{Ts...}` via a - * static assertion (always returns 0). - */ -template -void check_typed_input(const typed_actor&, - const detail::type_list&) { - static_assert(detail::tl_find< - detail::type_list, - atom_value - >::value == -1, - "atom(...) notation is not sufficient for static type " - "checking, please use atom_constant instead in this context"); - static_assert(detail::tl_find_if< - detail::type_list, - detail::input_is>::template eval - >::value >= 0, - "typed actor does not support given input"); +template +struct output_types_of { + // nop +}; + +template +struct output_types_of> { + using type = Out; +}; + +template +struct signatures_of { + using type = typename std::remove_pointer::type::signatures; +}; + +template +using signatures_of_t = typename signatures_of::type; + +template +constexpr bool statically_typed() { + return !std::is_same< + none_t, + typename std::remove_pointer::type::signatures + >::value; } +template +struct is_void_response : std::false_type {}; + +template <> +struct is_void_response> : std::true_type {}; + +// true for the purpose of type checking performed by send() +template <> +struct is_void_response : std::true_type {}; + } // namespace caf -#endif // CAF_CHECK_TYPED_INPUT_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/composable_behavior_based_actor.hpp actor-framework-0.16.3/libcaf_core/caf/composable_behavior_based_actor.hpp --- actor-framework-0.13.2/libcaf_core/caf/composable_behavior_based_actor.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/composable_behavior_based_actor.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,51 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include "caf/stateful_actor.hpp" +#include "caf/message_handler.hpp" + +namespace caf { + +/// Implementation class for spawning composable states directly as actors. +template +class composable_behavior_based_actor : public stateful_actor { + public: + static_assert(!std::is_abstract::value, + "State is abstract, please make sure to override all " + "virtual operator() member functions"); + + using super = stateful_actor; + + composable_behavior_based_actor(actor_config& cfg) : super(cfg) { + // nop + } + + using behavior_type = typename State::behavior_type; + + behavior_type make_behavior() override { + this->state.init_selfptr(this); + message_handler tmp; + this->state.init_behavior(tmp); + return behavior_type{typename behavior_type::unsafe_init{}, std::move(tmp)}; + } +}; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/composable_behavior.hpp actor-framework-0.16.3/libcaf_core/caf/composable_behavior.hpp --- actor-framework-0.13.2/libcaf_core/caf/composable_behavior.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/composable_behavior.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,109 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include "caf/param.hpp" +#include "caf/behavior.hpp" +#include "caf/replies_to.hpp" +#include "caf/typed_actor.hpp" +#include "caf/typed_actor_pointer.hpp" +#include "caf/abstract_composable_behavior.hpp" + +namespace caf { + +/// Generates an interface class that provides `operator()`. The signature +/// of the apply operator is derived from the typed message passing interface +/// `MPI`. +template +class composable_behavior_base; + +template +class composable_behavior_base, + output_tuple>> { +public: + virtual ~composable_behavior_base() noexcept { + // nop + } + + virtual result operator()(param_t...) = 0; + + // C++14 and later +# if __cplusplus > 201103L + auto make_callback() { + return [=](param_t... xs) { return (*this)(std::move(xs)...); }; + } +# else + // C++11 + std::function (param_t...)> make_callback() { + return [=](param_t... xs) { return (*this)(std::move(xs)...); }; + } +# endif +}; + +/// Base type for composable actor states. +template +class composable_behavior; + +template +class composable_behavior> + : virtual public abstract_composable_behavior, + public composable_behavior_base... { +public: + using signatures = detail::type_list; + + using handle_type = + typename detail::tl_apply< + signatures, + typed_actor + >::type; + + using actor_base = typename handle_type::base; + + using broker_base = typename handle_type::broker_base; + + using behavior_type = typename handle_type::behavior_type; + + composable_behavior() : self(nullptr) { + // nop + } + + template + unit_t init_selfptr(SelfPointer x) { + CAF_ASSERT(x != nullptr); + self = x; + return unit; + } + + void init_behavior(message_handler& x) override { + init_behavior_impl(x); + } + + unit_t init_behavior_impl(message_handler& x) { + if (x) + x = x.or_else(composable_behavior_base::make_callback()...); + else + x.assign(composable_behavior_base::make_callback()...); + return unit; + } + + typed_actor_pointer self; +}; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/composed_behavior.hpp actor-framework-0.16.3/libcaf_core/caf/composed_behavior.hpp --- actor-framework-0.13.2/libcaf_core/caf/composed_behavior.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/composed_behavior.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,75 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include "caf/param.hpp" +#include "caf/composable_behavior.hpp" +#include "caf/typed_actor_pointer.hpp" + +namespace caf { + +template +class composed_behavior : public Ts... { +public: + using signatures = + typename detail::tl_union::type; + + using handle_type = + typename detail::tl_apply< + signatures, + typed_actor + >::type; + + using behavior_type = typename handle_type::behavior_type; + + using actor_base = typename handle_type::base; + + using broker_base = typename handle_type::broker_base; + + using self_pointer = + typename detail::tl_apply< + signatures, + typed_actor_pointer + >::type; + + composed_behavior() : self(nullptr) { + // nop + } + + template + unit_t init_selfptr(SelfPointer x) { + CAF_ASSERT(x != nullptr); + self = x; + return unit(static_cast(this)->init_selfptr(x)...); + } + + void init_behavior(message_handler& x) override { + init_behavior_impl(x); + } + + unit_t init_behavior_impl(message_handler& x) { + return unit(static_cast(this)->init_behavior_impl(x)...); + } + +protected: + self_pointer self; +}; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/composed_type.hpp actor-framework-0.16.3/libcaf_core/caf/composed_type.hpp --- actor-framework-0.13.2/libcaf_core/caf/composed_type.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/composed_type.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,139 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include "caf/fwd.hpp" +#include "caf/replies_to.hpp" + +#include "caf/detail/type_list.hpp" + +namespace caf { + +/// Computes the type for f*g (actor composition). +/// +/// ~~~ +/// let output_type x = case x of Stream y -> y ; Single y -> y +/// +/// let propagate_stream from to = case from of +/// Stream _ -> Stream (output_type to) +/// Single _ -> to +/// let composed_type f g = +/// [(fst x, propagate_stream (snd x) (snd y)) | x <- g, y <- f, +/// output_type (snd x) == fst y] +/// ~~~ +/// +/// This class implements the list comprehension above in a +/// single shot with worst case n*m template instantiations using an +/// inner and outer loop, where n is the size +/// of Xs and m the size of Ys. Zs is a helper that models the +/// "inner loop variable" for generating the cross product of Xs and Ys. +/// The helper function propagate_stream is integrated into the loop with +/// four cases for the matching case. Rs collects the results. + +template +struct composed_type; + +// end of outer loop over Xs +template +struct composed_type, Ys, Zs, detail::type_list> { + using type = typed_actor; +}; + +// end of inner loop Ys (Zs) +template +struct composed_type, Ys, detail::type_list<>, Rs> + : composed_type, Ys, Ys, Rs> {}; + +// case #1 +template +struct composed_type, + output_tuple>, Xs...>, + Ys, + detail::type_list, + output_tuple>, Zs...>, + detail::type_list> + : composed_type, Ys, Ys, + detail::type_list, + output_tuple>>> {}; + +// case #2 +template +struct composed_type, + output_tuple>, Xs...>, + Ys, + detail::type_list, + output_stream>, + Zs...>, + detail::type_list> + : composed_type, Ys, Ys, + detail::type_list, + output_stream>>> { +}; + +// case #3 +template +struct composed_type, + output_stream>, Xs...>, + Ys, + detail::type_list, + output_tuple>, Zs...>, + detail::type_list> + : composed_type, Ys, Ys, + detail::type_list, + output_stream>>> { +}; + +// case #4 +template +struct composed_type, + output_stream>, Xs...>, + Ys, + detail::type_list, + output_stream>, Zs...>, + detail::type_list> + : composed_type, Ys, Ys, + detail::type_list, + output_stream>>> { +}; + +// default case (recurse over Zs) +template +struct composed_type, Xs...>, + Ys, + detail::type_list, Zs...>, + Rs> + : composed_type, Xs...>, + Ys, detail::type_list, Rs> {}; + +/// Convenience type alias. +/// @relates composed_type +template +using composed_type_t = + typename composed_type>::type; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/config.hpp actor-framework-0.16.3/libcaf_core/caf/config.hpp --- actor-framework-0.13.2/libcaf_core/caf/config.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/config.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,13 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_CONFIG_HPP -#define CAF_CONFIG_HPP +#pragma once + +// this header must be generated by the build system (may be empty) +#include "caf/detail/build_config.hpp" + +// Platform-specific adjustments. +#define CAF_CACHE_LINE_SIZE 64 // Config pararameters defined by the build system (usually CMake): // @@ -29,26 +33,18 @@ // - denotes the amount of logging, ranging from error messages only (0) // to complete traces (4) -/** - * Denotes version of CAF in the format {MAJOR}{MINOR}{PATCH}, - * whereas each number is a two-digit decimal number without - * leading zeros (e.g. 900 is version 0.9.0). - */ -#define CAF_VERSION 1302 - -/** - * Defined to the major version number of CAF. - **/ +/// Denotes version of CAF in the format {MAJOR}{MINOR}{PATCH}, +/// whereas each number is a two-digit decimal number without +/// leading zeros (e.g. 900 is version 0.9.0). +#define CAF_VERSION 1603 + +/// Defined to the major version number of CAF. #define CAF_MAJOR_VERSION (CAF_VERSION / 10000) -/** - * Defined to the minor version number of CAF. - **/ +/// Defined to the minor version number of CAF. #define CAF_MINOR_VERSION ((CAF_VERSION / 100) % 100) -/** - * Defined to the patch version number of CAF. - **/ +/// Defined to the patch version number of CAF. #define CAF_PATCH_VERSION (CAF_VERSION % 100) // This compiler-specific block defines: @@ -65,61 +61,124 @@ // CAF_PUSH_WARNINGS and CAF_POP_WARNINGS #if defined(__clang__) # define CAF_CLANG -# define CAF_DEPRECATED __attribute__((__deprecated__)) +# define CAF_LIKELY(x) __builtin_expect((x), 1) +# define CAF_UNLIKELY(x) __builtin_expect((x), 0) +# define CAF_DEPRECATED __attribute__((deprecated)) +# define CAF_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) # define CAF_PUSH_WARNINGS \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wall\"") \ _Pragma("clang diagnostic ignored \"-Wextra\"") \ - _Pragma("clang diagnostic ignored \"-Werror\"") \ + _Pragma("clang diagnostic ignored \"-Wundef\"") \ + _Pragma("clang diagnostic ignored \"-Wshadow\"") \ _Pragma("clang diagnostic ignored \"-Wdeprecated\"") \ - _Pragma("clang diagnostic ignored \"-Wdisabled-macro-expansion\"") \ _Pragma("clang diagnostic ignored \"-Wextra-semi\"") \ - _Pragma("clang diagnostic ignored \"-Wdocumentation\"") \ - _Pragma("clang diagnostic ignored \"-Wweak-vtables\"") \ - _Pragma("clang diagnostic ignored \"-Wunused-parameter\"") \ - _Pragma("clang diagnostic ignored \"-Wswitch-enum\"") \ - _Pragma("clang diagnostic ignored \"-Wshadow\"") \ _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 \"-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 \"-Wswitch-enum\"") \ + _Pragma("clang diagnostic ignored \"-Wweak-vtables\"") \ + _Pragma("clang diagnostic ignored \"-Wdocumentation\"") \ _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\"") \ + _Pragma("clang diagnostic ignored \"-Wunused-template\"") \ + _Pragma("clang diagnostic ignored \"-Wshorten-64-to-32\"") \ + _Pragma("clang diagnostic ignored \"-Wunreachable-code\"") \ + _Pragma("clang diagnostic ignored \"-Wdouble-promotion\"") \ + _Pragma("clang diagnostic ignored \"-Wc++14-extensions\"") \ + _Pragma("clang diagnostic ignored \"-Wunused-parameter\"") \ + _Pragma("clang diagnostic ignored \"-Wnested-anon-types\"") \ + _Pragma("clang diagnostic ignored \"-Wreserved-id-macro\"") \ + _Pragma("clang diagnostic ignored \"-Wconstant-conversion\"") \ + _Pragma("clang diagnostic ignored \"-Wimplicit-fallthrough\"") \ _Pragma("clang diagnostic ignored \"-Wused-but-marked-unused\"") \ - _Pragma("clang diagnostic ignored \"-Wdisabled-macro-expansion\"") \ - _Pragma("clang diagnostic ignored \"-Wsign-conversion\"") + _Pragma("clang diagnostic ignored \"-Wdisabled-macro-expansion\"") +# define CAF_PUSH_UNUSED_LABEL_WARNING \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wunused-label\"") +# define CAF_PUSH_NON_VIRTUAL_DTOR_WARNING \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wnon-virtual-dtor\"") +# define CAF_PUSH_DEPRECATED_WARNING \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") # define CAF_POP_WARNINGS \ _Pragma("clang diagnostic pop") # define CAF_ANNOTATE_FALLTHROUGH [[clang::fallthrough]] # define CAF_COMPILER_VERSION \ (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +# if !__has_feature(cxx_thread_local) +# define CAF_NO_THREAD_LOCAL +# endif #elif defined(__GNUC__) # define CAF_GCC -# define CAF_DEPRECATED __attribute__((__deprecated__)) -# define CAF_PUSH_WARNINGS -# define CAF_POP_WARNINGS -# define CAF_ANNOTATE_FALLTHROUGH static_cast(0) +# define CAF_LIKELY(x) __builtin_expect((x), 1) +# define CAF_UNLIKELY(x) __builtin_expect((x), 0) +# define CAF_DEPRECATED __attribute__((deprecated)) +# define CAF_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) +# define CAF_PUSH_WARNINGS \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wshadow\"") \ + _Pragma("GCC diagnostic ignored \"-Wpragmas\"") \ + _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \ + _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \ + _Pragma("GCC diagnostic ignored \"-Wconversion\"") \ + _Pragma("GCC diagnostic ignored \"-Wfloat-equal\"") \ + _Pragma("GCC diagnostic ignored \"-Wc++14-extensions\"") +# define CAF_PUSH_UNUSED_LABEL_WARNING \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wunused-label\"") +# define CAF_PUSH_NON_VIRTUAL_DTOR_WARNING \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"") +# define CAF_PUSH_DEPRECATED_WARNING \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define CAF_POP_WARNINGS \ + _Pragma("GCC diagnostic pop") +# if __GNUC__ >= 7 +# define CAF_ANNOTATE_FALLTHROUGH __attribute__((fallthrough)) +# else +# define CAF_ANNOTATE_FALLTHROUGH static_cast(0) +# endif # define CAF_COMPILER_VERSION \ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) + // disable thread_local on GCC/macOS due to heap-use-after-free bug: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67135 +# ifdef __APPLE__ +# define CAF_NO_THREAD_LOCAL +# endif #elif defined(_MSC_VER) # define CAF_MSVC +# define CAF_LIKELY(x) x +# define CAF_UNLIKELY(x) x # define CAF_DEPRECATED -# define CAF_PUSH_WARNINGS -# define CAF_POP_WARNINGS +# define CAF_DEPRECATED_MSG(msg) +# define CAF_PUSH_WARNINGS \ + __pragma(warning(push)) +# define CAF_PUSH_UNUSED_LABEL_WARNING \ + __pragma(warning(push)) \ + __pragma(warning(disable: 4102)) +# define CAF_PUSH_DEPRECATED_WARNING \ + __pragma(warning(push)) +# define CAF_PUSH_NON_VIRTUAL_DTOR_WARNING \ + __pragma(warning(push)) +# define CAF_POP_WARNINGS __pragma(warning(pop)) # define CAF_ANNOTATE_FALLTHROUGH static_cast(0) # define CAF_COMPILER_VERSION _MSC_FULL_VER +# pragma warning( disable : 4624 ) +# pragma warning( disable : 4800 ) +# pragma warning( disable : 4503 ) +# ifndef NOMINMAX +# define NOMINMAX +# endif // NOMINMAX #else +# define CAF_LIKELY(x) x +# define CAF_UNLIKELY(x) x # define CAF_DEPRECATED # define CAF_PUSH_WARNINGS +# define CAF_PUSH_NON_VIRTUAL_DTOR_WARNING +# define CAF_PUSH_DEPRECATED_WARNING # define CAF_POP_WARNINGS # define CAF_ANNOTATE_FALLTHROUGH static_cast(0) #endif @@ -136,7 +195,7 @@ # define CAF_IOS # else # define CAF_MACOS -# ifndef _GLIBCXX_HAS_GTHREADS +# if defined(CAF_GCC) && !defined(_GLIBCXX_HAS_GTHREADS) # define _GLIBCXX_HAS_GTHREADS # endif # endif @@ -150,15 +209,23 @@ # endif #elif defined(__FreeBSD__) # define CAF_BSD +#elif defined(__CYGWIN__) +# define CAF_CYGWIN #elif defined(WIN32) || defined(_WIN32) # define CAF_WINDOWS #else # error Platform and/or compiler not supportet #endif -#if defined(CAF_MACOS) || defined(CAF_LINUX) || defined(CAF_BSD) +#if defined(CAF_MACOS) || defined(CAF_LINUX) || defined(CAF_BSD) || defined(CAF_CYGWIN) # define CAF_POSIX #endif +#if defined(CAF_WINDOWS) && defined(CAF_CLANG) +// Fix for issue with static_cast<> in objbase.h. +// See: https://github.com/philsquared/Catch/issues/690. +struct IUnknown; +#endif + #include #include @@ -169,22 +236,26 @@ # define CAF_ASSERT(stmt) \ if (static_cast(stmt) == false) { \ printf("%s:%u: requirement failed '%s'\n", __FILE__, __LINE__, #stmt); \ - abort(); \ + ::abort(); \ } static_cast(0) #else // defined(CAF_LINUX) || defined(CAF_MACOS) # include # define CAF_ASSERT(stmt) \ if (static_cast(stmt) == false) { \ printf("%s:%u: requirement failed '%s'\n", __FILE__, __LINE__, #stmt); \ - void* array[10]; \ - auto caf_bt_size = ::backtrace(array, 10); \ + void* array[20]; \ + auto caf_bt_size = ::backtrace(array, 20); \ ::backtrace_symbols_fd(array, caf_bt_size, 2); \ - abort(); \ + ::abort(); \ } static_cast(0) #endif -#define CAF_CRITICAL(error) \ - printf("%s:%u: critical error: '%s'\n", __FILE__, __LINE__, error); \ - abort() +// Convenience macros. +#define CAF_IGNORE_UNUSED(x) static_cast(x) -#endif // CAF_CONFIG_HPP +#define CAF_CRITICAL(error) \ + do { \ + fprintf(stderr, "[FATAL] %s:%u: critical error: '%s'\n", \ + __FILE__, __LINE__, error); \ + ::abort(); \ + } while (false) diff -Nru actor-framework-0.13.2/libcaf_core/caf/config_option_adder.hpp actor-framework-0.16.3/libcaf_core/caf/config_option_adder.hpp --- actor-framework-0.13.2/libcaf_core/caf/config_option_adder.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/config_option_adder.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,78 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/config_option.hpp" +#include "caf/fwd.hpp" + +namespace caf { + +/// Adds config options of the same category to a `config_option_set`. +class config_option_adder { +public: + // -- constructors, destructors, and assignment operators -------------------- + + config_option_adder(config_option_set& target, string_view category); + + // -- properties ------------------------------------------------------------- + + /// Adds a config option to the category that synchronizes with `ref`. + template + config_option_adder& add(T& ref, string_view name, string_view description) { + return add_impl(make_config_option(ref, category_, name, description)); + } + + /// Adds a config option to the category. + template + config_option_adder& add(string_view name, string_view description) { + return add_impl(make_config_option(category_, name, description)); + } + + /// For backward compatibility only. Do not use for new code! + /// @private + config_option_adder& add_neg(bool& ref, string_view name, + string_view description); + + /// For backward compatibility only. Do not use for new code! + /// @private + config_option_adder& add_us(size_t& ref, string_view name, + string_view description); + + /// For backward compatibility only. Do not use for new code! + /// @private + config_option_adder& add_ms(size_t& ref, string_view name, + string_view description); + +private: + // -- properties ------------------------------------------------------------- + + config_option_adder& add_impl(config_option&& opt); + + // -- member variables ------------------------------------------------------- + + /// Reference to the target set. + config_option_set& xs_; + + /// Category for all options generated by this adder. + string_view category_; +}; + +} // namespace caf diff -Nru actor-framework-0.13.2/libcaf_core/caf/config_option.hpp actor-framework-0.16.3/libcaf_core/caf/config_option.hpp --- actor-framework-0.13.2/libcaf_core/caf/config_option.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/config_option.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,116 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include + +#include "caf/fwd.hpp" +#include "caf/string_view.hpp" + +namespace caf { + +/// Defines a configuration option for the application. +class config_option { +public: + // -- member types ----------------------------------------------------------- + + /// Custom vtable-like struct for delegating to type-specific functions and + /// storing type-specific information shared by several config options. + struct meta_state { + /// Checks whether a value matches the option's type. + error (*check)(const config_value&); + + /// Stores a value in the given location. + void (*store)(void*, const config_value&); + + /// Tries to extrac a value from the given location. Exists for backward + /// compatibility only and will get removed with CAF 0.17. + config_value (*get)(const void*); + + /// Human-readable name of the option's type. + std::string type_name; + }; + + // -- constructors, destructors, and assignment operators -------------------- + + /// Constructs a config option. + config_option(string_view category, string_view name, string_view description, + const meta_state* meta, void* value = nullptr); + + config_option(const config_option&); + + config_option(config_option&&) = default; + + config_option& operator=(const config_option&); + + config_option& operator=(config_option&&) = default; + + // -- swap function ---------------------------------------------------------- + + friend void swap(config_option& first, config_option& second) noexcept; + + // -- properties ------------------------------------------------------------- + + /// Returns the category of the option. + string_view category() const noexcept; + + /// Returns the name of the option. + string_view long_name() const noexcept; + + /// Returns (optional) one-letter short names of the option. + string_view short_names() const noexcept; + + /// Returns a human-readable description of the option. + string_view description() const noexcept; + + /// Returns the full name for this config option as ".". + string_view full_name() const noexcept; + + /// Checks whether `x` holds a legal value for this option. + error check(const config_value& x) const; + + /// Stores `x` in this option unless it is stateless. + /// @pre `check(x) == none`. + void store(const config_value& x) const; + + /// Returns a human-readable representation of this option's expected type. + string_view type_name() const noexcept; + + /// Returns whether this config option stores a boolean flag. + bool is_flag() const noexcept; + + /// @private + // TODO: remove with CAF 0.17 + optional get() const; + +private: + string_view buf_slice(size_t from, size_t to) const noexcept; + + std::unique_ptr buf_; + uint16_t category_separator_; + uint16_t long_name_separator_; + uint16_t short_names_separator_; + uint16_t buf_size_; + const meta_state* meta_; + mutable void* value_; +}; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/config_option_set.hpp actor-framework-0.16.3/libcaf_core/caf/config_option_set.hpp --- actor-framework-0.13.2/libcaf_core/caf/config_option_set.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/config_option_set.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,190 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include + +#include "caf/config_option.hpp" +#include "caf/fwd.hpp" +#include "caf/make_config_option.hpp" +#include "caf/pec.hpp" +#include "caf/string_view.hpp" + +namespace caf { + +/// A set of `config_option` objects that parses CLI arguments into a +/// `config_value::dictionary`. +class config_option_set { +public: + // -- member types ----------------------------------------------------------- + + /// An iterator over CLI arguments. + using argument_iterator = std::vector::const_iterator; + + /// The result of `parse` member functions. + using parse_result = std::pair; + + /// List of config options. + using option_vector = std::vector; + + /// Pointer to a config option. + using option_pointer = const config_option*; + + /// An iterator over ::config_option unique pointers. + using iterator = option_vector::iterator; + + /// An iterator over ::config_option unique pointers. + using const_iterator = option_vector::const_iterator; + + /// Maps string keys to arbitrary (config) values. + using dictionary = caf::dictionary; + + /// Categorized settings. + using config_map = caf::dictionary; + + // -- properties ------------------------------------------------------------- + + /// Returns the first `config_option` that matches the CLI name. + /// @param name Config option name formatted as + /// `#.`. Users can omit `` + /// for options that have an empty prefix and `` + /// if the category is "global". + option_pointer cli_long_name_lookup(string_view name) const; + + /// Returns the first `config_option` that matches the CLI short option name. + option_pointer cli_short_name_lookup(char short_name) const; + + /// Returns the first `config_option` that matches category and long name. + option_pointer qualified_name_lookup(string_view category, + string_view long_name) const; + + /// Returns the first `config_option` that matches the qualified name. + /// @param name Config option name formatted as `.`. + option_pointer qualified_name_lookup(string_view name) const; + + /// Returns the number of stored config options. + size_t size() const noexcept { + return opts_.size(); + } + + /// Returns the number of stored config options. + bool empty() const noexcept { + return opts_.empty(); + } + + /// Returns an iterator to the first ::config_option object. + iterator begin() noexcept { + return opts_.begin(); + } + + /// Returns an iterator to the first ::config_option object. + const_iterator begin() const noexcept { + return opts_.begin(); + } + + /// Returns the past-the-end iterator. + iterator end() noexcept { + return opts_.end(); + } + + /// Returns the past-the-end iterator. + const_iterator end() const noexcept { + return opts_.end(); + } + + /// Adds a config option to the set. + template + config_option_set& add(string_view category, string_view name, + string_view description) & { + return add(make_config_option(category, name, description)); + } + + /// Adds a config option to the set. + template + config_option_set& add(string_view name, string_view description) & { + return add(make_config_option("global", name, description)); + } + + /// Adds a config option to the set. + template + config_option_set&& add(string_view category, string_view name, + string_view description) && { + return std::move(add(category, name, description)); + } + + /// Adds a config option to the set. + template + config_option_set&& add(string_view name, string_view description) && { + return std::move(add("global", name, description)); + } + + /// Adds a config option to the set that synchronizes its value with `ref`. + template + config_option_set& add(T& ref, string_view category, string_view name, + string_view description) & { + return add(make_config_option(ref, category, name, description)); + } + + /// Adds a config option to the set that synchronizes its value with `ref`. + template + config_option_set& add(T& ref, string_view name, string_view description) & { + return add(ref, "global", name, description); + } + + /// Adds a config option to the set that synchronizes its value with `ref`. + template + config_option_set&& add(T& ref, string_view category, string_view name, + string_view description) && { + return std::move(add(ref, category, name, description)); + } + + /// Adds a config option to the set that synchronizes its value with `ref`. + template + config_option_set&& add(T& ref, string_view name, + string_view description) && { + return std::move(add(ref, "global", name, description)); + } + + /// Adds a config option to the set. + config_option_set& add(config_option opt); + + /// Generates human-readable help text for all options. + std::string help_text(bool global_only = true) const; + + // -- parsing ---------------------------------------------------------------- + + /// Parses a given range as CLI arguments into `config`. + parse_result parse(config_map& config, argument_iterator begin, + argument_iterator end) const; + + /// Parses a given range as CLI arguments into `config`. + parse_result parse(config_map& config, + const std::vector& args) const; + +private: + // -- member variables ------------------------------------------------------- + + option_vector opts_; +}; + +} // namespace caf diff -Nru actor-framework-0.13.2/libcaf_core/caf/config_value.hpp actor-framework-0.16.3/libcaf_core/caf/config_value.hpp --- actor-framework-0.13.2/libcaf_core/caf/config_value.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/config_value.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,598 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include + +#include "caf/atom.hpp" +#include "caf/detail/bounds_checker.hpp" +#include "caf/detail/type_traits.hpp" +#include "caf/dictionary.hpp" +#include "caf/fwd.hpp" +#include "caf/optional.hpp" +#include "caf/raise_error.hpp" +#include "caf/string_algorithms.hpp" +#include "caf/sum_type.hpp" +#include "caf/sum_type_access.hpp" +#include "caf/sum_type_token.hpp" +#include "caf/timestamp.hpp" +#include "caf/uri.hpp" +#include "caf/variant.hpp" + +namespace caf { + +/// A type for config parameters with similar interface to a `variant`. This +/// type is not implemented as a simple variant alias because variants cannot +/// contain lists of themselves. +class config_value { +public: + // -- member types ----------------------------------------------------------- + + using integer = int64_t; + + using boolean = bool; + + using real = double; + + using atom = atom_value; + + using timespan = caf::timespan; + + using string = std::string; + + using list = std::vector; + + using dictionary = caf::dictionary; + + using types = detail::type_list; + + using variant_type = detail::tl_apply_t; + + // -- constructors, destructors, and assignment operators -------------------- + + config_value() = default; + + config_value(config_value&& other) = default; + + config_value(const config_value& other) = default; + + template , config_value>::value>> + explicit config_value(T&& x) { + set(std::forward(x)); + } + + config_value& operator=(config_value&& other) = default; + + config_value& operator=(const config_value& other) = default; + + template , config_value>::value>> + config_value& operator=(T&& x) { + set(std::forward(x)); + return *this; + } + + ~config_value(); + + // -- parsing ---------------------------------------------------------------- + + /// Tries to parse a value from `str`. + static expected parse(string_view::iterator first, + string_view::iterator last); + + /// Tries to parse a value from `str`. + static expected parse(string_view str); + + // -- properties ------------------------------------------------------------- + + /// Converts the value to a list with one element. Does nothing if the value + /// already is a list. + void convert_to_list(); + + /// Appends `x` to a list. Converts this config value to a list first by + /// calling `convert_to_list` if needed. + void append(config_value x); + + /// Returns a human-readable type name of the current value. + const char* type_name() const noexcept; + + /// Returns the underlying variant. + inline variant_type& get_data() { + return data_; + } + + /// Returns the underlying variant. + inline const variant_type& get_data() const { + return data_; + } + + /// Returns a pointer to the underlying variant. + inline variant_type* get_data_ptr() { + return &data_; + } + + /// Returns a pointer to the underlying variant. + inline const variant_type* get_data_ptr() const { + return &data_; + } + +private: + // -- properties ------------------------------------------------------------- + + static const char* type_name_at_index(size_t index) noexcept; + + // -- auto conversion of related types --------------------------------------- + + inline void set(bool x) { + data_ = x; + } + + inline void set(float x) { + data_ = static_cast(x); + } + + inline void set(const char* x) { + data_ = std::string{x}; + } + + template + detail::enable_if_t::value> + set(T x) { + data_ = std::move(x); + } + + template + detail::enable_if_t::value> set(T x) { + data_ = static_cast(x); + } + + // -- member variables ------------------------------------------------------- + + variant_type data_; +}; + +// -- related type aliases ----------------------------------------------------- + +/// Organizes config values into categories. +/// @relates config_value +using config_value_map = dictionary; + +// -- SumType-like access ------------------------------------------------------ + +/// @relates config_value +template +struct config_value_access; + +/// Delegates to config_value_access for all specialized versions. +template ::value> +struct select_config_value_access { + using type = config_value_access; +}; + +/// Catches all non-specialized integer types. +template +struct select_config_value_access { + struct type { + static bool is(const config_value& x) { + auto ptr = caf::get_if(x.get_data_ptr()); + return ptr != nullptr && detail::bounds_checker::check(*ptr); + } + + static optional get_if(const config_value* x) { + auto ptr = caf::get_if(x->get_data_ptr()); + if (ptr != nullptr && detail::bounds_checker::check(*ptr)) + return static_cast(*ptr); + return none; + } + + static T get(const config_value& x) { + auto res = get_if(&x); + CAF_ASSERT(res != none); + return *res; + } + }; +}; + +template +using select_config_value_access_t = + typename select_config_value_access::type; + +template <> +struct sum_type_access { + using types = typename config_value::types; + + using type0 = typename detail::tl_head::type; + + static constexpr bool specialized = true; + + template + static bool is(const config_value& x, sum_type_token token) { + return x.get_data().is(token.pos); + } + + template + static bool is(const config_value& x, sum_type_token) { + return select_config_value_access_t::is(x); + } + + template + static U& get(config_value& x, sum_type_token token) { + return x.get_data().get(token.pos); + } + + template + static U get(config_value& x, sum_type_token) { + return select_config_value_access_t::get(x); + } + + template + static const U& get(const config_value& x, sum_type_token token) { + return x.get_data().get(token.pos); + } + + template + static U get(const config_value& x, sum_type_token) { + return select_config_value_access_t::get(x); + } + + template + static U* get_if(config_value* x, sum_type_token token) { + return is(*x, token) ? &get(*x, token) : nullptr; + } + + template + static optional get_if(config_value* x, sum_type_token) { + return select_config_value_access_t::get_if(x); + } + + template + static const U* get_if(const config_value* x, sum_type_token token) { + return is(*x, token) ? &get(*x, token) : nullptr; + } + + template + static optional get_if(const config_value* x, sum_type_token) { + return select_config_value_access_t::get_if(x); + } + + template + static Result apply(config_value& x, Visitor&& visitor, Ts&&... xs) { + return x.get_data().template apply(std::forward(visitor), + std::forward(xs)...); + } + + template + static Result apply(const config_value& x, Visitor&& visitor, Ts&&... xs) { + return x.get_data().template apply(std::forward(visitor), + std::forward(xs)...); + } +}; + +template <> +struct config_value_access { + static constexpr bool specialized = true; + + static bool is(const config_value& x) { + return holds_alternative(x.get_data()); + } + + static optional get_if(const config_value* x) { + auto res = caf::get_if(&(x->get_data())); + if (res) + return static_cast(*res); + return none; + } + + static float get(const config_value& x) { + return static_cast(caf::get(x.get_data())); + } +}; + +/// Implements automagic unboxing of `std::vector` from a homogeneous +/// `config_value::list`. +/// @relates config_value +template +struct config_value_access> { + using vector_type = std::vector; + + static constexpr bool specialized = true; + + static bool is(const config_value& x) { + auto lst = caf::get_if(&x); + if (lst != nullptr) { + return std::all_of(lst->begin(), lst->end(), [](const config_value& y) { + return caf::holds_alternative(y); + }); + } + return false; + } + + static optional get_if(const config_value* x) { + vector_type result; + auto extract = [&](const config_value& y) { + auto opt = caf::get_if(&y); + if (opt) { + result.emplace_back(*opt); + return true; + } + return false; + }; + auto lst = caf::get_if(x); + if (lst != nullptr && std::all_of(lst->begin(), lst->end(), extract)) + return result; + return none; + } + + static vector_type get(const config_value& x) { + auto result = get_if(&x); + if (!result) + CAF_RAISE_ERROR("invalid type found"); + return std::move(*result); + } +}; + +/// Implements automagic unboxing of `dictionary` from a homogeneous +/// `config_value::dictionary`. +/// @relates config_value +template +struct config_value_access> { + using map_type = dictionary; + + using kvp = std::pair; + + static constexpr bool specialized = true; + + static bool is(const config_value& x) { + auto lst = caf::get_if(&x); + if (lst != nullptr) { + return std::all_of(lst->begin(), lst->end(), [](const kvp& y) { + return holds_alternative(y.second); + }); + } + return false; + } + + static optional get_if(const config_value* x) { + map_type result; + auto extract = [&](const kvp& y) { + auto opt = caf::get_if(&(y.second)); + if (opt) { + result.emplace(y.first, std::move(*opt)); + return true; + } + return false; + }; + auto lst = caf::get_if(x); + if (lst != nullptr && std::all_of(lst->begin(), lst->end(), extract)) + return result; + return none; + } + + static map_type get(const config_value& x) { + auto result = get_if(&x); + if (!result) + CAF_RAISE_ERROR("invalid type found"); + return std::move(*result); + } +}; + +// -- SumType-like access of dictionary values --------------------------------- + +/// Tries to retrieve the value associated to `name` from `xs`. +/// @relates config_value +template +optional get_if(const config_value::dictionary* xs, string_view name) { + // Split the name into a path. + std::vector path; + split(path, name, "."); + // Sanity check. + if (path.size() == 0) + return none; + // Resolve path, i.e., find the requested submap. + auto current = xs; + auto leaf = path.end() - 1; + for (auto i = path.begin(); i != leaf; ++i) { + auto j = current->find(*i); + if (j == current->end()) + return none; + current = caf::get_if(&j->second); + if (current == nullptr) + return none; + } + // Get the leaf value. + auto j = current->find(*leaf); + if (j == current->end()) + return none; + auto result = caf::get_if(&j->second); + if (result) + return *result; + return none; +} + +/// Retrieves the value associated to `name` from `xs`. +/// @relates config_value +template +T get(const config_value::dictionary& xs, string_view name) { + auto result = get_if(&xs, name); + if (result) + return std::move(*result); + CAF_RAISE_ERROR("invalid type or name found"); +} + +/// Retrieves the value associated to `name` from `xs` or returns +/// `default_value`. +/// @relates config_value +template ::value>> +T get_or(const config_value::dictionary& xs, string_view name, + const T& default_value) { + auto result = get_if(&xs, name); + if (result) + return std::move(*result); + return default_value; +} + +/// Retrieves the value associated to `name` from `xs` or returns +/// `default_value`. +/// @relates config_value +std::string get_or(const config_value::dictionary& xs, string_view name, + const char* default_value); + +/// Tries to retrieve the value associated to `name` from `xs`. +/// @relates config_value +template +optional get_if(const config_value_map* xs, string_view name) { + // Get the category. + auto pos = name.find('.'); + if (pos == std::string::npos) { + auto i = xs->find("global"); + if (i == xs->end()) + return none; + return get_if(&i->second, name); + } + auto i = xs->find(name.substr(0, pos)); + if (i == xs->end()) + return none; + return get_if(&i->second, name.substr(pos + 1)); +} + +/// Retrieves the value associated to `name` from `xs`. +/// @relates config_value +template +T get(const config_value_map& xs, string_view name) { + auto result = get_if(&xs, name); + if (result) + return std::move(*result); + CAF_RAISE_ERROR("invalid type or name found"); +} + +/// Retrieves the value associated to `name` from `xs` or returns +/// `default_value`. +/// @relates config_value +template ::value>> +T get_or(const config_value_map& xs, string_view name, const T& default_value) { + auto result = get_if(&xs, name); + if (result) + return std::move(*result); + return default_value; +} + +/// Retrieves the value associated to `name` from `xs` or returns +/// `default_value`. +/// @relates config_value +std::string get_or(const config_value_map& xs, string_view name, + const char* default_value); + +/// Tries to retrieve the value associated to `name` from `cfg`. +/// @relates config_value +template +optional get_if(const actor_system_config* cfg, string_view name) { + return get_if(&content(*cfg), name); +} + +/// Retrieves the value associated to `name` from `cfg`. +/// @relates config_value +template +T get(const actor_system_config& cfg, string_view name) { + return get(content(cfg), name); +} + +/// Retrieves the value associated to `name` from `cfg` or returns +/// `default_value`. +/// @relates config_value +template ::value>> +T get_or(const actor_system_config& cfg, string_view name, + const T& default_value) { + return get_or(content(cfg), name, default_value); +} + +std::string get_or(const actor_system_config& cfg, string_view name, + const char* default_value); + +/// @private +void put_impl(config_value::dictionary& dict, + const std::vector& path, config_value& value); + +/// @private +void put_impl(config_value::dictionary& dict, string_view key, + config_value& value); + +/// @private +void put_impl(dictionary& dict, string_view key, + config_value& value); + +/// Converts `value` to a `config_value` and assigns it to `key`. +/// @param dict Dictionary of key-value pairs. +/// @param key Human-readable nested keys in the form `category.key`. +/// @param value New value for given `key`. +template +void put(dictionary& dict, string_view key, + T&& value) { + config_value tmp{std::forward(value)}; + put_impl(dict, key, tmp); +} + +/// Inserts a new list named `name` into the dictionary `xs` and returns +/// a reference to it. Overrides existing entries with the same name. +config_value::list& put_list(config_value::dictionary& xs, std::string name); + +/// Inserts a new list named `name` into the dictionary `xs` and returns +/// a reference to it. Overrides existing entries with the same name. +config_value::dictionary& put_dictionary(config_value::dictionary& xs, + std::string name); + +/// @relates config_value +bool operator<(const config_value& x, const config_value& y); + +/// @relates config_value +bool operator==(const config_value& x, const config_value& y); + +/// @relates config_value +inline bool operator>=(const config_value& x, const config_value& y) { + return !(x < y); +} + +/// @relates config_value +inline bool operator!=(const config_value& x, const config_value& y) { + return !(x == y); +} + +/// @relates config_value +std::string to_string(const config_value& x); + +template +config_value make_config_value_list(Ts&&... xs) { + std::vector lst{config_value{std::forward(xs)}...}; + return config_value{std::move(lst)}; +} + +/// @relates config_value +template +typename Inspector::result_type inspect(Inspector& f, config_value& x) { + return f(meta::type_name("config_value"), x.get_data()); +} + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/continue_helper.hpp actor-framework-0.16.3/libcaf_core/caf/continue_helper.hpp --- actor-framework-0.13.2/libcaf_core/caf/continue_helper.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/continue_helper.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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 CONTINUE_HELPER_HPP -#define CONTINUE_HELPER_HPP - -#include - -#include "caf/on.hpp" -#include "caf/behavior.hpp" -#include "caf/message_id.hpp" -#include "caf/message_handler.hpp" - -namespace caf { - -class local_actor; - -/** - * Helper class to enable users to add continuations - * when dealing with synchronous sends. - */ -class continue_helper { - public: - using message_id_wrapper_tag = int; - continue_helper(message_id mid); - - /** - * Returns the ID of the expected response message. - */ - message_id get_message_id() const { - return m_mid; - } - - private: - message_id m_mid; -}; - -} // namespace caf - -#endif // CONTINUE_HELPER_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/cow_tuple.hpp actor-framework-0.16.3/libcaf_core/caf/cow_tuple.hpp --- actor-framework-0.13.2/libcaf_core/caf/cow_tuple.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/cow_tuple.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,130 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/detail/comparable.hpp" +#include "caf/detail/tuple_vals.hpp" +#include "caf/make_copy_on_write.hpp" + +namespace caf { + +/// A copy-on-write tuple implementation. +template +class cow_tuple : detail::comparable>, + detail::comparable, std::tuple> { +public: + // -- member types ----------------------------------------------------------- + + using impl = detail::tuple_vals; + + using data_type = std::tuple; + + // -- constructors, destructors, and assignment operators -------------------- + + explicit cow_tuple(Ts... xs) + : ptr_(make_copy_on_write(std::move(xs)...)) { + // nop + } + + cow_tuple() : ptr_(make_copy_on_write()) { + // nop + } + + cow_tuple(cow_tuple&&) = default; + + cow_tuple(const cow_tuple&) = default; + + cow_tuple& operator=(cow_tuple&&) = default; + + cow_tuple& operator=(const cow_tuple&) = default; + + // -- properties ------------------------------------------------------------- + + /// Returns the managed tuple. + const data_type& data() const noexcept { + return ptr_->data(); + } + + /// Returns a mutable reference to the managed tuple, guaranteed to have a + /// reference count of 1. + data_type& unshared() { + return ptr_.unshared().data(); + } + + /// Returns whether the reference count of the managed object is 1. + bool unique() const noexcept { + return ptr_->unique(); + } + + /// @private + const intrusive_cow_ptr& ptr() const noexcept { + return ptr_; + } + + // -- comparison ------------------------------------------------------------- + + template + int compare(const std::tuple& other) const noexcept { + return data() < other ? -1 : (data() == other ? 0 : 1); + } + + template + int compare(const cow_tuple& other) const noexcept { + return compare(other.data()); + } + +private: + // -- member variables ------------------------------------------------------- + + intrusive_cow_ptr ptr_; +}; + +/// @relates cow_tuple +template +typename std::enable_if::type +inspect(Inspector& f, const cow_tuple& x) { + return f(x.data()); +} + +/// @relates cow_tuple +template +typename std::enable_if::type +inspect(Inspector& f, cow_tuple& x) { + return f(x.unshared()); +} + +/// Creates a new copy-on-write tuple from given arguments. +/// @relates cow_tuple +template +cow_tuple::type...> make_cow_tuple(Ts&&... xs) { + return cow_tuple::type...>{std::forward(xs)...}; +} + +/// Convenience function for calling `get(xs.data())`. +/// @relates cow_tuple +template +auto get(const cow_tuple& xs) -> decltype(std::get(xs.data())) { + return std::get(xs.data()); +} + +} // namespace caf diff -Nru actor-framework-0.13.2/libcaf_core/caf/data_processor.hpp actor-framework-0.16.3/libcaf_core/caf/data_processor.hpp --- actor-framework-0.13.2/libcaf_core/caf/data_processor.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/data_processor.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,587 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include // size_t +#include +#include + +#include "caf/fwd.hpp" +#include "caf/atom.hpp" +#include "caf/error.hpp" +#include "caf/timestamp.hpp" +#include "caf/allowed_unsafe_message_type.hpp" + +#include "caf/meta/annotation.hpp" +#include "caf/meta/save_callback.hpp" +#include "caf/meta/load_callback.hpp" + +#include "caf/detail/type_list.hpp" +#include "caf/detail/apply_args.hpp" +#include "caf/detail/delegate_serialize.hpp" +#include "caf/detail/select_integer_type.hpp" + +namespace caf { + + +/// A data processor translates an object into a format that can be +/// stored or vice versa. A data processor can be either in saving +/// or loading mode. +template +class data_processor { +public: + // -- member types ----------------------------------------------------------- + + /// Return type for `operator()`. + using result_type = error; + + /// List of builtin types for data processors. + using builtin_t = + detail::type_list< + int8_t, + uint8_t, + int16_t, + uint16_t, + int32_t, + uint32_t, + int64_t, + uint64_t, + float, + double, + long double, + std::string, + std::u16string, + std::u32string + >; + + /// List of builtin types for data processors as enum. + enum builtin { + i8_v, + u8_v, + i16_v, + u16_v, + i32_v, + u32_v, + i64_v, + u64_v, + float_v, + double_v, + ldouble_v, + string8_v, + string16_v, + string32_v + }; + + // -- constructors, destructors, and assignment operators -------------------- + + data_processor(const data_processor&) = delete; + data_processor& operator=(const data_processor&) = delete; + + data_processor(execution_unit* ctx = nullptr) : context_(ctx) { + // nop + } + + virtual ~data_processor() { + // nop + } + + // -- pure virtual functions ------------------------------------------------- + + /// Begins processing of an object. Saves the type information + /// to the underlying storage when in saving mode, otherwise + /// extracts them and sets both arguments accordingly. + virtual error begin_object(uint16_t& typenr, std::string& name) = 0; + + /// Ends processing of an object. + virtual error end_object() = 0; + + /// Begins processing of a sequence. Saves the size + /// to the underlying storage when in saving mode, otherwise + /// sets `num` accordingly. + virtual error begin_sequence(size_t& num) = 0; + + /// Ends processing of a sequence. + virtual error end_sequence() = 0; + + // -- getter ----------------------------------------------------------------- + + /// Returns the actor system associated to this data processor. + execution_unit* context() { + return context_; + } + + // -- apply functions -------------------------------------------------------- + + /// Applies this processor to an arithmetic type. + template + typename std::enable_if::value, error>::type + apply(T& x) { + static constexpr auto tlindex = detail::tl_index_of::value; + static_assert(tlindex >= 0, "T not recognized as builtin type"); + return apply_builtin(static_cast(tlindex), &x); + } + + template + typename std::enable_if< + std::is_integral::value + && !std::is_same::value, + error + >::type + apply(T& x) { + using type = + typename detail::select_integer_type< + static_cast(sizeof(T)) * (std::is_signed::value ? -1 : 1) + >::type; + static constexpr auto tlindex = detail::tl_index_of::value; + static_assert(tlindex >= 0, "T not recognized as builtin type"); + return apply_builtin(static_cast(tlindex), &x); + } + + error apply(std::string& x) { + return apply_builtin(string8_v, &x); + } + + error apply(std::u16string& x) { + return apply_builtin(string16_v, &x); + } + + error apply(std::u32string& x) { + return apply_builtin(string32_v, &x); + } + + template + static error apply_atom_constant(D& self, atom_constant&) { + static_assert(!D::writes_state, "cannot deserialize an atom_constant"); + auto x = V; + return self.apply(x); + } + + template + error apply(atom_constant& x) { + return apply_atom_constant(dref(), x); + } + + /// Serializes enums using the underlying type + /// if no user-defined serialization is defined. + template + typename std::enable_if< + std::is_enum::value + && !detail::has_serialize::value, + error + >::type + apply(T& x) { + using underlying = typename std::underlying_type::type; + struct { + void operator()(T& lhs, underlying& rhs) const { + lhs = static_cast(rhs); + } + void operator()(underlying& lhs, T& rhs) const { + lhs = static_cast(rhs); + } + } assign; + underlying tmp; + return convert_apply(dref(), x, tmp, assign); + } + + /// Applies this processor to an empty type. + template + typename std::enable_if< + std::is_empty::value && !detail::is_inspectable::value, + error + >::type + apply(T&) { + return none; + } + + error apply(bool& x) { + struct { + void operator()(bool& lhs, uint8_t& rhs) const { + lhs = rhs != 0; + } + void operator()(uint8_t& lhs, bool& rhs) const { + lhs = rhs ? 1 : 0; + } + } assign; + uint8_t tmp; + return convert_apply(dref(), x, tmp, assign); + } + + // Special case to avoid using 1 byte per bool + error apply(std::vector& x) { + auto len = x.size(); + auto err = begin_sequence(len); + if (err || len == 0) + return err; + struct { + size_t len; + void operator()(std::vector& lhs, std::vector& rhs) const { + lhs.resize(len, false); + size_t cpt = 0; + for (auto v: rhs) { + for (int k = 0; k < 8; ++k) { + lhs[cpt] = ((v & (1 << k)) != 0); + if (++cpt >= len) + return; + } + } + } + void operator()(std::vector& lhs, std::vector& rhs) const { + size_t k = 0; + lhs.resize((rhs.size() - 1) / 8 + 1, 0); + for (bool b: rhs) { + if (b) + lhs[k / 8] |= (1 << (k % 8)); + ++k; + } + } + } assign; + assign.len = len; + std::vector tmp; + return convert_apply(dref(), x, tmp, assign); + } + + template + error consume_range(T& xs) { + for (auto& x : xs) { + using value_type = typename std::remove_const< + typename std::remove_reference::type + >::type; + auto e = apply(const_cast(x)); + if (e) + return e; + } + return none; + } + + /// Converts each element in `xs` to `U` before calling `apply`. + template + error consume_range_c(T& xs) { + for (U x : xs) { + auto e = apply(x); + if (e) + return e; + } + return none; + } + + template + error fill_range(T& xs, size_t num_elements) { + xs.clear(); + auto insert_iter = std::inserter(xs, xs.end()); + for (size_t i = 0; i < num_elements; ++i) { + typename std::remove_const::type x; + auto err = apply(x); + if (err) + return err; + *insert_iter++ = std::move(x); + } + return none; + } + + /// Loads elements from type `U` before inserting to `xs`. + template + error fill_range_c(T& xs, size_t num_elements) { + xs.clear(); + auto insert_iter = std::inserter(xs, xs.end()); + for (size_t i = 0; i < num_elements; ++i) { + U x; + auto err = apply(x); + if (err) + return err; + *insert_iter++ = std::move(x); + } + return none; + } + // Applies this processor as Derived to `xs` in saving mode. + template + static typename std::enable_if< + D::reads_state && !detail::is_byte_sequence::value, + error + >::type + apply_sequence(D& self, T& xs) { + auto s = xs.size(); + return error::eval([&] { return self.begin_sequence(s); }, + [&] { return self.consume_range(xs); }, + [&] { return self.end_sequence(); }); + } + + // Applies this processor as Derived to `xs` in loading mode. + template + static typename std::enable_if< + !D::reads_state && !detail::is_byte_sequence::value, + error + >::type + apply_sequence(D& self, T& xs) { + size_t s; + return error::eval([&] { return self.begin_sequence(s); }, + [&] { return self.fill_range(xs, s); }, + [&] { return self.end_sequence(); }); + } + + // Optimized saving for contiguous byte sequences. + template + static typename std::enable_if< + D::reads_state && detail::is_byte_sequence::value, + error + >::type + apply_sequence(D& self, T& xs) { + auto s = xs.size(); + return error::eval([&] { return self.begin_sequence(s); }, + [&] { return s > 0 ? self.apply_raw(xs.size(), &xs[0]) + : none; }, + [&] { return self.end_sequence(); }); + } + + // Optimized loading for contiguous byte sequences. + template + static typename std::enable_if< + !D::reads_state && detail::is_byte_sequence::value, + error + >::type + apply_sequence(D& self, T& xs) { + size_t s; + return error::eval([&] { return self.begin_sequence(s); }, + [&] { xs.resize(s); + return s > 0 ? self.apply_raw(s, &xs[0]) + : none; }, + [&] { return self.end_sequence(); }); + } + + /// Applies this processor to a sequence of values. + template + typename std::enable_if< + detail::is_iterable::value + && !detail::has_serialize::value + && !detail::is_inspectable::value, + error + >::type + apply(T& xs) { + return apply_sequence(dref(), xs); + } + + /// Applies this processor to an array. + template + typename std::enable_if::value, error>::type + apply(std::array& xs) { + return consume_range(xs); + } + + /// Applies this processor to an array. + template + typename std::enable_if::value, error>::type + apply(T (&xs) [S]) { + return consume_range(xs); + } + + template + typename std::enable_if< + detail::is_serializable::type>::value + && detail::is_serializable::value, + error + >::type + apply(std::pair& xs) { + using t0 = typename std::remove_const::type; + // This cast allows the data processor to cope with + // `pair` value types used by `std::map`. + return error::eval([&] { return apply(const_cast(xs.first)); }, + [&] { return apply(xs.second); }); + } + + template + typename std::enable_if< + detail::conjunction< + detail::is_serializable::value... + >::value, + error + >::type + apply(std::tuple& xs) { + //apply_helper f{*this}; + return detail::apply_args(*this, detail::get_indices(xs), xs); + } + + template + typename std::enable_if< + !std::is_empty::value + && detail::has_serialize::value, + error + >::type + apply(T& x) { + // throws on error + detail::delegate_serialize(dref(), x); + return none; + } + + template + typename std::enable_if::value, error>::type + apply(std::chrono::duration& x) { + using duration_type = std::chrono::duration; + // always save/store durations as int64_t to work around possibly + // different integer types on different plattforms for standard typedefs + struct { + void operator()(duration_type& lhs, Rep& rhs) const { + duration_type tmp{rhs}; + lhs = tmp; + } + void operator()(Rep& lhs, duration_type& rhs) const { + lhs = rhs.count(); + } + } assign; + Rep tmp; + return convert_apply(dref(), x, tmp, assign); + } + + template + typename std::enable_if::value, error>::type + apply(std::chrono::duration& x) { + using duration_type = std::chrono::duration; + // always save/store floating point durations + // as doubles for the same reason as above + struct { + void operator()(duration_type& lhs, double& rhs) const { + duration_type tmp{rhs}; + lhs = tmp; + } + void operator()(double& lhs, duration_type& rhs) const { + lhs = rhs.count(); + } + } assign; + double tmp; + return convert_apply(dref(), x, tmp, assign); + } + + template + error apply(std::chrono::time_point& t) { + if (Derived::reads_state) { + auto dur = t.time_since_epoch(); + return apply(dur); + } + if (Derived::writes_state) { + Duration dur{}; + auto e = apply(dur); + t = std::chrono::time_point{dur}; + return e; + } + } + + /// Applies this processor to a raw block of data of size `num_bytes`. + virtual error apply_raw(size_t num_bytes, void* data) = 0; + + template + typename std::enable_if< + detail::is_inspectable::value + && !detail::has_serialize::value, + decltype(inspect(std::declval(), std::declval())) + >::type + apply(T& x) { + return inspect(dref(), x); + } + + // -- operator() ------------------------------------------------------------- + + inline error operator()() { + return none; + } + + template + error operator()(meta::save_callback_t x, Ts&&... xs) { + error e; + if (Derived::reads_state) + e = x.fun(); + return e ? e : (*this)(std::forward(xs)...); + } + + template + error operator()(meta::load_callback_t x, Ts&&... xs) { + error e; + if (Derived::writes_state) + e = x.fun(); + return e ? e : (*this)(std::forward(xs)...); + } + + template + error operator()(const meta::annotation&, Ts&&... xs) { + return (*this)(std::forward(xs)...); + } + + template + typename std::enable_if< + is_allowed_unsafe_message_type::value, + error + >::type + operator()(const T&, Ts&&... xs) { + return (*this)(std::forward(xs)...); + } + + template + typename std::enable_if< + !meta::is_annotation::value + && !is_allowed_unsafe_message_type::value, + error + >::type + operator()(T&& x, Ts&&... xs) { + static_assert(Derived::reads_state + || (!std::is_rvalue_reference::value + && !std::is_const< + typename std::remove_reference::type + >::value), + "a loading inspector requires mutable lvalue references"); + auto e = apply(deconst(x)); + return e ? e : (*this)(std::forward(xs)...); + } + +protected: + /// Applies this processor to a single builtin value. + virtual error apply_builtin(builtin in_out_type, void* in_out) = 0; + +private: + template + T& deconst(const T& x) { + return const_cast(x); + } + + template + static typename std::enable_if::type + convert_apply(D& self, T& x, U& storage, F assign) { + assign(storage, x); + return self.apply(storage); + } + + template + static typename std::enable_if::type + convert_apply(D& self, T& x, U& storage, F assign) { + auto e = self.apply(storage); + if (e) + return e; + assign(x, storage); + return none; + } + + // Returns a reference to the derived type. + Derived& dref() { + return *static_cast(this); + } + + execution_unit* context_; +}; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/decorator/sequencer.hpp actor-framework-0.16.3/libcaf_core/caf/decorator/sequencer.hpp --- actor-framework-0.13.2/libcaf_core/caf/decorator/sequencer.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/decorator/sequencer.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,60 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include "caf/actor_addr.hpp" +#include "caf/mailbox_element.hpp" +#include "caf/monitorable_actor.hpp" + +namespace caf { +namespace decorator { + +/// An actor decorator implementing "dot operator"-like compositions, +/// i.e., `f.g(x) = f(g(x))`. Composed actors are hidden actors. +/// A composed actor exits when either of its constituent actors exits; +/// Constituent actors have no dependency on the composed actor +/// by default, and exit of a composed actor has no effect on its +/// constituent actors. A composed actor is hosted on the same actor +/// system and node as `g`, the first actor on the forwarding chain. +class sequencer : public monitorable_actor { +public: + using message_types_set = std::set; + + sequencer(strong_actor_ptr f, strong_actor_ptr g, + message_types_set msg_types); + + // non-system messages are processed and then forwarded; + // system messages are handled and consumed on the spot; + // in either case, the processing is done synchronously + void enqueue(mailbox_element_ptr what, execution_unit* context) override; + + message_types_set message_types() const override; + +protected: + void on_cleanup(const error& reason) override; + +private: + strong_actor_ptr f_; + strong_actor_ptr g_; + message_types_set msg_types_; +}; + +} // namespace decorator +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/decorator/splitter.hpp actor-framework-0.16.3/libcaf_core/caf/decorator/splitter.hpp --- actor-framework-0.13.2/libcaf_core/caf/decorator/splitter.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/decorator/splitter.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,58 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/actor_addr.hpp" +#include "caf/mailbox_element.hpp" +#include "caf/monitorable_actor.hpp" + +namespace caf { +namespace decorator { + +/// An actor decorator implementing "dot operator"-like compositions, +/// i.e., `f.g(x) = f(g(x))`. Composed actors are hidden actors. +/// A composed actor exits when either of its constituent actors exits; +/// Constituent actors have no dependency on the composed actor +/// by default, and exit of a composed actor has no effect on its +/// constituent actors. A composed actor is hosted on the same actor +/// system and node as `g`, the first actor on the forwarding chain. +class splitter : public monitorable_actor { +public: + using message_types_set = std::set; + + splitter(std::vector workers, message_types_set msg_types); + + // non-system messages are processed and then forwarded; + // system messages are handled and consumed on the spot; + // in either case, the processing is done synchronously + void enqueue(mailbox_element_ptr what, execution_unit* context) override; + + message_types_set message_types() const override; + +private: + const size_t num_workers; + std::vector workers_; + message_types_set msg_types_; +}; + +} // namespace decorator +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/deduce_mpi.hpp actor-framework-0.16.3/libcaf_core/caf/deduce_mpi.hpp --- actor-framework-0.13.2/libcaf_core/caf/deduce_mpi.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/deduce_mpi.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,127 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/fwd.hpp" +#include "caf/param.hpp" +#include "caf/expected.hpp" +#include "caf/optional.hpp" +#include "caf/replies_to.hpp" + +#include "caf/detail/implicit_conversions.hpp" + +namespace caf { + +namespace detail { + +// dmi = deduce_mpi_implementation +template +struct dmi; + +// case #1: function returning a single value +template +struct dmi { + using type = typed_mpi::type...>, + output_tuple>>; +}; + +// case #2a: function returning a result<...> +template +struct dmi (Xs...)> { + using type = typed_mpi::type...>, + output_tuple...>>; +}; + +// case #2b: function returning a std::tuple<...> +template +struct dmi (Xs...)> { + using type = typed_mpi::type...>, + output_tuple...>>; +}; + +// case #2c: function returning a std::tuple<...> +template +struct dmi (Xs...)> { + using type = typed_mpi::type...>, + output_tuple...>>; +}; + +// case #2d: function returning a typed_response_promise<...> +template +struct dmi (Xs...)> { + using type = typed_mpi::type...>, + output_tuple...>>; +}; + +// case #3: function returning an optional<> +template +struct dmi (Xs...)> : dmi {}; + +// case #4: function returning an expected<> +template +struct dmi (Xs...)> : dmi {}; + +// case #5: function returning an output_stream<> +template +struct dmi, P> (Xs...)> : dmi { + using type = + typed_mpi::type...>, + output_tuple, strip_and_convert_t...>>; +}; + +// -- dmfou = deduce_mpi_function_object_unboxing + +template ::value> +struct dmfou; + +// case #1: const member function pointer +template +struct dmfou : dmi {}; + +// case #2: member function pointer +template +struct dmfou : dmi {}; + +// case #3: good ol' function +template +struct dmfou : dmi {}; + +template +struct dmfou : dmfou {}; + +// this specialization leaves timeout definitions untouched, +// later stages such as interface_mismatch need to deal with them later +template +struct dmfou, true> { + using type = timeout_definition; +}; + +template +struct dmfou, true> : dmfou {}; + +} // namespace detail + +/// Deduces the message passing interface from a function object. +template +using deduce_mpi_t = typename detail::dmfou::type>::type; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/deep_to_string.hpp actor-framework-0.16.3/libcaf_core/caf/deep_to_string.hpp --- actor-framework-0.13.2/libcaf_core/caf/deep_to_string.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/deep_to_string.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,64 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "caf/atom.hpp" +#include "caf/detail/apply_args.hpp" +#include "caf/detail/type_traits.hpp" +#include "caf/detail/stringification_inspector.hpp" + +namespace caf { + +class deep_to_string_t { +public: + constexpr deep_to_string_t() { + // nop + } + + template + std::string operator()(Ts&&... xs) const { + std::string result; + detail::stringification_inspector f{result}; + f(std::forward(xs)...); + return result; + } +}; + +/// Unrolls collections such as vectors/maps, decomposes +/// tuples/pairs/arrays, auto-escapes strings and calls +/// `to_string` for user-defined types via argument-dependent +/// loopkup (ADL). Any user-defined type that does not +/// provide a `to_string` is mapped to ``. +constexpr deep_to_string_t deep_to_string = deep_to_string_t{}; + +/// Convenience function for `deep_to_string(std::forward_as_tuple(xs...))`. +template +std::string deep_to_string_as_tuple(Ts&&... xs) { + return deep_to_string(std::forward_as_tuple(std::forward(xs)...)); +} + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/default_attachable.hpp actor-framework-0.16.3/libcaf_core/caf/default_attachable.hpp --- actor-framework-0.13.2/libcaf_core/caf/default_attachable.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/default_attachable.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DEFAULT_ATTACHABLE_HPP -#define CAF_DEFAULT_ATTACHABLE_HPP +#pragma once #include "caf/actor_addr.hpp" #include "caf/attachable.hpp" @@ -26,7 +24,7 @@ namespace caf { class default_attachable : public attachable { - public: +public: enum observe_type { monitor, link @@ -38,42 +36,57 @@ static constexpr size_t token_type = attachable::token::observer; }; - void actor_exited(abstract_actor* self, uint32_t reason) override; + void actor_exited(const error& rsn, execution_unit* host) override; bool matches(const token& what) override; - inline static attachable_ptr make_monitor(actor_addr observer) { - return attachable_ptr{new default_attachable(std::move(observer), monitor)}; + static attachable_ptr + make_monitor(actor_addr observed, actor_addr observer, + message_priority prio = message_priority::normal) { + return attachable_ptr{new default_attachable( + std::move(observed), std::move(observer), monitor, prio)}; } - inline static attachable_ptr make_link(actor_addr observer) { - return attachable_ptr{new default_attachable(std::move(observer), link)}; + static attachable_ptr make_link(actor_addr observed, actor_addr observer) { + return attachable_ptr{new default_attachable(std::move(observed), + std::move(observer), link)}; } class predicate { - public: + public: inline predicate(actor_addr observer, observe_type type) - : m_observer(std::move(observer)), - m_type(type) { + : observer_(std::move(observer)), + type_(type) { // nop } inline bool operator()(const attachable_ptr& ptr) const { - return ptr->matches(observe_token{m_observer, m_type}); + return ptr->matches(observe_token{observer_, type_}); } - private: - actor_addr m_observer; - observe_type m_type; + private: + actor_addr observer_; + observe_type type_; }; - private: - default_attachable(actor_addr observer, observe_type type); - actor_addr m_observer; - observe_type m_type; +private: + default_attachable(actor_addr observed, actor_addr observer, + observe_type type, + message_priority prio = message_priority::normal); + + /// Holds a weak reference to the observed actor. + actor_addr observed_; + + /// Holds a weak reference to the observing actor. + actor_addr observer_; + + /// Defines the type of message we wish to send. + observe_type type_; + + /// Defines the priority for the message. + message_priority priority_; }; } // namespace caf -#endif // CAF_DEFAULT_ATTACHABLE_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/default_downstream_manager.hpp actor-framework-0.16.3/libcaf_core/caf/default_downstream_manager.hpp --- actor-framework-0.13.2/libcaf_core/caf/default_downstream_manager.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/default_downstream_manager.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,59 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include "caf/broadcast_downstream_manager.hpp" +#include "caf/stream_source_trait.hpp" +#include "caf/stream_stage_trait.hpp" + +#include "caf/detail/type_traits.hpp" + +namespace caf { + +/// Selects a downstream manager implementation based on the signature of +/// various handlers. +template +struct default_downstream_manager { + /// The function signature of `F`. + using fun_sig = typename detail::get_callable_trait::fun_sig; + + /// The source trait for `F`. + using source_trait = stream_source_trait; + + /// The stage trait for `F`. + using stage_trait = stream_stage_trait; + + /// The output type as returned by the source or stage trait. + using output_type = + typename std::conditional< + source_trait::valid, + typename source_trait::output, + typename stage_trait::output + >::type; + + /// The default downstream manager deduced by this trait. + using type = broadcast_downstream_manager; +}; + +template +using default_downstream_manager_t = + typename default_downstream_manager::type; + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/defaults.hpp actor-framework-0.16.3/libcaf_core/caf/defaults.hpp --- actor-framework-0.13.2/libcaf_core/caf/defaults.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/defaults.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,86 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include + +#include "caf/atom.hpp" +#include "caf/timestamp.hpp" + +// -- hard-coded default values for various CAF options ------------------------ + +namespace caf { +namespace defaults { + +namespace stream { + +extern const timespan desired_batch_complexity; +extern const timespan max_batch_delay; +extern const timespan credit_round_interval; + +} // namespace streaming + +namespace scheduler { + +extern const atom_value policy; +extern const char* profiling_output_file; +extern const size_t max_threads; +extern const size_t max_throughput; +extern const timespan profiling_resolution; + +} // namespace scheduler + +namespace work_stealing { + +extern const size_t aggressive_poll_attempts; +extern const size_t aggressive_steal_interval; +extern const size_t moderate_poll_attempts; +extern const size_t moderate_steal_interval; +extern const timespan moderate_sleep_duration; +extern const size_t relaxed_steal_interval; +extern const timespan relaxed_sleep_duration; + +} // namespace work_stealing + +namespace logger { + +extern const char* component_filter; +extern const atom_value console; +extern const char* console_format; +extern const atom_value console_verbosity; +extern const char* file_format; +extern const char* file_name; +extern const atom_value file_verbosity; + +} // namespace logger + +namespace middleman { + +extern const char* app_identifier; +extern const atom_value network_backend; +extern const size_t max_consecutive_reads; +extern const size_t heartbeat_interval; +extern const size_t cached_udp_buffers; +extern const size_t max_pending_msgs; + +} // namespace middleman + +} // namespace defaults +} // namespace caf diff -Nru actor-framework-0.13.2/libcaf_core/caf/default_sum_type_access.hpp actor-framework-0.16.3/libcaf_core/caf/default_sum_type_access.hpp --- actor-framework-0.13.2/libcaf_core/caf/default_sum_type_access.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/default_sum_type_access.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,78 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include +#include + +#include "caf/detail/type_list.hpp" +#include "caf/sum_type_token.hpp" + +namespace caf { + +/// Allows specializing the `sum_type_access` trait for any type that simply +/// wraps a `variant` and exposes it with a `get_data()` member function. +template +struct default_sum_type_access { + using types = typename T::types; + + using type0 = typename detail::tl_head::type; + + static constexpr bool specialized = true; + + template + static bool is(const T& x, sum_type_token token) { + return x.get_data().is(token.pos); + } + + template + static U& get(T& x, sum_type_token token) { + return x.get_data().get(token.pos); + } + + template + static const U& get(const T& x, sum_type_token token) { + return x.get_data().get(token.pos); + } + + template + static U* get_if(T* x, sum_type_token token) { + return is(*x, token) ? &get(*x, token) : nullptr; + } + + template + static const U* get_if(const T* x, sum_type_token token) { + return is(*x, token) ? &get(*x, token) : nullptr; + } + + template + static Result apply(T& x, Visitor&& visitor, Ts&&... xs) { + return x.get_data().template apply(std::forward(visitor), + std::forward(xs)...); + } + + template + static Result apply(const T& x, Visitor&& visitor, Ts&&... xs) { + return x.get_data().template apply(std::forward(visitor), + std::forward(xs)...); + } +}; + +} // namespace caf diff -Nru actor-framework-0.13.2/libcaf_core/caf/delegated.hpp actor-framework-0.16.3/libcaf_core/caf/delegated.hpp --- actor-framework-0.13.2/libcaf_core/caf/delegated.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/delegated.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,38 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +namespace caf { + +/// Helper class to indicate that a request has been forwarded. +template +class delegated { + // nop +}; + + +template +inline bool operator==(const delegated&, const delegated&) { + return true; +} + +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/deserializer.hpp actor-framework-0.16.3/libcaf_core/caf/deserializer.hpp --- actor-framework-0.13.2/libcaf_core/caf/deserializer.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/deserializer.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,112 +16,64 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DESERIALIZER_HPP -#define CAF_DESERIALIZER_HPP +#pragma once #include #include +#include +#include -#include "caf/primitive_variant.hpp" -#include "caf/uniform_type_info.hpp" +#include "caf/data_processor.hpp" +#include "caf/fwd.hpp" +#include "caf/raise_error.hpp" namespace caf { -class actor_namespace; -class uniform_type_info; +/// @ingroup TypeSystem +/// Technology-independent deserialization interface. +class deserializer : public data_processor { +public: + ~deserializer() override; -/** - * @ingroup TypeSystem - * Technology-independent deserialization interface. - */ -class deserializer { - - deserializer(const deserializer&) = delete; - deserializer& operator=(const deserializer&) = delete; - - public: - - deserializer(actor_namespace* ns = nullptr); - - virtual ~deserializer(); - - /** - * Begins deserialization of a new object. - */ - virtual const uniform_type_info* begin_object() = 0; - - /** - * Ends deserialization of an object. - */ - virtual void end_object() = 0; - - /** - * Begins deserialization of a sequence. - * @returns The size of the sequence. - */ - virtual size_t begin_sequence() = 0; - - /** - * Ends deserialization of a sequence. - */ - virtual void end_sequence() = 0; - - /** - * Reads a primitive value from the data source. - */ - virtual void read_value(primitive_variant& storage) = 0; - - /** - * Reads a value of type `T` from the data source. - * @note `T` must be a primitive type. - */ - template - inline T read() { - primitive_variant val{T()}; - read_value(val); - return std::move(get(val)); - } - - template - inline T read(const uniform_type_info* uti) { - T result; - uti->deserialize(&result, this); - return result; - } - - template - inline deserializer& read(T& storage) { - primitive_variant val{T()}; - read_value(val); - storage = std::move(get(val)); - return *this; - } - - template - inline deserializer& read(T& storage, const uniform_type_info* uti) { - uti->deserialize(&storage, this); - return *this; - } - - /** - * Reads a raw memory block. - */ - virtual void read_raw(size_t num_bytes, void* storage) = 0; - - inline actor_namespace* get_namespace() { - return m_namespace; - } - - template - void read_raw(size_t num_bytes, Buffer& storage) { - storage.resize(num_bytes); - read_raw(num_bytes, storage.data()); - } + using super = data_processor; - private: - actor_namespace* m_namespace; + static constexpr bool reads_state = false; + static constexpr bool writes_state = true; + + // Boost Serialization compatibility + using is_saving = std::false_type; + using is_loading = std::true_type; + + explicit deserializer(actor_system& x); + + explicit deserializer(execution_unit* x = nullptr); }; +template +typename std::enable_if< + std::is_same< + error, + decltype(std::declval().apply(std::declval())) + >::value +>::type +operator&(deserializer& source, T& x) { + auto e = source.apply(x); + if (e) + CAF_RAISE_ERROR("error during serialization (using operator&)"); +} + +template +typename std::enable_if< + std::is_same< + error, + decltype(std::declval().apply(std::declval())) + >::value, + deserializer& +>::type +operator>>(deserializer& source, T& x) { + source & x; + return source; +} + } // namespace caf -#endif // CAF_DESERIALIZER_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/abstract_uniform_type_info.hpp actor-framework-0.16.3/libcaf_core/caf/detail/abstract_uniform_type_info.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/abstract_uniform_type_info.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/abstract_uniform_type_info.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_DETAIL_ABSTRACT_UNIFORM_TYPE_INFO_HPP -#define CAF_DETAIL_ABSTRACT_UNIFORM_TYPE_INFO_HPP - -#include "caf/message.hpp" -#include "caf/deserializer.hpp" -#include "caf/uniform_type_info.hpp" - -#include "caf/detail/type_traits.hpp" - -#include "caf/detail/uniform_type_info_map.hpp" - -namespace caf { -namespace detail { - -/** - * Implements all pure virtual functions of `uniform_type_info` - * except serialize() and deserialize(). - */ -template -class abstract_uniform_type_info : public uniform_type_info { - public: - const char* name() const override { - return m_name.c_str(); - } - - message as_message(void* instance) const override { - return make_message(deref(instance)); - } - - bool equal_to(const std::type_info& tinfo) const override { - return m_native == &tinfo || *m_native == tinfo; - } - - bool equals(const void* lhs, const void* rhs) const override { - return eq(deref(lhs), deref(rhs)); - } - - uniform_value create(const uniform_value& other) const override { - return create_impl(other); - } - - protected: - abstract_uniform_type_info(std::string tname) - : m_name(std::move(tname)), - m_native(&typeid(T)) { - // nop - } - - static const T& deref(const void* ptr) { - return *reinterpret_cast(ptr); - } - - static T& deref(void* ptr) { - return *reinterpret_cast(ptr); - } - - // can be overridden in subclasses to compare POD types - // by comparing each individual member - virtual bool pod_mems_equals(const T&, const T&) const { - return false; - } - - std::string m_name; - const std::type_info* m_native; - - private: - template - typename std::enable_if::value, bool>::type - eq(const C&, const C&) const { - return true; - } - - template - typename std::enable_if::value && - detail::is_comparable::value, - bool>::type - eq(const C& lhs, const C& rhs) const { - return lhs == rhs; - } - - template - typename std::enable_if::value && std::is_pod::value && - !detail::is_comparable::value, - bool>::type - eq(const C& lhs, const C& rhs) const { - return pod_mems_equals(lhs, rhs); - } -}; - -} // namespace detail -} // namespace caf - -#endif // CAF_DETAIL_ABSTRACT_UNIFORM_TYPE_INFO_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/actor_registry.hpp actor-framework-0.16.3/libcaf_core/caf/detail/actor_registry.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/actor_registry.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/actor_registry.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_DETAIL_ACTOR_REGISTRY_HPP -#define CAF_DETAIL_ACTOR_REGISTRY_HPP - -#include -#include -#include -#include -#include -#include - -#include "caf/abstract_actor.hpp" -#include "caf/detail/shared_spinlock.hpp" - -#include "caf/detail/singleton_mixin.hpp" - -namespace caf { -namespace detail { - -class singletons; - -class actor_registry : public singleton_mixin { - public: - friend class singleton_mixin; - - ~actor_registry(); - - /** - * A registry entry consists of a pointer to the actor and an - * exit reason. An entry with a nullptr means the actor has finished - * execution for given reason. - */ - using value_type = std::pair; - - value_type get_entry(actor_id key) const; - - // return nullptr if the actor wasn't put *or* finished execution - inline abstract_actor_ptr get(actor_id key) const { - return get_entry(key).first; - } - - void put(actor_id key, const abstract_actor_ptr& value); - - void erase(actor_id key, uint32_t reason); - - // gets the next free actor id - actor_id next_id(); - - // increases running-actors-count by one - void inc_running(); - - // decreases running-actors-count by one - void dec_running(); - - size_t running() const; - - // blocks the caller until running-actors-count becomes `expected` - void await_running_count_equal(size_t expected); - - private: - using entries = std::map; - - actor_registry(); - - std::atomic m_running; - std::atomic m_ids; - - std::mutex m_running_mtx; - std::condition_variable m_running_cv; - - mutable detail::shared_spinlock m_instances_mtx; - entries m_entries; -}; - -} // namespace detail -} // namespace caf - -#endif // CAF_DETAIL_ACTOR_REGISTRY_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/algorithms.hpp actor-framework-0.16.3/libcaf_core/caf/detail/algorithms.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/algorithms.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/algorithms.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,133 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/detail/type_traits.hpp" + +namespace caf { +namespace detail { + +/// Like `std::for_each`, but for multiple containers and filters elements by +/// predicate. +/// @pre `x.size() <= y.size()` for each `y` in `xs` +template +void zip_foreach(F f, Container&& x, Containers&&... xs) { + for (size_t i = 0; i < x.size(); ++i) + f(x[i], xs[i]...); +} + +/// Like `std::for_each`, but for multiple containers. +/// @pre `x.size() <= y.size()` for each `y` in `xs` +template +void zip_foreach_if(F f, Predicate p, Container&& x, Containers&&... xs) { + for (size_t i = 0; i < x.size(); ++i) + if (p(x[i], xs[i]...)) + f(x[i], xs[i]...); +} + +/// Like `std::accumulate`, but for multiple containers. +/// @pre `x.size() <= y.size()` for each `y` in `xs` +template +T zip_fold(F f, T init, Container&& x, Containers&&... xs) { + for (size_t i = 0; i < x.size(); ++i) + init = f(init, x[i], xs[i]...); + return init; +} + +/// Like `std::accumulate`, but for multiple containers and filters elements by +/// predicate. +/// @pre `x.size() <= y.size()` for each `y` in `xs` +template +T zip_fold_if(F f, Predicate p, T init, Container&& x, Containers&&... xs) { + for (size_t i = 0; i < x.size(); ++i) + if (p(x[i], xs[i]...)) + init = f(init, x[i], xs[i]...); + return init; +} + +/// Decorates a container of type `T` to appear as container of type `U`. +template +struct container_view { + Container& x; + using value_type = typename detail::get_callable_trait::result_type; + inline size_t size() const { + return x.size(); + } + value_type operator[](size_t i) { + F f; + return f(x[i]); + } +}; + +/// Returns a container view for `x`. +/// @relates container_view +template +container_view make_container_view(Container& x) { + return {x}; +} + +/// Like `std::find`, but takes a range instead of an iterator pair and returns +/// a pointer to the found object on success instead of returning an iterator. +template +typename T::value_type* ptr_find(T& xs, const typename T::value_type& x) { + for (auto& y : xs) + if (y == x) + return &y; + return nullptr; +} + +/// Like `std::find`, but takes a range instead of an iterator pair and returns +/// a pointer to the found object on success instead of returning an iterator. +template +const typename T::value_type* ptr_find(const T& xs, + const typename T::value_type& x) { + for (auto& y : xs) + if (y == x) + return &y; + return nullptr; +} + +/// Like `std::find_if`, but takes a range instead of an iterator pair and +/// returns a pointer to the found object on success instead of returning an +/// iterator. +template +typename T::value_type* ptr_find_if(T& xs, Predicate pred) { + for (auto& x : xs) + if (pred(x)) + return &x; + return nullptr; +} + +/// Like `std::find_if`, but takes a range instead of an iterator pair and +/// returns a pointer to the found object on success instead of returning an +/// iterator. +template +const typename T::value_type* ptr_find_if(const T& xs, Predicate pred) { + for (auto& x : xs) + if (pred(x)) + return &x; + return nullptr; +} + +} // namespace detail +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/append_hex.hpp actor-framework-0.16.3/libcaf_core/caf/detail/append_hex.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/append_hex.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/append_hex.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,29 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +namespace caf { +namespace detail { + +void append_hex(std::string& result, const uint8_t* xs, size_t n); + +} // namespace detail +} // namespace caf diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/apply_args.hpp actor-framework-0.16.3/libcaf_core/caf/detail/apply_args.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/apply_args.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/apply_args.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_APPLY_ARGS_HPP -#define CAF_DETAIL_APPLY_ARGS_HPP +#pragma once #include @@ -35,11 +33,17 @@ typename tl_at, Pos>::type get(const type_list&); template -auto apply_args(F& f, detail::int_list, Tuple&& tup) +auto apply_args(F& f, detail::int_list, Tuple& tup) -> decltype(f(get(tup)...)) { return f(get(tup)...); } +template +auto apply_moved_args(F& f, detail::int_list, Tuple& tup) +-> decltype(f(std::move(get(tup))...)) { + return f(std::move(get(tup))...); +} + template auto apply_args_prefixed(F& f, detail::int_list<>, Tuple&, Ts&&... xs) -> decltype(f(std::forward(xs)...)) { @@ -52,6 +56,18 @@ return f(std::forward(xs)..., get(tup)...); } +template +auto apply_moved_args_prefixed(F& f, detail::int_list<>, Tuple&, Ts&&... xs) +-> decltype(f(std::forward(xs)...)) { + return f(std::forward(xs)...); +} + +template +auto apply_moved_args_prefixed(F& f, detail::int_list, Tuple& tup, Ts&&... xs) +-> decltype(f(std::forward(xs)..., std::move(get(tup))...)) { + return f(std::forward(xs)..., std::move(get(tup))...); +} + template auto apply_args_suffxied(F& f, detail::int_list, Tuple& tup, Ts&&... xs) -> decltype(f(get(tup)..., std::forward(xs)...)) { @@ -61,4 +77,3 @@ } // namespace detail } // namespace caf -#endif // CAF_DETAIL_APPLY_ARGS_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/arg_match_t.hpp actor-framework-0.16.3/libcaf_core/caf/detail/arg_match_t.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/arg_match_t.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/arg_match_t.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_ARG_MATCH_T_HPP -#define CAF_DETAIL_ARG_MATCH_T_HPP +#pragma once namespace caf { namespace detail { @@ -28,4 +26,3 @@ } // namespace detail } // namespace caf -#endif // CAF_DETAIL_ARG_MATCH_T_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/arg_wrapper.hpp actor-framework-0.16.3/libcaf_core/caf/detail/arg_wrapper.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/arg_wrapper.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/arg_wrapper.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,93 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/deep_to_string.hpp" + +namespace caf { +namespace detail { + +/// Enables automagical string conversion for `CAF_ARG`. +template +struct single_arg_wrapper { + const char* name; + const T& value; + single_arg_wrapper(const char* x, const T& y) : name(x), value(y) { + // nop + } +}; + +template +std::string to_string(const single_arg_wrapper& x) { + std::string result = x.name; + result += " = "; + result += deep_to_string(x.value); + return result; +} + +template +struct range_arg_wrapper { + const char* name; + Iterator first; + Iterator last; + range_arg_wrapper(const char* x, Iterator begin, Iterator end) + : name(x), + first(begin), + last(end) { + // nop + } +}; + +template +std::string to_string(const range_arg_wrapper& x) { + std::string result = x.name; + result += " = "; + struct dummy { + Iterator first; + Iterator last; + Iterator begin() const { + return first; + } + Iterator end() const { + return last; + } + }; + dummy y{x.first, x.last}; + result += deep_to_string(y); + return result; +} + +/// Used to implement `CAF_ARG`. +template +single_arg_wrapper make_arg_wrapper(const char* name, const T& value) { + return {name, value}; +} + +/// Used to implement `CAF_ARG`. +template +range_arg_wrapper make_arg_wrapper(const char* name, Iterator first, + Iterator last) { + return {name, first, last}; +} + +} // namespace detail +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/atom_val.hpp actor-framework-0.16.3/libcaf_core/caf/detail/atom_val.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/atom_val.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/atom_val.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_ATOM_VAL_HPP -#define CAF_DETAIL_ATOM_VAL_HPP +#pragma once namespace caf { namespace detail { @@ -39,8 +37,8 @@ // decodes 6bit characters to ASCII constexpr char decoding_table[] = " 0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ_" - "abcdefghijklmnopqrstuvwxyz"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZ_" + "abcdefghijklmnopqrstuvwxyz"; } // namespace @@ -48,7 +46,7 @@ return (current << 6) | encoding_table[(char_code <= 0x7F) ? char_code : 0]; } -constexpr uint64_t atom_val(const char* cstr, uint64_t interim = 0) { +constexpr uint64_t atom_val(const char* cstr, uint64_t interim = 0xF) { return (*cstr == '\0') ? interim : atom_val(cstr + 1, @@ -58,4 +56,3 @@ } // namespace detail } // namespace caf -#endif // CAF_DETAIL_ATOM_VAL_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/behavior_impl.hpp actor-framework-0.16.3/libcaf_core/caf/detail/behavior_impl.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/behavior_impl.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/behavior_impl.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_BEHAVIOR_IMPL_HPP -#define CAF_DETAIL_BEHAVIOR_IMPL_HPP +#pragma once #include #include @@ -31,11 +29,10 @@ #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" -#include "caf/skip_message.hpp" +#include "caf/skip.hpp" #include "caf/response_promise.hpp" #include "caf/timeout_definition.hpp" #include "caf/typed_response_promise.hpp" @@ -44,208 +41,203 @@ #include "caf/detail/apply_args.hpp" #include "caf/detail/type_traits.hpp" #include "caf/detail/tail_argument_token.hpp" -#include "caf/detail/optional_message_visitor.hpp" +#include "caf/detail/invoke_result_visitor.hpp" namespace caf { class message_handler; -using bhvr_invoke_result = optional; } // namespace caf namespace caf { namespace detail { -template -struct has_skip_message { - static constexpr bool value = - disjunction::value...>::value; -}; - class behavior_impl : public ref_counted { - public: +public: using pointer = intrusive_ptr; - ~behavior_impl(); + ~behavior_impl() override; behavior_impl(duration tout = duration{}); - virtual bhvr_invoke_result invoke(message&); + virtual match_case::result invoke_empty(detail::invoke_result_visitor& f); - inline bhvr_invoke_result invoke(message&& arg) { - message tmp(std::move(arg)); - return invoke(tmp); - } + virtual match_case::result invoke(detail::invoke_result_visitor& f, + type_erased_tuple& xs); + + match_case::result invoke(detail::invoke_result_visitor& f, message& xs); + + optional invoke(message&); + + optional invoke(type_erased_tuple&); virtual void handle_timeout(); inline const duration& timeout() const { - return m_timeout; + return timeout_; } - virtual pointer copy(const generic_timeout_definition& tdef) const = 0; - pointer or_else(const pointer& other); - protected: - duration m_timeout; - match_case_info* m_begin; - match_case_info* m_end; -}; - -template -struct defaut_bhvr_impl_init { - template - static void init(Array& arr, Tuple& tup) { - auto& x = arr[Pos]; - x.ptr = &std::get(tup); - x.has_wildcard = x.ptr->has_wildcard(); - x.type_token = x.ptr->type_token(); - defaut_bhvr_impl_init::init(arr, tup); - } +protected: + duration timeout_; + match_case_info* begin_; + match_case_info* end_; }; -template -struct defaut_bhvr_impl_init { - template - static void init(Array&, Tuple&) { - // nop - } +template +void call_timeout_handler(Tuple& tup, std::true_type) { + auto& f = std::get::value - 1>(tup); + f.handler(); +} + +template +void call_timeout_handler(Tuple&, std::false_type) { + // nop +} + +template ::value> +struct lift_behavior { + using type = trivial_match_case; }; +template +struct lift_behavior { + using type = T; +}; + +template +struct with_generic_timeout; + +template +struct with_generic_timeout> { + using type = std::tuple; +}; + +template +struct with_generic_timeout> { + using type = + typename tl_apply< + typename tl_replace_back< + type_list, + generic_timeout_definition + >::type, + std::tuple + >::type; +}; template -class default_behavior_impl : public behavior_impl { - public: - static constexpr size_t num_cases = std::tuple_size::value; +class default_behavior_impl; - default_behavior_impl(Tuple tup) : m_cases(std::move(tup)) { - init(); - } +template +class default_behavior_impl> : public behavior_impl { +public: + using tuple_type = std::tuple; + + using back_type = typename tl_back>::type; - template - default_behavior_impl(Tuple tup, timeout_definition d) - : behavior_impl(d.timeout), - m_cases(std::move(tup)), - m_fun(d.handler) { + static constexpr bool has_timeout = is_timeout_definition::value; + + static constexpr size_t num_cases = sizeof...(Ts) - (has_timeout ? 1 : 0); + + using cases = + typename std::conditional< + has_timeout, + typename tl_pop_back>::type, + type_list + >::type; + + default_behavior_impl(tuple_type&& tup) : cases_(std::move(tup)) { init(); } - typename behavior_impl::pointer - copy(const generic_timeout_definition& tdef) const override { - return make_counted>(m_cases, tdef); + template + default_behavior_impl(Us&&... xs) : cases_(std::forward(xs)...) { + init(); } void handle_timeout() override { - m_fun(); + std::integral_constant token; + call_timeout_handler(cases_, token); } - private: +private: void init() { - defaut_bhvr_impl_init<0, num_cases>::init(m_arr, m_cases); - m_begin = m_arr.data(); - m_end = m_begin + m_arr.size(); + std::integral_constant first; + std::integral_constant last; + init(first, last); } - Tuple m_cases; - std::array m_arr; - std::function m_fun; -}; - -// eor = end of recursion -// ra = reorganize arguments - -template -intrusive_ptr make_behavior_eor(std::tuple match_cases) { - return make_counted(std::move(match_cases)); -} + template + void init(std::integral_constant, + std::integral_constant) { + this->begin_ = arr_.data(); + this->end_ = arr_.data() + arr_.size(); + std::integral_constant token; + set_timeout(token); + } -template -intrusive_ptr make_behavior_eor(std::tuple match_cases, - timeout_definition& td) { - return make_counted(std::move(match_cases), std::move(td)); -} + template + void init(std::integral_constant, + std::integral_constant last) { + auto& element = std::get(cases_); + arr_[First] = match_case_info{element.type_token(), &element}; + init(std::integral_constant{}, last); + } -template ::value> -struct lift_to_mctuple { - using type = std::tuple>; -}; + void set_timeout(std::true_type) { + this->timeout_ = std::get(cases_).timeout; + } -template -struct lift_to_mctuple { - using type = std::tuple; -}; + void set_timeout(std::false_type) { + // nop + } -template -struct lift_to_mctuple, false> { - using type = std::tuple; + tuple_type cases_; + std::array arr_; }; -template -struct lift_to_mctuple, false> { - using type = std::tuple<>; +template +struct behavior_factory { + template + typename behavior_impl::pointer operator()(Ts&&... xs) const { + return make_counted>(std::forward(xs)...); + } }; -template -struct join_std_tuples; - -template -struct join_std_tuples { - using type = T; -}; +struct make_behavior_t { + constexpr make_behavior_t() { + // nop + } -template -struct join_std_tuples, std::tuple, Suffix...> - : join_std_tuples, Suffix...> { - // nop + template + intrusive_ptr< + default_behavior_impl::type...>>> + operator()(Ts... xs) const { + using type = + default_behavior_impl::type...>>; + return make_counted(std::move(xs)...); + } }; -// this function reorganizes its arguments to shift the timeout definition -// to the front (receives it at the tail) -template -intrusive_ptr make_behavior_ra(timeout_definition& td, - tail_argument_token&, Ts... xs) { - return make_behavior_eor(std::tuple_cat(to_match_case_tuple(xs)...), td); -} +constexpr make_behavior_t make_behavior = make_behavior_t{}; -template -intrusive_ptr make_behavior_ra(tail_argument_token&, Ts... xs) { - return make_behavior_eor(std::tuple_cat(to_match_case_tuple(xs)...)); -} +using behavior_impl_ptr = intrusive_ptr; -// for some reason, this call is ambigious on GCC without enable_if -template -typename std::enable_if< - !std::is_same::value, - intrusive_ptr ->::type -make_behavior_ra(V& v, Ts&... xs) { - return make_behavior_ra(xs..., v); -} +// utility for getting a type-erased version of make_behavior +struct make_behavior_impl_t { + constexpr make_behavior_impl_t() { + // nop + } -// this function reorganizes its arguments to shift the timeout definition -// to the front (receives it at the tail) -template -intrusive_ptr< - default_behavior_impl< - typename join_std_tuples< - typename lift_to_mctuple::type... - >::type - >> -make_behavior(Ts&... xs) { - using result_type = - default_behavior_impl< - typename join_std_tuples< - typename lift_to_mctuple::type... - >::type - >; - tail_argument_token eoa; - return make_behavior_ra(xs..., eoa); -} + template + behavior_impl_ptr operator()(Ts&&... xs) const { + return make_behavior(std::forward(xs)...); + } +}; -using behavior_impl_ptr = intrusive_ptr; +constexpr make_behavior_impl_t make_behavior_impl = make_behavior_impl_t{}; } // namespace detail } // namespace caf -#endif // CAF_DETAIL_BEHAVIOR_IMPL_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/behavior_stack.hpp actor-framework-0.16.3/libcaf_core/caf/detail/behavior_stack.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/behavior_stack.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/behavior_stack.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_BEHAVIOR_STACK_HPP -#define CAF_DETAIL_BEHAVIOR_STACK_HPP +#pragma once #include #include @@ -38,7 +36,7 @@ struct behavior_stack_mover; class behavior_stack { - public: +public: friend struct behavior_stack_mover; behavior_stack(const behavior_stack&) = delete; @@ -52,28 +50,32 @@ void clear(); inline bool empty() const { - return m_elements.empty(); + return elements_.empty(); } inline behavior& back() { CAF_ASSERT(!empty()); - return m_elements.back(); + return elements_.back(); } inline void push_back(behavior&& what) { - m_elements.emplace_back(std::move(what)); + elements_.emplace_back(std::move(what)); } + template + inline void emplace_back(Ts&&... xs) { + elements_.emplace_back(std::forward(xs)...); + } + inline void cleanup() { - m_erased_elements.clear(); + erased_elements_.clear(); } - private: - std::vector m_elements; - std::vector m_erased_elements; +private: + std::vector elements_; + std::vector erased_elements_; }; } // namespace detail } // namespace caf -#endif // CAF_DETAIL_BEHAVIOR_STACK_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/blocking_behavior.hpp actor-framework-0.16.3/libcaf_core/caf/detail/blocking_behavior.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/blocking_behavior.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/blocking_behavior.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,147 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include "caf/behavior.hpp" +#include "caf/catch_all.hpp" +#include "caf/timeout_definition.hpp" + +namespace caf { +namespace detail { + +class blocking_behavior { +public: + behavior& nested; + + blocking_behavior(behavior& x); + blocking_behavior(blocking_behavior&&) = default; + + virtual ~blocking_behavior(); + + virtual result fallback(message_view&); + + virtual duration timeout(); + + virtual void handle_timeout(); +}; + +template +class blocking_behavior_v2 : public blocking_behavior { +public: + catch_all f; + + blocking_behavior_v2(behavior& x, catch_all y) + : blocking_behavior(x), + f(std::move(y)) { + // nop + } + + blocking_behavior_v2(blocking_behavior_v2&&) = default; + + result fallback(message_view& x) override { + return f.handler(x); + } +}; + +template +class blocking_behavior_v3 : public blocking_behavior { +public: + timeout_definition f; + + blocking_behavior_v3(behavior& x, timeout_definition y) + : blocking_behavior(x), + f(std::move(y)) { + // nop + } + + blocking_behavior_v3(blocking_behavior_v3&&) = default; + + duration timeout() override { + return f.timeout; + } + + void handle_timeout() override { + f.handler(); + } +}; + +template +class blocking_behavior_v4 : public blocking_behavior { +public: + catch_all f1; + timeout_definition f2; + + blocking_behavior_v4(behavior& x, catch_all y, timeout_definition z) + : blocking_behavior(x), + f1(std::move(y)), + f2(std::move(z)) { + // nop + } + + blocking_behavior_v4(blocking_behavior_v4&&) = default; + + result fallback(message_view& x) override { + return f1.handler(x); + } + + duration timeout() override { + return f2.timeout; + } + + void handle_timeout() override { + f2.handler(); + } +}; + +struct make_blocking_behavior_t { + constexpr make_blocking_behavior_t() { + // nop + } + + inline blocking_behavior operator()(behavior* x) const { + CAF_ASSERT(x != nullptr); + return {*x}; + } + + template + blocking_behavior_v2 operator()(behavior* x, catch_all y) const { + CAF_ASSERT(x != nullptr); + return {*x, std::move(y)}; + } + + template + blocking_behavior_v3 operator()(behavior* x, + timeout_definition y) const { + CAF_ASSERT(x != nullptr); + return {*x, std::move(y)}; + } + + template + blocking_behavior_v4 operator()(behavior* x, catch_all y, + timeout_definition z) const { + CAF_ASSERT(x != nullptr); + return {*x, std::move(y), std::move(z)}; + } +}; + +constexpr make_blocking_behavior_t make_blocking_behavior = make_blocking_behavior_t{}; + +} // namespace detail +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/bounds_checker.hpp actor-framework-0.16.3/libcaf_core/caf/detail/bounds_checker.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/bounds_checker.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/bounds_checker.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,45 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include +#include + +namespace caf { +namespace detail { + +template = sizeof(int64_t) + && std::is_unsigned::value> +struct bounds_checker { + static inline bool check(int64_t x) { + return x >= std::numeric_limits::min() + && x <= std::numeric_limits::max(); + } +}; + +template +struct bounds_checker { + static inline bool check(int64_t x) { + return x >= 0; + } +}; + +} // namespace detail +} // namespace caf diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/boxed.hpp actor-framework-0.16.3/libcaf_core/caf/detail/boxed.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/boxed.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/boxed.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_DETAIL_BOXED_HPP -#define CAF_DETAIL_BOXED_HPP - -#include "caf/anything.hpp" -#include "caf/detail/wrapped.hpp" - -namespace caf { -namespace detail { - -template -struct boxed { - using type = detail::wrapped; - -}; - -template -struct boxed> { - using type = detail::wrapped; - -}; - -template <> -struct boxed { - using type = anything; - -}; - -template -struct is_boxed { - static constexpr bool value = false; - -}; - -template -struct is_boxed> { - static constexpr bool value = true; - -}; - -template -struct is_boxed()> { - static constexpr bool value = true; - -}; - -template -struct is_boxed(&)()> { - static constexpr bool value = true; - -}; - -template -struct is_boxed(*)()> { - static constexpr bool value = true; - -}; - -} // namespace detail -} // namespace caf - -#endif // CAF_DETAIL_BOXED_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/cas_weak.hpp actor-framework-0.16.3/libcaf_core/caf/detail/cas_weak.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/cas_weak.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/cas_weak.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_CAS_WEAK_HPP -#define CAF_DETAIL_CAS_WEAK_HPP +#pragma once #include @@ -40,4 +38,3 @@ } // namespace detail } // namespace caf -#endif // CAF_DETAIL_CAS_WEAK_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/comparable.hpp actor-framework-0.16.3/libcaf_core/caf/detail/comparable.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/comparable.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/comparable.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,103 +16,95 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_COMPARABLE_HPP -#define CAF_COMPARABLE_HPP +#pragma once namespace caf { 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` if `*this < other` - * - `x > 0` if `*this > other` - * - `x == 0` if `*this == other` - */ +/// 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` if `*this < other` +/// - `x > 0` if `*this > other` +/// - `x == 0` if `*this == other` template class comparable { - - friend bool operator==(const Subclass& lhs, const T& rhs) { + friend bool operator==(const Subclass& lhs, const T& rhs) noexcept { return lhs.compare(rhs) == 0; } - friend bool operator==(const T& lhs, const Subclass& rhs) { + friend bool operator==(const T& lhs, const Subclass& rhs) noexcept { return rhs.compare(lhs) == 0; } - friend bool operator!=(const Subclass& lhs, const T& rhs) { + friend bool operator!=(const Subclass& lhs, const T& rhs) noexcept { return lhs.compare(rhs) != 0; } - friend bool operator!=(const T& lhs, const Subclass& rhs) { + friend bool operator!=(const T& lhs, const Subclass& rhs) noexcept { return rhs.compare(lhs) != 0; } - friend bool operator<(const Subclass& lhs, const T& rhs) { + friend bool operator<(const Subclass& lhs, const T& rhs) noexcept { return lhs.compare(rhs) < 0; } - friend bool operator>(const Subclass& lhs, const T& rhs) { + friend bool operator>(const Subclass& lhs, const T& rhs) noexcept { return lhs.compare(rhs) > 0; } - friend bool operator<(const T& lhs, const Subclass& rhs) { + friend bool operator<(const T& lhs, const Subclass& rhs) noexcept { return rhs > lhs; } - friend bool operator>(const T& lhs, const Subclass& rhs) { + friend bool operator>(const T& lhs, const Subclass& rhs) noexcept { return rhs < lhs; } - friend bool operator<=(const Subclass& lhs, const T& rhs) { + friend bool operator<=(const Subclass& lhs, const T& rhs) noexcept { return lhs.compare(rhs) <= 0; } - friend bool operator>=(const Subclass& lhs, const T& rhs) { + friend bool operator>=(const Subclass& lhs, const T& rhs) noexcept { return lhs.compare(rhs) >= 0; } - friend bool operator<=(const T& lhs, const Subclass& rhs) { + friend bool operator<=(const T& lhs, const Subclass& rhs) noexcept { return rhs >= lhs; } - friend bool operator>=(const T& lhs, const Subclass& rhs) { + friend bool operator>=(const T& lhs, const Subclass& rhs) noexcept { return rhs <= lhs; } - }; template class comparable { - - friend bool operator==(const Subclass& lhs, const Subclass& rhs) { + friend bool operator==(const Subclass& lhs, const Subclass& rhs) noexcept { return lhs.compare(rhs) == 0; } - friend bool operator!=(const Subclass& lhs, const Subclass& rhs) { + friend bool operator!=(const Subclass& lhs, const Subclass& rhs) noexcept { return lhs.compare(rhs) != 0; } - friend bool operator<(const Subclass& lhs, const Subclass& rhs) { + friend bool operator<(const Subclass& lhs, const Subclass& rhs) noexcept { return lhs.compare(rhs) < 0; } - friend bool operator<=(const Subclass& lhs, const Subclass& rhs) { + friend bool operator<=(const Subclass& lhs, const Subclass& rhs) noexcept { return lhs.compare(rhs) <= 0; } - friend bool operator>(const Subclass& lhs, const Subclass& rhs) { + friend bool operator>(const Subclass& lhs, const Subclass& rhs) noexcept { return lhs.compare(rhs) > 0; } - friend bool operator>=(const Subclass& lhs, const Subclass& rhs) { + friend bool operator>=(const Subclass& lhs, const Subclass& rhs) noexcept { return lhs.compare(rhs) >= 0; } - }; } // namespace details } // namespace caf -#endif // CAF_COMPARABLE_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/concatenated_tuple.hpp actor-framework-0.16.3/libcaf_core/caf/detail/concatenated_tuple.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/concatenated_tuple.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/concatenated_tuple.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_CONCATENATED_TUPLE_HPP -#define CAF_DETAIL_CONCATENATED_TUPLE_HPP +#pragma once #include #include @@ -29,47 +27,64 @@ namespace detail { class concatenated_tuple : public message_data { - public: - concatenated_tuple& operator=(const concatenated_tuple&) = delete; +public: + // -- member types ----------------------------------------------------------- using message_data::cow_ptr; + using vector_type = std::vector; + // -- constructors, destructors, and assignment operators -------------------- + + concatenated_tuple(std::initializer_list xs); + static cow_ptr make(std::initializer_list xs); - void* mutable_at(size_t pos) override; + concatenated_tuple(const concatenated_tuple&) = default; - size_t size() const override; + concatenated_tuple& operator=(const concatenated_tuple&) = delete; - cow_ptr copy() const override; + // -- overridden observers of message_data ----------------------------------- - const void* at(size_t pos) const override; + concatenated_tuple* copy() const override; - bool match_element(size_t pos, uint16_t typenr, - const std::type_info* rtti) const override; + // -- overridden modifiers of type_erased_tuple ------------------------------ - uint32_t type_token() const override; + void* get_mutable(size_t pos) override; - const char* uniform_name_at(size_t pos) const override; + error load(size_t pos, deserializer& source) override; - uint16_t type_nr_at(size_t pos) const override; + // -- overridden observers of type_erased_tuple ------------------------------ - concatenated_tuple() = default; + size_t size() const noexcept override; - private: - concatenated_tuple(const concatenated_tuple&) = default; + uint32_t type_token() const noexcept override; + + rtti_pair type(size_t pos) const noexcept override; + + const void* get(size_t pos) const noexcept override; + + std::string stringify(size_t pos) const override; + + type_erased_value_ptr copy(size_t pos) const override; + + error save(size_t pos, serializer& sink) const override; + + // -- element access --------------------------------------------------------- + + std::pair select(size_t pos); - std::pair select(size_t pos) const; + std::pair select(size_t pos) const; - void init(); +private: + // -- data members ----------------------------------------------------------- - vector_type m_data; - uint32_t m_type_token; - size_t m_size; + vector_type data_; + uint32_t type_token_; + size_t size_; }; } // namespace detail } // namespace caf -#endif // CAF_DETAIL_CONCATENATED_TUPLE_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/ctm.hpp actor-framework-0.16.3/libcaf_core/caf/detail/ctm.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/ctm.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/ctm.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,135 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_DETAIL_CTM_HPP -#define CAF_DETAIL_CTM_HPP - -#include "caf/replies_to.hpp" -#include "caf/typed_response_promise.hpp" - -#include "caf/detail/type_list.hpp" -#include "caf/detail/typed_actor_util.hpp" - -namespace caf { -namespace detail { - -// CTM: Compile-Time Match - -// left hand side is the MPI we are comparing to, this is *not* commutative -template -struct ctm_cmp : std::false_type { }; - -template -struct ctm_cmp, - typed_mpi> { - static constexpr bool value = std::is_same::value - || std::is_same::value; -}; - - -/* -template -struct ctm_cmp, - typed_mpi> - : std::true_type { }; - -template -struct ctm_cmp, - typed_mpi> - : std::true_type { }; -*/ - -template -struct ctm_cmp, - typed_mpi>, empty_type_list>> - : std::true_type { }; - -template -struct ctm_cmp, - typed_mpi>, empty_type_list>> - : std::true_type { }; - -template -struct ctm_cmp, - typed_mpi, empty_type_list>> - : std::true_type { }; - -template -struct ctm_cmp, - typed_mpi>>, empty_type_list>> - : std::true_type { }; - -/* -template -struct ctm_cmp, - typed_mpi> - : std::true_type { }; -*/ - -template -struct ctm_cmp, - typed_mpi> - : std::true_type { }; - -template -struct ctm_impl { // : std::integral_constant { - // -2 means: to few message handlers defined - static constexpr int value = (tl_size::value < tl_size::value) - ? -2 - : -3; -}; - -template -struct ctm_impl - : std::integral_constant { - // everything's fine, -1 means: no mismatch found (both sets are empty) -}; - -template -struct ctm_impl, type_list, Pos> { - using next_ys = - typename tl_filter_not< - type_list, - tbind::template type - >::type; - static constexpr int value = - // check if filter_not did remove something - sizeof...(Ys) == tl_size::value - ? Pos // error at this position - : ctm_impl, next_ys, Pos + 1>::value; -}; - -template -struct ctm { - // -3 means too many handler, -2 means too few, -1 means OK, everything else - // mismatch at that position - static constexpr size_t num_xs = tl_size::value; - static constexpr size_t num_ys = tl_size::value; - /* - static constexpr int value = num_xs != num_ys - ? num_xs > num_ys ? -3 : -2 - : ctm_impl::value; - */ - static constexpr int value = ctm_impl::value; -}; - -} // namespace detail -} // namespace caf - -#endif // CAF_DETAIL_CTM_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/decorated_tuple.hpp actor-framework-0.16.3/libcaf_core/caf/detail/decorated_tuple.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/decorated_tuple.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/decorated_tuple.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,15 +16,13 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_DECORATED_TUPLE_HPP -#define CAF_DETAIL_DECORATED_TUPLE_HPP +#pragma once #include #include #include "caf/config.hpp" #include "caf/ref_counted.hpp" -#include "caf/uniform_type_info.hpp" #include "caf/detail/type_list.hpp" @@ -36,52 +33,69 @@ namespace detail { class decorated_tuple : public message_data { - public: - decorated_tuple& operator=(const decorated_tuple&) = delete; +public: + // -- member types ----------------------------------------------------------- + + using message_data::cow_ptr; using vector_type = std::vector; - using message_data::cow_ptr; + // -- constructors, destructors, and assignment operators -------------------- decorated_tuple(cow_ptr&&, vector_type&&); - // creates a typed subtuple from `d` with mapping `v` static cow_ptr make(cow_ptr d, vector_type v); - void* mutable_at(size_t pos) override; + decorated_tuple& operator=(const decorated_tuple&) = delete; + + // -- overridden observers of message_data ----------------------------------- + + message_data* copy() const override; - size_t size() const override; + // -- overridden modifiers of type_erased_tuple ------------------------------ - cow_ptr copy() const override; + void* get_mutable(size_t pos) override; - const void* at(size_t pos) const override; + error load(size_t pos, deserializer& source) override; - bool match_element(size_t pos, uint16_t typenr, - const std::type_info* rtti) const override; + // -- overridden observers of type_erased_tuple ------------------------------ - uint32_t type_token() const override; + size_t size() const noexcept override; - const char* uniform_name_at(size_t pos) const override; + uint32_t type_token() const noexcept override; - uint16_t type_nr_at(size_t pos) const override; + rtti_pair type(size_t pos) const noexcept override; + + const void* get(size_t pos) const noexcept override; + + std::string stringify(size_t pos) const override; + + type_erased_value_ptr copy(size_t pos) const override; + + error save(size_t pos, serializer& sink) const override; + + // -- inline observers ------------------------------------------------------- inline const cow_ptr& decorated() const { - return m_decorated; + return decorated_; } inline const vector_type& mapping() const { - return m_mapping; + return mapping_; } - private: +private: + // -- constructors, destructors, and assignment operators -------------------- + decorated_tuple(const decorated_tuple&) = default; - cow_ptr m_decorated; - vector_type m_mapping; - uint32_t m_type_token; + // -- data members ----------------------------------------------------------- + + cow_ptr decorated_; + vector_type mapping_; + uint32_t type_token_; }; } // namespace detail } // namespace caf -#endif // CAF_DETAIL_DECORATED_TUPLE_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/default_invoke_result_visitor.hpp actor-framework-0.16.3/libcaf_core/caf/detail/default_invoke_result_visitor.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/default_invoke_result_visitor.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/default_invoke_result_visitor.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,92 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include "caf/local_actor.hpp" + +#include "caf/detail/invoke_result_visitor.hpp" + +namespace caf { +namespace detail { + +template +class default_invoke_result_visitor : public invoke_result_visitor { +public: + inline default_invoke_result_visitor(Self* ptr) : self_(ptr) { + // nop + } + + ~default_invoke_result_visitor() override { + // nop + } + + void operator()() override { + // nop + } + + void operator()(error& x) override { + CAF_LOG_TRACE(CAF_ARG(x)); + delegate(x); + } + + void operator()(message& x) override { + CAF_LOG_TRACE(CAF_ARG(x)); + delegate(x); + } + + void operator()(const none_t& x) override { + CAF_LOG_TRACE(CAF_ARG(x)); + delegate(x); + } + +private: + void deliver(response_promise& rp, error& x) { + CAF_LOG_DEBUG("report error back to requesting actor"); + rp.deliver(std::move(x)); + } + + void deliver(response_promise& rp, message& x) { + CAF_LOG_DEBUG("respond via response_promise"); + // suppress empty messages for asynchronous messages + if (x.empty() && rp.async()) + return; + rp.deliver(std::move(x)); + } + + void deliver(response_promise& rp, const none_t&) { + error err = sec::unexpected_response; + deliver(rp, err); + } + + template + void delegate(T& x) { + auto rp = self_->make_response_promise(); + if (!rp.pending()) { + CAF_LOG_DEBUG("suppress response message: invalid response promise"); + return; + } + deliver(rp, x); + } + + Self* self_; +}; + +} // namespace detail +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/default_uniform_type_info.hpp actor-framework-0.16.3/libcaf_core/caf/detail/default_uniform_type_info.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/default_uniform_type_info.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/default_uniform_type_info.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,607 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_DETAIL_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP -#define CAF_DETAIL_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP - -#include - -#include "caf/unit.hpp" -#include "caf/actor.hpp" -#include "caf/anything.hpp" -#include "caf/serializer.hpp" -#include "caf/typed_actor.hpp" -#include "caf/deserializer.hpp" - -#include "caf/detail/type_traits.hpp" -#include "caf/detail/abstract_uniform_type_info.hpp" - - -namespace caf { -namespace detail { - -using uniform_type_info_ptr = uniform_type_info_ptr; - -// check if there's a 'push_back' that takes a C::value_type -template -char sfinae_has_push_back(T* ptr, typename T::value_type* val = nullptr, - decltype(ptr->push_back(*val)) * = nullptr); - -long sfinae_has_push_back(void*); // SFNINAE default - -template -struct is_stl_compliant_list { - static constexpr bool value = - detail::is_iterable::value - && sizeof(sfinae_has_push_back(static_cast(nullptr))) == sizeof(char); -}; - -// check if there's an 'insert' that takes a C::value_type -template -char sfinae_has_insert(T* ptr, typename T::value_type* val = nullptr, - decltype(ptr->insert(*val)) * = nullptr); - -long sfinae_has_insert(void*); // SFNINAE default - -template -struct is_stl_compliant_map { - static constexpr bool value = - detail::is_iterable::value - && sizeof(sfinae_has_insert(static_cast(nullptr))) == sizeof(char); -}; - -template -struct is_stl_pair : std::false_type { - // no members -}; - -template -struct is_stl_pair> : std::true_type { - // no members -}; - -using primitive_impl = std::integral_constant; -using list_impl = std::integral_constant; -using map_impl = std::integral_constant; -using pair_impl = std::integral_constant; -using opt_impl = std::integral_constant; -using recursive_impl = std::integral_constant; - -template -constexpr int impl_id() { - return detail::is_primitive::value - ? 0 - : (is_stl_compliant_list::value - ? 1 - : (is_stl_compliant_map::value - ? 2 - : (is_stl_pair::value - ? 3 - : (detail::is_optional::value - ? 4 - : 9)))); -} - -template -struct deconst_pair { - using type = T; -}; - -template -struct deconst_pair> { - using first_type = typename std::remove_const::type; - using second_type = typename std::remove_const::type; - using type = std::pair; -}; - -class default_serialize_policy { - public: - template - void operator()(const T& val, serializer* s) const { - std::integral_constant()> token; - simpl(val, s, token); - } - - template - void operator()(T& val, deserializer* d) const { - std::integral_constant()> token; - dimpl(val, d, token); - } - - private: - template - void simpl(const T& val, serializer* s, primitive_impl) const { - s->write_value(val); - } - - template - void simpl(const T& val, serializer* s, list_impl) const { - s->begin_sequence(val.size()); - for (auto i = val.begin(); i != val.end(); ++i) { - (*this)(*i, s); - } - s->end_sequence(); - } - - template - void simpl(const T& val, serializer* s, map_impl) const { - // lists and maps share code for serialization - list_impl token; - simpl(val, s, token); - } - - template - void simpl(const T& val, serializer* s, pair_impl) const { - (*this)(val.first, s); - (*this)(val.second, s); - } - - template - void simpl(const optional& val, serializer* s, opt_impl) const { - uint8_t flag = val ? 1 : 0; - s->write_value(flag); - if (val) { - (*this)(*val, s); - } - } - - template - void simpl(const T& val, serializer* s, recursive_impl) const { - uniform_typeid()->serialize(&val, s); - } - - template - void dimpl(T& storage, deserializer* d, primitive_impl) const { - storage = d->read(); - } - - template - void dimpl(T& storage, deserializer* d, list_impl) const { - using value_type = typename T::value_type; - storage.clear(); - size_t size = d->begin_sequence(); - for (size_t i = 0; i < size; ++i) { - value_type tmp; - (*this)(tmp, d); - storage.push_back(std::move(tmp)); - } - d->end_sequence(); - } - - template - void dimpl(T& storage, deserializer* d, map_impl) const { - storage.clear(); - size_t size = d->begin_sequence(); - for (size_t i = 0; i < size; ++i) { - typename deconst_pair::type tmp; - (*this)(tmp, d); - storage.insert(tmp); - } - d->end_sequence(); - } - - template - void dimpl(T& storage, deserializer* d, pair_impl) const { - (*this)(storage.first, d); - (*this)(storage.second, d); - } - - template - void dimpl(optional& val, deserializer* d, opt_impl) const { - auto flag = d->read(); - if (flag != 0) { - T tmp; - (*this)(tmp, d); - val = std::move(tmp); - } else { - val = none; - } - } - - template - void dimpl(T& storage, deserializer* d, recursive_impl) const { - uniform_typeid()->deserialize(&storage, d); - } -}; - -class forwarding_serialize_policy { - public: - inline forwarding_serialize_policy(uniform_type_info_ptr uti) - : m_uti(std::move(uti)) { - // nop - } - - template - void operator()(const T& val, serializer* s) const { - m_uti->serialize(&val, s); - } - - template - void operator()(T& val, deserializer* d) const { - m_uti->deserialize(&val, d); - } - - private: - uniform_type_info_ptr m_uti; -}; - -template ::value, - bool IsEmptyType = std::is_class::value&& std::is_empty::value> -class member_tinfo : public detail::abstract_uniform_type_info { - public: - using super = detail::abstract_uniform_type_info; - member_tinfo(AccessPolicy apol, SerializePolicy spol) - : super("--member--"), - m_apol(std::move(apol)), m_spol(std::move(spol)) { - // nop - } - - member_tinfo(AccessPolicy apol) - : super("--member--"), - m_apol(std::move(apol)) { - // nop - } - - member_tinfo() : super("--member--") { - // nop - } - - void serialize(const void* vptr, serializer* s) const override { - m_spol(m_apol(vptr), s); - } - - void deserialize(void* vptr, deserializer* d) const override { - std::integral_constant token; - ds(vptr, d, token); - } - - private: - - void ds(void* p, deserializer* d, std::true_type) const { - m_spol(m_apol(p), d); - } - - void ds(void* p, deserializer* d, std::false_type) const { - T tmp; - m_spol(tmp, d); - m_apol(p, std::move(tmp)); - } - - AccessPolicy m_apol; - SerializePolicy m_spol; - -}; - -template -class member_tinfo - : public detail::abstract_uniform_type_info { - public: - using super = detail::abstract_uniform_type_info; - - member_tinfo(const A&, const S&) : super("--member--") { - // nop - } - - member_tinfo(const A&) : super("--member--") { - // nop - } - - member_tinfo() : super("--member--") { - // nop - } - - void serialize(const void*, serializer*) const override { - // nop - } - - void deserialize(void*, deserializer*) const override { - // nop - } -}; - -template -class member_tinfo - : public detail::abstract_uniform_type_info { - public: - using super = detail::abstract_uniform_type_info; - using value_type = typename std::underlying_type::type; - - member_tinfo(AccessPolicy apol, SerializePolicy spol) - : super("--member--"), - m_apol(std::move(apol)), m_spol(std::move(spol)) { - // nop - } - - member_tinfo(AccessPolicy apol) - : super("--member--"), - m_apol(std::move(apol)) { - // nop - } - - member_tinfo() : super("--member--") { - // nop - } - - void serialize(const void* p, serializer* s) const override { - auto val = m_apol(p); - m_spol(static_cast(val), s); - } - - void deserialize(void* p, deserializer* d) const override { - value_type tmp; - m_spol(tmp, d); - m_apol(p, static_cast(tmp)); - } - - private: - AccessPolicy m_apol; - SerializePolicy m_spol; -}; - -template -class memptr_access_policy { - public: - inline memptr_access_policy(T C::*memptr) : m_memptr(memptr) { - // nop - } - memptr_access_policy(const memptr_access_policy&) = default; - memptr_access_policy& operator=(const memptr_access_policy&) = default; - - inline T& operator()(void* vptr) const { - auto ptr = reinterpret_cast(vptr); - return *ptr.*m_memptr; - } - - inline const T& operator()(const void* vptr) const { - auto ptr = reinterpret_cast(vptr); - return *ptr.*m_memptr; - } - - template - inline void operator()(void* vptr, Arg&& value) const { - auto ptr = reinterpret_cast(vptr); - (*ptr.*m_memptr) = std::forward(value); - } - - static constexpr bool grants_mutable_access = true; - - private: - T C::*m_memptr; -}; - -template -class getter_setter_access_policy { - public: - - using getter = GRes (C::*)() const; - using setter = SRes (C::*)(SArg); - - getter_setter_access_policy(getter g, setter s) : m_get(g), m_set(s) {} - - inline GRes operator()(const void* vptr) const { - auto ptr = reinterpret_cast(vptr); - return (*ptr.*m_get)(); - } - - template - inline void operator()(void* vptr, Arg&& value) const { - auto ptr = reinterpret_cast(vptr); - (*ptr.*m_set)(std::forward(value)); - } - - static constexpr bool grants_mutable_access = false; - - private: - getter m_get; - setter m_set; -}; - -template -struct fake_access_policy { - inline T& operator()(void* vptr) const { - return *reinterpret_cast(vptr); - } - - inline const T& operator()(const void* vptr) const { - return *reinterpret_cast(vptr); - } - - template - inline void operator()(void* vptr, U&& value) const { - *reinterpret_cast(vptr) = std::forward(value); - } - - static constexpr bool grants_mutable_access = true; -}; - -template -uniform_type_info_ptr new_member_tinfo(T C::*memptr) { - using access_policy = memptr_access_policy; - using result_type = member_tinfo; - return uniform_type_info_ptr(new result_type(memptr)); -} - -template -uniform_type_info_ptr new_member_tinfo(T C::*memptr, - uniform_type_info_ptr meminf) { - using access_policy = memptr_access_policy; - using tinfo = member_tinfo; - return uniform_type_info_ptr(new tinfo(memptr, std::move(meminf))); -} - -template -uniform_type_info_ptr new_member_tinfo(GRes (C::*getter)() const, - SRes (C::*setter)(SArg)) { - using access_policy = getter_setter_access_policy; - using value_type = typename std::decay::type; - using result_type = member_tinfo; - return uniform_type_info_ptr( - new result_type(access_policy(getter, setter))); -} - -template -uniform_type_info_ptr new_member_tinfo(GRes (C::*getter)() const, - SRes (C::*setter)(SArg), - uniform_type_info_ptr meminf) { - using access_policy = getter_setter_access_policy; - using value_type = typename std::decay::type; - using tinfo = member_tinfo; - return uniform_type_info_ptr(new tinfo(access_policy(getter, setter), - std::move(meminf))); -} - -template -class default_uniform_type_info : public detail::abstract_uniform_type_info { - public: - using super = detail::abstract_uniform_type_info; - - template - default_uniform_type_info(std::string tname, Ts&&... xs) - : super(std::move(tname)) { - push_back(std::forward(xs)...); - } - - default_uniform_type_info(std::string tname) : super(std::move(tname)) { - using result_type = member_tinfo>; - m_members.push_back(uniform_type_info_ptr(new result_type)); - } - - void serialize(const void* obj, serializer* s) const override { - // serialize each member - for (auto& m : m_members) { - m->serialize(obj, s); - } - } - - void deserialize(void* obj, deserializer* d) const override { - // deserialize each member - for (auto& m : m_members) { - m->deserialize(obj, d); - } - } - - protected: - bool pod_mems_equals(const T& lhs, const T& rhs) const override { - return pod_eq(lhs, rhs); - } - - private: - template - typename std::enable_if::value, bool>::type - pod_eq(const C& lhs, const C& rhs) const { - for (auto& member : m_members) { - if (!member->equals(&lhs, &rhs)) return false; - } - return true; - } - - template - typename std::enable_if::value, bool>::type - pod_eq(const C&, const C&) const { - return false; - } - - inline void push_back() { - // terminate recursion - } - - template - void push_back(R C::*memptr, Ts&&... xs) { - m_members.push_back(new_member_tinfo(memptr)); - push_back(std::forward(xs)...); - } - - // pr.first = member pointer - // pr.second = meta object to handle pr.first - template - void push_back(const std::pair*>& pr, - Ts&&... xs) { - m_members.push_back(new_member_tinfo(pr.first, - uniform_type_info_ptr(pr.second))); - push_back(std::forward(xs)...); - } - - // pr.first = const-qualified getter - // pr.second = setter with one argument - template - void push_back(const std::pair& pr, - Ts&&... xs) { - m_members.push_back(new_member_tinfo(pr.first, pr.second)); - push_back(std::forward(xs)...); - } - - // pr.first = pair of const-qualified getter and setter with one argument - // pr.second = uniform type info pointer - template - void push_back(const std::pair< - std::pair, - detail::abstract_uniform_type_info< - typename std::decay::type>* - >& pr, - Ts&&... xs) { - m_members.push_back(new_member_tinfo(pr.first.first, pr.first.second, - uniform_type_info_ptr(pr.second))); - push_back(std::forward(xs)...); - } - - std::vector m_members; -}; - -template -class default_uniform_type_info> : - public detail::abstract_uniform_type_info> { - public: - using super = detail::abstract_uniform_type_info>; - using handle_type = typed_actor; - - default_uniform_type_info(std::string tname) : super(std::move(tname)) { - sub_uti = uniform_typeid(); - } - - void serialize(const void* obj, serializer* s) const override { - auto tmp = actor_cast(deref(obj).address()); - sub_uti->serialize(&tmp, s); - } - - void deserialize(void* obj, deserializer* d) const override { - actor tmp; - sub_uti->deserialize(&tmp, d); - deref(obj) = actor_cast(tmp); - } - - private: - static handle_type& deref(void* ptr) { - return *reinterpret_cast(ptr); - } - static const handle_type& deref(const void* ptr) { - return *reinterpret_cast(ptr); - } - const uniform_type_info* sub_uti; -}; - -} // namespace detail -} // namespace caf - -#endif // CAF_DETAIL_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/delegate_serialize.hpp actor-framework-0.16.3/libcaf_core/caf/detail/delegate_serialize.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/delegate_serialize.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/delegate_serialize.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,70 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +// The rationale of this header is to provide a serialization API +// that is compatbile to boost.serialization. In particular, the +// design goals are: +// - allow users to integrate existing boost.serialization-based code easily +// - allow to switch out this header with the actual boost header in boost.actor +// +// Differences in semantics are: +// - CAF does *not* respect class versions +// - the `unsigned int` argument is always 0 and ignored by CAF +// +// Since CAF requires all runtime instances to have the same types +// announced, different class versions in a single actor system would +// cause inconsistencies that are not recoverable. + +#pragma once + +#include +#include + +#include "caf/detail/type_traits.hpp" + +namespace boost { +namespace serialization { + +} // namespace serialization +} // namespace boost + +namespace caf { +namespace detail { + +// Calls `serialize(...)` with `using namespace boost::serialization` +// to enable both ADL and picking up existing boost code. + +template +auto delegate_serialize(Processor& proc, U& x, const unsigned int y = 0) + -> decltype(serialize(proc, x, y)) { + using namespace boost::serialization; + serialize(proc, x, y); +} + +// Calls `serialize(...)` without the unused version argument, which CAF +// ignores anyway. + +template +auto delegate_serialize(Processor& proc, U& x) + -> decltype(serialize(proc, x)) { + serialize(proc, x); +} + +} // namespace detail +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/disablable_delete.hpp actor-framework-0.16.3/libcaf_core/caf/detail/disablable_delete.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/disablable_delete.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/disablable_delete.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_DETAIL_DISABLABLE_DELETE_HPP -#define CAF_DETAIL_DISABLABLE_DELETE_HPP - -namespace caf { -namespace detail { - -class disablable_delete { - - public: - - constexpr disablable_delete() : m_enabled(true) {} - - inline void disable() { m_enabled = false; } - - inline void enable() { m_enabled = true; } - - template - inline void operator()(T* ptr) { - if (m_enabled) delete ptr; - } - - private: - - bool m_enabled; - -}; - -} // namespace detail -} // namespace caf - -#endif // CAF_DETAIL_DISABLABLE_DELETE_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/disposer.hpp actor-framework-0.16.3/libcaf_core/caf/detail/disposer.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/disposer.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/disposer.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,9 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_DISPOSER_HPP -#define CAF_DETAIL_DISPOSER_HPP +#pragma once + +#include #include "caf/memory_managed.hpp" @@ -26,14 +26,19 @@ namespace detail { class disposer { - public: - inline void operator()(memory_managed* ptr) const { +public: + inline void operator()(memory_managed* ptr) const noexcept { ptr->request_deletion(false); } + + template + typename std::enable_if::value>::type + operator()(T* ptr) const noexcept { + delete ptr; + } }; } // namespace detail } // namespace caf -#endif // CAF_DETAIL_DISPOSER_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/double_ended_queue.hpp actor-framework-0.16.3/libcaf_core/caf/detail/double_ended_queue.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/double_ended_queue.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/double_ended_queue.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,13 +16,10 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_DOUBLE_ENDED_QUEUE_HPP -#define CAF_DETAIL_DOUBLE_ENDED_QUEUE_HPP +#pragma once #include "caf/config.hpp" -#define CAF_CACHE_LINE_SIZE 64 - #include #include #include @@ -77,7 +73,7 @@ */ template class double_ended_queue { - public: +public: using value_type = T; using size_type = size_t; using difference_type = ptrdiff_t; @@ -87,13 +83,13 @@ using const_pointer = const value_type*; class node { - public: + public: pointer value; std::atomic next; - node(pointer val) : value(val), next(nullptr) { + explicit node(pointer val) : value(val), next(nullptr) { // nop } - private: + private: static constexpr size_type payload_size = sizeof(pointer) + sizeof(std::atomic); static constexpr size_type cline_size = CAF_CACHE_LINE_SIZE; @@ -110,15 +106,15 @@ "sizeof(node*) >= CAF_CACHE_LINE_SIZE"); double_ended_queue() { - m_head_lock.clear(); - m_tail_lock.clear(); + head_lock_.clear(); + tail_lock_.clear(); auto ptr = new node(nullptr); - m_head = ptr; - m_tail = ptr; + head_ = ptr; + tail_ = ptr; } ~double_ended_queue() { - auto ptr = m_head.load(); + auto ptr = head_.load(); while (ptr) { unique_node_ptr tmp{ptr}; ptr = tmp->next.load(); @@ -128,33 +124,33 @@ // acquires only one lock void append(pointer value) { CAF_ASSERT(value != nullptr); - node* tmp = new node(value); - lock_guard guard(m_tail_lock); + auto* tmp = new node(value); + lock_guard guard(tail_lock_); // publish & swing last forward - m_tail.load()->next = tmp; - m_tail = tmp; + tail_.load()->next = tmp; + tail_ = tmp; } // acquires both locks void prepend(pointer value) { CAF_ASSERT(value != nullptr); - node* tmp = new node(value); + auto* tmp = new node(value); node* first = nullptr; - // acquire both locks since we might touch m_last too - lock_guard guard1(m_head_lock); - lock_guard guard2(m_tail_lock); - first = m_head.load(); + // acquire both locks since we might touch last_ too + lock_guard guard1(head_lock_); + lock_guard guard2(tail_lock_); + first = head_.load(); CAF_ASSERT(first != nullptr); auto next = first->next.load(); - // m_first always points to a dummy with no value, + // first_ always points to a dummy with no value, // hence we put the new element second - if (next == nullptr) { - // queue is empty - CAF_ASSERT(first == m_tail); - m_tail = tmp; - } else { - CAF_ASSERT(first != m_tail); + if (next) { + CAF_ASSERT(first != tail_); tmp->next = next; + } else { + // queue is empty + CAF_ASSERT(first == tail_); + tail_ = tmp; } first->next = tmp; } @@ -164,8 +160,8 @@ unique_node_ptr first; pointer result = nullptr; { // lifetime scope of guard - lock_guard guard(m_head_lock); - first.reset(m_head.load()); + lock_guard guard(head_lock_); + first.reset(head_.load()); node* next = first->next; if (next == nullptr) { // queue is empty @@ -175,7 +171,7 @@ // take it out of the node & swing first forward result = next->value; next->value = nullptr; - m_head = next; + head_ = next; } return result; } @@ -185,18 +181,18 @@ pointer result = nullptr; unique_node_ptr last; { // lifetime scope of guards - lock_guard guard1(m_head_lock); - lock_guard guard2(m_tail_lock); - CAF_ASSERT(m_head != nullptr); - last.reset(m_tail.load()); - if (last.get() == m_head.load()) { + lock_guard guard1(head_lock_); + lock_guard guard2(tail_lock_); + CAF_ASSERT(head_ != nullptr); + last.reset(tail_.load()); + if (last.get() == head_.load()) { last.release(); return nullptr; } result = last->value; - m_tail = find_predecessor(last.get()); - CAF_ASSERT(m_tail != nullptr); - m_tail.load()->next = nullptr; + tail_ = find_predecessor(last.get()); + CAF_ASSERT(tail_ != nullptr); + tail_.load()->next = nullptr; } return result; } @@ -204,13 +200,13 @@ // does not lock bool empty() const { // atomically compares first and last pointer without locks - return m_head == m_tail; + return head_.load() == tail_.load(); } - private: +private: // precondition: *both* locks acquired node* find_predecessor(node* what) { - for (auto i = m_head.load(); i != nullptr; i = i->next) { + for (auto i = head_.load(); i != nullptr; i = i->next) { if (i->next == what) { return i; } @@ -218,32 +214,31 @@ return nullptr; } - // guarded by m_head_lock - std::atomic m_head; - char m_pad1[CAF_CACHE_LINE_SIZE - sizeof(node*)]; - // guarded by m_tail_lock - std::atomic m_tail; - char m_pad2[CAF_CACHE_LINE_SIZE - sizeof(node*)]; + // guarded by head_lock_ + std::atomic head_; + char pad1_[CAF_CACHE_LINE_SIZE - sizeof(node*)]; + // guarded by tail_lock_ + std::atomic tail_; + char pad2_[CAF_CACHE_LINE_SIZE - sizeof(node*)]; // enforce exclusive access - std::atomic_flag m_head_lock; - std::atomic_flag m_tail_lock; + std::atomic_flag head_lock_; + std::atomic_flag tail_lock_; class lock_guard { - public: - lock_guard(std::atomic_flag& lock) : m_lock(lock) { + public: + explicit lock_guard(std::atomic_flag& lock) : lock_(lock) { while (lock.test_and_set(std::memory_order_acquire)) { std::this_thread::yield(); } } ~lock_guard() { - m_lock.clear(std::memory_order_release); + lock_.clear(std::memory_order_release); } - private: - std::atomic_flag& m_lock; + private: + std::atomic_flag& lock_; }; }; } // namespace detail } // namespace caf -#endif // CAF_DETAIL_DOUBLE_ENDED_QUEUE_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/dynamic_message_data.hpp actor-framework-0.16.3/libcaf_core/caf/detail/dynamic_message_data.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/dynamic_message_data.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/dynamic_message_data.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,95 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/type_erased_value.hpp" + +#include "caf/detail/message_data.hpp" + +namespace caf { +namespace detail { + +class dynamic_message_data : public message_data { +public: + // -- member types ----------------------------------------------------------- + + using elements = std::vector; + + // -- constructors, destructors, and assignment operators -------------------- + + dynamic_message_data(); + + dynamic_message_data(elements&& data); + + dynamic_message_data(const dynamic_message_data& other); + + ~dynamic_message_data() override; + + // -- overridden observers of message_data ----------------------------------- + + dynamic_message_data* copy() const override; + + // -- overridden modifiers of type_erased_tuple ------------------------------ + + void* get_mutable(size_t pos) override; + + error load(size_t pos, deserializer& source) override; + + // -- overridden observers of type_erased_tuple ------------------------------ + + size_t size() const noexcept override; + + uint32_t type_token() const noexcept override; + + rtti_pair type(size_t pos) const noexcept override; + + const void* get(size_t pos) const noexcept override; + + std::string stringify(size_t pos) const override; + + type_erased_value_ptr copy(size_t pos) const override; + + error save(size_t pos, serializer& sink) const override; + + // -- modifiers -------------------------------------------------------------- + + void clear(); + + void append(type_erased_value_ptr x); + + void add_to_type_token(uint16_t typenr); + +private: + // -- data members ----------------------------------------------------------- + + elements elements_; + uint32_t type_token_; +}; + +void intrusive_ptr_add_ref(const dynamic_message_data*); + +void intrusive_ptr_release(const dynamic_message_data*); + +dynamic_message_data* intrusive_cow_ptr_unshare(dynamic_message_data*&); + +} // namespace detail +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/embedded.hpp actor-framework-0.16.3/libcaf_core/caf/detail/embedded.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/embedded.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/embedded.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_EMBEDDED_HPP -#define CAF_DETAIL_EMBEDDED_HPP +#pragma once #include "caf/ref_counted.hpp" #include "caf/intrusive_ptr.hpp" @@ -28,11 +26,11 @@ template class embedded final : public Base { - public: +public: template embedded(intrusive_ptr storage, Ts&&... xs) : Base(std::forward(xs)...), - m_storage(std::move(storage)) { + storage_(std::move(storage)) { // nop } @@ -42,18 +40,17 @@ void request_deletion(bool) noexcept override { intrusive_ptr guard; - guard.swap(m_storage); + guard.swap(storage_); // this code assumes that embedded is part of pair_storage<>, // i.e., this object lives inside a union! this->~embedded(); } - protected: - intrusive_ptr m_storage; +protected: + intrusive_ptr storage_; }; } // namespace detail } // namespace caf -#endif // CAF_DETAIL_EMBEDDED_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/enqueue_result.hpp actor-framework-0.16.3/libcaf_core/caf/detail/enqueue_result.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/enqueue_result.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/enqueue_result.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,32 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright (C) 2011 - 2017 * + * Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include "caf/intrusive/inbox_result.hpp" + +namespace caf { +namespace detail { + +/// Alias for backwards compatibility. +using enqueue_result = intrusive::inbox_result; + +} // namespace intrusive +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/enum_to_string.hpp actor-framework-0.16.3/libcaf_core/caf/detail/enum_to_string.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/enum_to_string.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/enum_to_string.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,36 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +namespace caf { +namespace detail { + +/// Converts x to its underlying type and fetches the name from the +/// lookup table. Assumes consecutive enum values. +template +const char* enum_to_string(E x, const char* (&lookup_table)[N]) { + auto index = static_cast::type>(x); + return index < N ? lookup_table[index] : ""; +} + +} // namespace detail +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/functor_attachable.hpp actor-framework-0.16.3/libcaf_core/caf/detail/functor_attachable.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/functor_attachable.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/functor_attachable.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_FUNCTOR_ATTACHABLE_HPP -#define CAF_FUNCTOR_ATTACHABLE_HPP +#pragma once #include "caf/attachable.hpp" @@ -31,29 +29,41 @@ template ::arg_types>::value> struct functor_attachable : attachable { - static_assert(Args == 2, "Only 1 and 2 arguments for F are supported"); - F m_functor; - functor_attachable(F arg) : m_functor(std::move(arg)) { + static_assert(Args == 1 || Args == 2, + "Only 0, 1 or 2 arguments for F are supported"); + F functor_; + functor_attachable(F arg) : functor_(std::move(arg)) { // nop } - void actor_exited(abstract_actor* self, uint32_t reason) override { - m_functor(self, reason); + void actor_exited(const error& fail_state, execution_unit*) override { + functor_(fail_state); } static constexpr size_t token_type = attachable::token::anonymous; }; template -struct functor_attachable : attachable { - F m_functor; - functor_attachable(F arg) : m_functor(std::move(arg)) { +struct functor_attachable : attachable { + F functor_; + functor_attachable(F arg) : functor_(std::move(arg)) { // nop } - void actor_exited(abstract_actor*, uint32_t reason) override { - m_functor(reason); + void actor_exited(const error& x, execution_unit* y) override { + functor_(x, y); + } +}; + + +template +struct functor_attachable : attachable { + F functor_; + functor_attachable(F arg) : functor_(std::move(arg)) { + // nop + } + void actor_exited(const error&, execution_unit*) override { + functor_(); } }; } // namespace detail } // namespace caf -#endif // CAF_FUNCTOR_ATTACHABLE_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/gcd.hpp actor-framework-0.16.3/libcaf_core/caf/detail/gcd.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/gcd.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/gcd.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,39 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright (C) 2011 - 2017 * + * Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +namespace caf { +namespace detail { + +template +T gcd(T a, T b) { + T r; + while (b != 0) { + r = a % b; + a = b; + b = r; + } + return a; +} + +} // namespace detail +} // namespace caf + + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/get_mac_addresses.hpp actor-framework-0.16.3/libcaf_core/caf/detail/get_mac_addresses.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/get_mac_addresses.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/get_mac_addresses.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_GET_MAC_ADDRESSES_HPP -#define CAF_DETAIL_GET_MAC_ADDRESSES_HPP +#pragma once #include #include @@ -35,4 +33,3 @@ } // namespace detail } // namespace caf -#endif // CAF_DETAIL_GET_MAC_ADDRESSES_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/get_process_id.hpp actor-framework-0.16.3/libcaf_core/caf/detail/get_process_id.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/get_process_id.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/get_process_id.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,32 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include +#include + +namespace caf { +namespace detail { + +unsigned get_process_id(); + +} // namespace detail +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/get_root_uuid.hpp actor-framework-0.16.3/libcaf_core/caf/detail/get_root_uuid.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/get_root_uuid.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/get_root_uuid.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,8 +16,7 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_GET_ROOT_UUID_HPP -#define CAF_DETAIL_GET_ROOT_UUID_HPP +#pragma once #include @@ -30,4 +28,3 @@ } // namespace detail } // namespace caf -#endif // CAF_DETAIL_GET_ROOT_UUID_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/group_manager.hpp actor-framework-0.16.3/libcaf_core/caf/detail/group_manager.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/group_manager.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/group_manager.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_DETAIL_GROUP_MANAGER_HPP -#define CAF_DETAIL_GROUP_MANAGER_HPP - -#include -#include -#include - -#include "caf/abstract_group.hpp" -#include "caf/detail/shared_spinlock.hpp" - -#include "caf/detail/singleton_mixin.hpp" - -namespace caf { -namespace detail { - -class group_manager { - public: - - inline void dispose() { - delete this; - } - - static inline group_manager* create_singleton() { - return new group_manager; - } - - void stop(); - - inline void initialize() { - // nop - } - - ~group_manager(); - - group get(const std::string& module_name, - const std::string& group_identifier); - - group anonymous(); - - void add_module(abstract_group::unique_module_ptr); - - abstract_group::module_ptr get_module(const std::string& module_name); - - private: - using modules_map = std::map; - - group_manager(); - - modules_map m_mmap; - std::mutex m_mmap_mtx; -}; - -} // namespace detail -} // namespace caf - -#endif // CAF_DETAIL_GROUP_MANAGER_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/ieee_754.hpp actor-framework-0.16.3/libcaf_core/caf/detail/ieee_754.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/ieee_754.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/ieee_754.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -21,8 +20,7 @@ * Based on http://beej.us/guide/bgnet/examples/pack2.c * \ ******************************************************************************/ -#ifndef CAF_DETAIL_IEEE_754_HPP -#define CAF_DETAIL_IEEE_754_HPP +#pragma once #include #include @@ -65,7 +63,7 @@ template typename ieee_754_trait::packed_type pack754(T f) { - typedef ieee_754_trait trait; // using trait = ... fails on GCC 4.7 + using trait = ieee_754_trait; using result_type = typename trait::packed_type; // filter special type if (std::fabs(f) <= trait::zero) { @@ -106,7 +104,7 @@ template typename ieee_754_trait::float_type unpack754(T i) { - typedef ieee_754_trait trait; // using trait = ... fails on GCC 4.7 + using trait = ieee_754_trait; using signed_type = typename trait::signed_packed_type; using result_type = typename trait::float_type; if (i == 0) return trait::zero; @@ -130,11 +128,10 @@ ++shift; } // sign it - result *= (i >> (trait::bits - 1)) & 1 ? -1 : 1; + result *= ((i >> (trait::bits - 1)) & 1) ? -1 : 1; return result; } } // namespace detail } // namespace caf -#endif // CAF_DETAIL_IEEE_754_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/implicit_conversions.hpp actor-framework-0.16.3/libcaf_core/caf/detail/implicit_conversions.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/implicit_conversions.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/implicit_conversions.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,58 +16,133 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_IMPLICIT_CONVERSIONS_HPP -#define CAF_DETAIL_IMPLICIT_CONVERSIONS_HPP +#pragma once #include #include #include "caf/fwd.hpp" +#include "caf/actor_marker.hpp" + +#include "caf/detail/type_list.hpp" #include "caf/detail/type_traits.hpp" namespace caf { namespace detail { +template ::value, + bool IsStat = std::is_base_of::value> +struct implicit_actor_conversions { + using type = T; +}; + template -struct implicit_conversions { - // convert C strings to std::string if possible - using step1 = - typename replace_type< - T, std::string, - std::is_same, std::is_same, - std::is_same, is_array_of, - is_array_of - >::type; - // convert C strings to std::u16string if possible - using step2 = - typename replace_type< - step1, std::u16string, - std::is_same, std::is_same, - is_array_of - >::type; - // convert C strings to std::u32string if possible - using step3 = - typename replace_type< - step2, std::u32string, - std::is_same, std::is_same, - is_array_of +struct implicit_actor_conversions { + using type = actor; +}; + +template +struct implicit_actor_conversions { + using type = + typename detail::tl_apply< + typename T::signatures, + typed_actor >::type; +}; + +template <> +struct implicit_actor_conversions { + using type = strong_actor_ptr; +}; + +template +struct implicit_conversions { using type = - typename replace_type< - step3, actor, - std::is_convertible, std::is_same + typename std::conditional< + std::is_convertible::value, + error, + T >::type; }; template +struct implicit_conversions : implicit_actor_conversions {}; + +template <> +struct implicit_conversions { + using type = std::string; +}; + +template +struct implicit_conversions + : implicit_conversions {}; + +template <> +struct implicit_conversions + : implicit_conversions {}; + +template +struct implicit_conversions + : implicit_conversions {}; + +template <> +struct implicit_conversions { + using type = std::u16string; +}; + +template +struct implicit_conversions + : implicit_conversions {}; + +template <> +struct implicit_conversions + : implicit_conversions {}; + +template +struct implicit_conversions + : implicit_conversions {}; + +template <> +struct implicit_conversions { + using type = std::u16string; +}; + +template +struct implicit_conversions + : implicit_conversions {}; + +template <> +struct implicit_conversions + : implicit_conversions {}; + +template +struct implicit_conversions + : implicit_conversions {}; + +template <> +struct implicit_conversions { + using type = actor; +}; + +template +using implicit_conversions_t = typename implicit_conversions::type; + +template struct strip_and_convert { using type = typename implicit_conversions< - typename std::decay::type + typename std::remove_const< + typename std::remove_reference< + T + >::type + >::type >::type; }; +template +using strip_and_convert_t = typename strip_and_convert::type; + } // namespace detail } // namespace caf -#endif // CAF_DETAIL_IMPLICIT_CONVERSIONS_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/ini_consumer.hpp actor-framework-0.16.3/libcaf_core/caf/detail/ini_consumer.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/ini_consumer.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/ini_consumer.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,216 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/config_option_set.hpp" +#include "caf/config_value.hpp" +#include "caf/dictionary.hpp" + +namespace caf { +namespace detail { + +class ini_consumer; +class ini_list_consumer; +class ini_map_consumer; + +class abstract_ini_consumer { +public: + // -- constructors, destructors, and assignment operators -------------------- + + explicit abstract_ini_consumer(abstract_ini_consumer* parent = nullptr); + + abstract_ini_consumer(const abstract_ini_consumer&) = delete; + + abstract_ini_consumer& operator=(const abstract_ini_consumer&) = delete; + + virtual ~abstract_ini_consumer(); + + // -- properties ------------------------------------------------------------- + + virtual void value_impl(config_value&& x) = 0; + + template + void value(T&& x) { + value_impl(config_value{std::forward(x)}); + } + + inline abstract_ini_consumer* parent() { + return parent_; + } + + ini_map_consumer begin_map(); + + ini_list_consumer begin_list(); + +protected: + // -- member variables ------------------------------------------------------- + + abstract_ini_consumer* parent_; +}; + +class ini_map_consumer : public abstract_ini_consumer { +public: + // -- member types ----------------------------------------------------------- + + using super = abstract_ini_consumer; + + using map_type = config_value::dictionary; + + using iterator = map_type::iterator; + + // -- constructors, destructors, and assignment operators -------------------- + + ini_map_consumer(abstract_ini_consumer* ptr); + + ini_map_consumer(ini_map_consumer&& other); + + ~ini_map_consumer() override; + + // -- properties ------------------------------------------------------------- + + void end_map(); + + void key(std::string name); + + void value_impl(config_value&& x) override; + +private: + // -- member variables ------------------------------------------------------- + + map_type xs_; + iterator i_; +}; + +class ini_list_consumer : public abstract_ini_consumer { +public: + // -- member types ----------------------------------------------------------- + + using super = abstract_ini_consumer; + + // -- constructors, destructors, and assignment operators -------------------- + + ini_list_consumer(abstract_ini_consumer* ptr); + + ini_list_consumer(ini_list_consumer&& other); + + // -- properties ------------------------------------------------------------- + + void end_list(); + + void value_impl(config_value&& x) override; + +private: + // -- member variables ------------------------------------------------------- + + config_value::list xs_; +}; + +/// Consumes a single value from an INI parser. +class ini_value_consumer : public abstract_ini_consumer { +public: + // -- member types ----------------------------------------------------------- + + using super = abstract_ini_consumer; + + // -- constructors, destructors, and assignment operators -------------------- + + explicit ini_value_consumer(abstract_ini_consumer* parent = nullptr); + + // -- properties ------------------------------------------------------------- + + void value_impl(config_value&& x) override; + + // -- member variables ------------------------------------------------------- + + config_value result; +}; + +/// Consumes a config category. +class ini_category_consumer : public abstract_ini_consumer { +public: + // -- member types ----------------------------------------------------------- + + using super = abstract_ini_consumer; + + // -- constructors, destructors, and assignment operators -------------------- + + ini_category_consumer(ini_consumer* parent, std::string category); + + ini_category_consumer(ini_category_consumer&&); + + // -- properties ------------------------------------------------------------- + + void end_map(); + + void key(std::string name); + + void value_impl(config_value&& x) override; + +private: + // -- properties ------------------------------------------------------------- + + ini_consumer* dparent(); + + // -- member variables ------------------------------------------------------- + + std::string category_; + config_value::dictionary xs_; + std::string current_key; +}; + +/// Consumes a series of dictionaries forming a application configuration. +class ini_consumer : public abstract_ini_consumer { +public: + // -- friends ---------------------------------------------------------------- + + friend class ini_category_consumer; + + // -- member types ----------------------------------------------------------- + + using super = abstract_ini_consumer; + + using config_map = dictionary; + + // -- constructors, destructors, and assignment operators -------------------- + + ini_consumer(config_option_set& options, config_map& cfg); + + ini_consumer(ini_consumer&&) = default; + + // -- properties ------------------------------------------------------------- + + ini_category_consumer begin_map(); + + void key(std::string name); + + void value_impl(config_value&& x) override; + +private: + // -- member variables ------------------------------------------------------- + + config_option_set& options_; + config_map& cfg_; + std::string current_key; + std::vector warnings_; +}; + +} // namespace detail +} // namespace caf diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/init_fun_factory.hpp actor-framework-0.16.3/libcaf_core/caf/detail/init_fun_factory.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/init_fun_factory.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/init_fun_factory.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,110 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include + +#include "caf/fwd.hpp" + +#include "caf/detail/apply_args.hpp" +#include "caf/detail/spawn_fwd.hpp" +#include "caf/detail/type_traits.hpp" + +namespace caf { +namespace detail { + +template +class init_fun_factory_helper { +public: + init_fun_factory_helper(init_fun_factory_helper&&) = default; + init_fun_factory_helper(const init_fun_factory_helper&) = default; + + init_fun_factory_helper(F fun, ArgsPtr args) + : fun_(std::move(fun)), + args_(std::move(args)) { + // nop + } + + behavior operator()(local_actor* self) { + bool_token returns_behavior_token; + bool_token captures_self_token; + return apply(returns_behavior_token, captures_self_token, self); + } + +private: + // behavior (pointer) + behavior apply(std::true_type, std::true_type, local_actor* ptr) { + auto res = apply_moved_args_prefixed(fun_, get_indices(*args_), *args_, + static_cast(ptr)); + return std::move(res.unbox()); + } + + // void (pointer) + behavior apply(std::false_type, std::true_type, local_actor* ptr) { + apply_moved_args_prefixed(fun_, get_indices(*args_), + *args_, static_cast(ptr)); + return behavior{}; + } + + // behavior () + behavior apply(std::true_type, std::false_type, local_actor*) { + auto res = apply_args(fun_, get_indices(*args_), *args_); + return std::move(res.unbox()); + } + + // void () + behavior apply(std::false_type, std::false_type, local_actor*) { + apply_args(fun_, get_indices(*args_), *args_); + return behavior{}; + } + + F fun_; + ArgsPtr args_; +}; + +template +class init_fun_factory { +public: + using fun = std::function; + + template + fun operator()(F f, Ts&&... xs) { + static_assert(std::is_base_of::value, + "Given Base does not extend local_actor"); + using trait = typename detail::get_callable_trait::type; + using arg_types = typename trait::arg_types; + using res_type = typename trait::result_type; + using first_arg = typename detail::tl_head::type; + constexpr bool selfptr = std::is_pointer::value; + constexpr bool rets = std::is_convertible::value; + using tuple_type = decltype(std::make_tuple(detail::spawn_fwd(xs)...)); + using tuple_ptr = std::shared_ptr; + using helper = init_fun_factory_helper; + return helper{std::move(f), + sizeof...(Ts) > 0 + ? std::make_shared(detail::spawn_fwd(xs)...) + : nullptr}; + } +}; + +} // namespace detail +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/int_list.hpp actor-framework-0.16.3/libcaf_core/caf/detail/int_list.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/int_list.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/int_list.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,17 +16,14 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_INT_LIST_HPP -#define CAF_DETAIL_INT_LIST_HPP +#pragma once #include "caf/detail/type_list.hpp" namespace caf { namespace detail { -/** - * A list of integers (wraps a long... template parameter pack). - */ +/// A list of integers (wraps a long... template parameter pack). template struct int_list {}; @@ -78,9 +74,7 @@ }; -/** - * Creates indices for `List` beginning at `Pos`. - */ +/// Creates indices for `List` beginning at `Pos`. template > struct il_indices; @@ -115,7 +109,14 @@ return {}; } +template +struct il_range : il_range {}; + +template +struct il_range { + using type = int_list; +}; + } // namespace detail } // namespace caf -#endif // CAF_DETAIL_INT_LIST_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/intrusive_partitioned_list.hpp actor-framework-0.16.3/libcaf_core/caf/detail/intrusive_partitioned_list.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/intrusive_partitioned_list.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/intrusive_partitioned_list.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,271 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_DETAIL_INTRUSIVE_PARTITIONED_LIST_HPP -#define CAF_DETAIL_INTRUSIVE_PARTITIONED_LIST_HPP - -#include -#include - -#include "caf/invoke_message_result.hpp" - -namespace caf { -namespace detail { - -template > -class intrusive_partitioned_list { - public: - using value_type = T; - using pointer = value_type*; - using deleter_type = Delete; - - struct iterator : std::iterator { - pointer ptr; - - iterator(pointer init = nullptr) : ptr(init) { - // nop - } - - iterator(const iterator&) = default; - iterator& operator=(const iterator&) = default; - - iterator& operator++() { - ptr = ptr->next; - return *this; - } - - iterator operator++(int) { - iterator res = *this; - ptr = ptr->next; - return res; - } - - iterator& operator--() { - ptr = ptr->prev; - return *this; - } - - iterator operator--(int) { - iterator res = *this; - ptr = ptr->prev; - return res; - } - - value_type& operator*() { - return *ptr; - } - - pointer operator->() { - return ptr; - } - - bool operator==(const iterator& other) const { - return ptr == other.ptr; - } - - bool operator!=(const iterator& other) const { - return ptr != other.ptr; - } - }; - - intrusive_partitioned_list() { - m_head.next = &m_separator; - m_separator.prev = &m_head; - m_separator.next = &m_tail; - m_tail.prev = &m_separator; - } - - ~intrusive_partitioned_list() { - clear(); - } - - void clear() { - while (!first_empty()) { - erase(first_begin()); - } - while (!second_empty()) { - erase(second_begin()); - } - } - - template - void clear(F f) { - while (!first_empty()) { - f(first_front()); - erase(first_begin()); - } - while (!second_empty()) { - f(second_front()); - erase(second_begin()); - } - } - - iterator first_begin() { - return m_head.next; - } - - iterator first_end() { - return &m_separator; - } - - iterator second_begin() { - return m_separator.next; - } - - iterator second_end() { - return &m_tail; - } - - iterator insert(iterator next, pointer val) { - auto prev = next->prev; - val->prev = prev; - val->next = next.ptr; - prev->next = val; - next->prev = val; - return val; - } - - bool first_empty() { - return first_begin() == first_end(); - } - - bool second_empty() { - return second_begin() == second_end(); - } - - bool empty() { - return first_empty() && second_empty(); - } - - pointer take(iterator pos) { - auto res = pos.ptr; - auto next = res->next; - auto prev = res->prev; - prev->next = next; - next->prev = prev; - return res; - } - - iterator erase(iterator pos) { - auto next = pos->next; - m_delete(take(pos)); - return next; - } - - pointer take_first_front() { - return take(first_begin()); - } - - pointer take_second_front() { - return take(second_begin()); - } - - value_type& first_front() { - return *first_begin(); - } - - value_type& second_front() { - return *second_begin(); - } - - void pop_first_front() { - erase(first_begin()); - } - - void pop_second_front() { - erase(second_begin()); - } - - void push_first_back(pointer val) { - insert(first_end(), val); - } - - void push_second_back(pointer val) { - insert(second_end(), val); - } - - template - bool invoke(Actor* self, iterator first, iterator last, - behavior& bhvr, message_id mid) { - pointer prev = first->prev; - pointer next = first->next; - auto move_on = [&](bool first_valid) { - if (first_valid) { - prev = first.ptr; - } - first = next; - next = first->next; - }; - while (first != last) { - std::unique_ptr tmp{first.ptr}; - // since this function can be called recursively during - // self->invoke_message(tmp, xs...), we have to remove the - // element from the list proactively and put it back in if - // it's safe, i.e., if invoke_message returned im_skipped - prev->next = next; - next->prev = prev; - switch (self->invoke_message(tmp, bhvr, mid)) { - case im_dropped: - move_on(false); - break; - case im_success: - return true; - case im_skipped: - if (tmp) { - // re-integrate tmp and move on - prev->next = tmp.get(); - next->prev = tmp.release(); - move_on(true); - } - else { - // only happens if the user does something - // really, really stupid; check it nonetheless - move_on(false); - } - break; - } - } - return false; - } - - size_t count(iterator first, iterator last, size_t max_count) { - size_t result = 0; - while (first != last && result < max_count) { - ++first; - ++result; - } - return result; - } - - size_t count(size_t max_count = std::numeric_limits::max()) { - auto r1 = count(first_begin(), first_end(), max_count); - return r1 + count(second_begin(), second_end(), max_count - r1); - } - - private: - value_type m_head; - value_type m_separator; - value_type m_tail; - deleter_type m_delete; -}; - -} // namespace detail -} // namespace caf - -#endif // CAF_DETAIL_INTRUSIVE_PARTITIONED_LIST_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/invoke_result_visitor.hpp actor-framework-0.16.3/libcaf_core/caf/detail/invoke_result_visitor.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/invoke_result_visitor.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/invoke_result_visitor.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,228 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/expected.hpp" +#include "caf/fwd.hpp" +#include "caf/make_message.hpp" +#include "caf/make_sink_result.hpp" +#include "caf/make_source_result.hpp" +#include "caf/make_stage_result.hpp" +#include "caf/message.hpp" +#include "caf/none.hpp" +#include "caf/optional.hpp" +#include "caf/result.hpp" +#include "caf/skip.hpp" +#include "caf/unit.hpp" + +#include "caf/detail/apply_args.hpp" +#include "caf/detail/int_list.hpp" +#include "caf/detail/type_traits.hpp" + +namespace caf { +namespace detail { + +/// Inspects the result of message handlers and triggers type-depended actions +/// such as generating result messages. +class invoke_result_visitor { +public: + virtual ~invoke_result_visitor(); + + constexpr invoke_result_visitor() { + // nop + } + + // -- virtual handlers ------------------------------------------------------- + + /// Called whenever no result messages gets produced, e.g., when returning a + /// `response_promise`. + virtual void operator()() = 0; + + /// Called if the message handler returned an error. + virtual void operator()(error&) = 0; + + /// Called if the message handler returned any "ordinary" value. + virtual void operator()(message&) = 0; + + /// Called if the message handler returns "nothing", for example a + /// default-constructed `optional`. + virtual void operator()(const none_t&) = 0; + + // -- on-the-fly type conversions -------------------------------------------- + + /// Called if the message handler returns `void` or `unit_t`. + inline void operator()(const unit_t&) { + message empty_msg; + (*this)(empty_msg); + } + + /// Unwraps an `optional` by recursively calling the visitor with either + /// `none_t` or `T`. + template + void operator()(optional& x) { + if (x) + (*this)(*x); + else + (*this)(none); + } + + /// Unwraps an `expected` by recursively calling the visitor with either + /// `error` or `T`. + template + void operator()(expected& x) { + if (x) + (*this)(*x); + else + (*this)(x.error()); + } + + /// Wraps arbitrary values into a `message` and calls the visitor recursively. + template + void operator()(Ts&... xs) { + static_assert(detail::conjunction::value...>::value, + "returning a stream from a message handler achieves not " + "what you would expect and is most likely a mistake"); + auto tmp = make_message(std::move(xs)...); + (*this)(tmp); + } + + /// Wraps the tuple into a `message` and calls the visitor recursively with + /// its contents. + template + void operator()(std::tuple& xs) { + apply_args(*this, get_indices(xs), xs); + } + + /// Disambiguates the variadic `operator()`. + inline void operator()(none_t& x) { + (*this)(const_cast(x)); + } + + /// Disambiguates the variadic `operator()`. + inline void operator()(unit_t& x) { + (*this)(const_cast(x)); + } + + // -- special-purpose handlers that don't procude results -------------------- + + /// Calls `(*this)()`. + inline void operator()(response_promise&) { + (*this)(); + } + + /// Calls `(*this)()`. + template + void operator()(typed_response_promise&) { + (*this)(); + } + + /// Calls `(*this)()`. + template + void operator()(delegated&) { + (*this)(); + } + + /// Calls `(*this)()`. + template + void operator()(output_stream&) { + (*this)(); + } + + /// Calls `(*this)()`. + template + void operator()(outbound_stream_slot&) { + (*this)(); + } + + /// Calls `(*this)()`. + template + void operator()(inbound_stream_slot&) { + (*this)(); + } + + /// Calls `(*this)()`. + template + void operator()(make_sink_result&) { + (*this)(); + } + + /// Calls `(*this)()`. + template + void operator()(make_source_result&) { + (*this)(); + } + + /// Calls `(*this)()`. + template + void operator()(make_stage_result&) { + (*this)(); + } + + // -- visit API: return true if T was visited, false if T was skipped -------- + + /// Delegates `x` to the appropriate handler and returns `true`. + template + bool visit(T& x) { + (*this)(x); + return true; + } + + /// Returns `false`. + inline bool visit(skip_t&) { + return false; + } + + /// Returns `false`. + inline bool visit(const skip_t&) { + return false; + } + + /// Returns `false` if `x != none`, otherwise calls the void handler and + /// returns `true`.. + inline bool visit(optional& x) { + if (x) + return false; + (*this)(); + return true; + } + + /// Dispatches on the runtime-type of `x`. + template + bool visit(result& x) { + switch (x.flag) { + case rt_value: + (*this)(x.value); + return true; + case rt_error: + (*this)(x.err); + return true; + case rt_delegated: + (*this)(); + return true; + default: + return false; + } + } +}; + +} // namespace detail +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/is_one_of.hpp actor-framework-0.16.3/libcaf_core/caf/detail/is_one_of.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/is_one_of.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/is_one_of.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,41 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +namespace caf { +namespace detail { + +/// Checks wheter `T` is in the template parameter pack `Ts`. +template +struct is_one_of; + +template +struct is_one_of : std::false_type {}; + +template +struct is_one_of : std::true_type {}; + +template +struct is_one_of : is_one_of {}; + +} // namespace detail +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/is_primitive_config_value.hpp actor-framework-0.16.3/libcaf_core/caf/detail/is_primitive_config_value.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/is_primitive_config_value.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/is_primitive_config_value.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,51 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include + +#include "caf/detail/is_one_of.hpp" +#include "caf/timespan.hpp" + +// -- forward declarations (this header cannot include fwd.hpp) ---------------- + +namespace caf { + +class config_value; +enum class atom_value : uint64_t; + +} // namespace caf + +// -- trait -------------------------------------------------------------------- + +namespace caf { +namespace detail { + +/// Checks wheter `T` is in a primitive value type in `config_value`. +template +using is_primitive_config_value = + is_one_of, std::map>; + +} // namespace detail +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/left_or_right.hpp actor-framework-0.16.3/libcaf_core/caf/detail/left_or_right.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/left_or_right.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/left_or_right.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_LEFT_OR_RIGHT_HPP -#define CAF_LEFT_OR_RIGHT_HPP - -#include "caf/unit.hpp" - -namespace caf { -namespace detail { - -/** - * Evaluates to `Right` if `Left` == unit_t, `Left` otherwise. - */ -template -struct left_or_right { - using type = Left; -}; - -template -struct left_or_right { - using type = Right; -}; - -template -struct left_or_right { - using type = Right; -}; - -template -struct left_or_right { - using type = Right; -}; - -/** - * Evaluates to `Right` if `Left` != unit_t, `unit_t` otherwise. - */ -template -struct if_not_left { - using type = unit_t; -}; - -template -struct if_not_left { - using type = Right; -}; - -} // namespace detail -} // namespace caf - -#endif // CAF_LEFT_OR_RIGHT_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/limited_vector.hpp actor-framework-0.16.3/libcaf_core/caf/detail/limited_vector.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/limited_vector.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/limited_vector.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,29 +16,25 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_LIMITED_VECTOR_HPP -#define CAF_DETAIL_LIMITED_VECTOR_HPP +#pragma once #include #include #include -#include #include #include #include "caf/config.hpp" +#include "caf/raise_error.hpp" namespace caf { namespace detail { -/* - * A vector with a fixed maximum size (uses an array internally). - * @warning This implementation is highly optimized for arithmetic types and - * does not call constructors or destructors. - */ +// A vector with a fixed maximum size (uses an array internally). +// @warning This implementation is highly optimized for arithmetic types and template class limited_vector { - public: +public: using value_type = T; using size_type = size_t; using difference_type = ptrdiff_t; @@ -52,16 +47,16 @@ using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - limited_vector() : m_size(0) { + limited_vector() : size_(0) { // nop } - limited_vector(size_t initial_size) : m_size(initial_size) { + explicit limited_vector(size_t initial_size) : size_(initial_size) { T tmp; std::fill_n(begin(), initial_size, tmp); } - limited_vector(const limited_vector& other) : m_size(other.m_size) { + limited_vector(const limited_vector& other) : size_(other.size_) { std::copy(other.begin(), other.end(), begin()); } @@ -73,10 +68,10 @@ void resize(size_type s) { CAF_ASSERT(s <= MaxSize); - m_size = s; + size_ = s; } - limited_vector(std::initializer_list init) : m_size(init.size()) { + explicit limited_vector(std::initializer_list init) : size_(init.size()) { CAF_ASSERT(init.size() <= MaxSize); std::copy(init.begin(), init.end(), begin()); } @@ -89,7 +84,7 @@ template void assign(InputIterator first, InputIterator last, // dummy SFINAE argument - typename std::iterator_traits::pointer = 0) { + typename std::iterator_traits::pointer = nullptr) { auto dist = std::distance(first, last); CAF_ASSERT(dist >= 0); resize(static_cast(dist)); @@ -97,7 +92,7 @@ } size_type size() const { - return m_size; + return size_; } size_type max_size() const { @@ -109,35 +104,35 @@ } void clear() { - m_size = 0; + size_ = 0; } bool empty() const { - return m_size == 0; + return size_ == 0; } bool full() const { - return m_size == MaxSize; + return size_ == MaxSize; } void push_back(const_reference what) { CAF_ASSERT(!full()); - m_data[m_size++] = what; + data_[size_++] = what; } void pop_back() { CAF_ASSERT(!empty()); - --m_size; + --size_; } reference at(size_type pos) { - CAF_ASSERT(pos < m_size); - return m_data[pos]; + CAF_ASSERT(pos < size_); + return data_[pos]; } const_reference at(size_type pos) const { - CAF_ASSERT(pos < m_size); - return m_data[pos]; + CAF_ASSERT(pos < size_); + return data_[pos]; } reference operator[](size_type pos) { @@ -149,11 +144,11 @@ } iterator begin() { - return m_data; + return data_; } const_iterator begin() const { - return m_data; + return data_; } const_iterator cbegin() const { @@ -161,11 +156,11 @@ } iterator end() { - return begin() + m_size; + return begin() + size_; } const_iterator end() const { - return begin() + m_size; + return begin() + size_; } const_iterator cend() const { @@ -198,30 +193,30 @@ reference front() { CAF_ASSERT(!empty()); - return m_data[0]; + return data_[0]; } const_reference front() const { CAF_ASSERT(!empty()); - return m_data[0]; + return data_[0]; } reference back() { CAF_ASSERT(!empty()); - return m_data[m_size - 1]; + return data_[size_ - 1]; } const_reference back() const { CAF_ASSERT(!empty()); - return m_data[m_size - 1]; + return data_[size_ - 1]; } T* data() { - return m_data; + return data_; } const T* data() const { - return m_data; + return data_; } template @@ -229,7 +224,7 @@ CAF_ASSERT(first <= last); auto num_elements = static_cast(std::distance(first, last)); if ((size() + num_elements) > MaxSize) { - throw std::length_error("limited_vector::insert: too much elements"); + CAF_RAISE_ERROR("limited_vector::insert: too much elements"); } if (pos == end()) { resize(size() + num_elements); @@ -245,12 +240,11 @@ } } - private: - size_t m_size; - T m_data[(MaxSize > 0) ? MaxSize : 1]; +private: + size_t size_; + T data_[(MaxSize > 0) ? MaxSize : 1]; }; } // namespace detail } // namespace caf -#endif // CAF_DETAIL_LIMITED_VECTOR_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/logging.hpp actor-framework-0.16.3/libcaf_core/caf/detail/logging.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/logging.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/logging.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,321 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_LOGGING_HPP -#define CAF_LOGGING_HPP - -#include -#include -#include -#include -#include -#include - -#include "caf/config.hpp" -#include "caf/to_string.hpp" -#include "caf/abstract_actor.hpp" - -#include "caf/detail/singletons.hpp" -#include "caf/detail/scope_guard.hpp" -#include "caf/detail/shared_spinlock.hpp" - -/* - * To enable logging, you have to define CAF_DEBUG. This enables - * CAF_LOG_ERROR messages. To enable more debugging output, you can - * define CAF_LOG_LEVEL to: - * 1: + warning - * 2: + info - * 3: + debug - * 4: + trace (prints for each logged method entry and exit message) - * - * Note: this logger emits log4j style XML output; logs are best viewed - * using a log4j viewer, e.g., http://code.google.com/p/otroslogviewer/ - * - */ -namespace caf { -namespace detail { - -class singletons; - -class logging { - public: - friend class detail::singletons; - - // returns the actor ID for the current thread or 0 if none is assigned - actor_id get_aid(); - - // associates given actor id with this thread, - // returns the previously set actor id - actor_id set_aid(actor_id aid); - - virtual void log(const char* level, const char* class_name, - const char* function_name, const char* file_name, - int line_num, const std::string& msg) = 0; - - class trace_helper { - public: - trace_helper(std::string class_name, const char* fun_name, - const char* file_name, int line_num, const std::string& msg); - - ~trace_helper(); - - private: - std::string m_class; - const char* m_fun_name; - const char* m_file_name; - int m_line_num; - }; - - protected: - virtual ~logging(); - - static logging* create_singleton(); - - virtual void initialize() = 0; - - virtual void stop() = 0; - - inline void dispose() { - delete this; - } - - private: - detail::shared_spinlock m_aids_lock; - std::unordered_map m_aids; -}; - -struct oss_wr { - inline oss_wr() { - // nop - } - - inline oss_wr(oss_wr&& other) : m_str(std::move(other.m_str)) { - // nop - } - - std::string m_str; - - inline std::string str() { - return std::move(m_str); - } -}; - -inline oss_wr operator<<(oss_wr&& lhs, std::string str) { - lhs.m_str += std::move(str); - return std::move(lhs); -} - -inline oss_wr operator<<(oss_wr&& lhs, const char* str) { - lhs.m_str += str; - return std::move(lhs); -} - -template -oss_wr operator<<(oss_wr&& lhs, T rhs) { - std::ostringstream oss; - oss << rhs; - lhs.m_str += oss.str(); - return std::move(lhs); -} - -} // namespace detail -} // namespace caf - -#define CAF_VOID_STMT static_cast(0) - -#define CAF_CAT(a, b) a##b - -#define CAF_ERROR 0 -#define CAF_WARNING 1 -#define CAF_INFO 2 -#define CAF_DEBUG 3 -#define CAF_TRACE 4 - -#define CAF_LVL_NAME0() "ERROR" -#define CAF_LVL_NAME1() "WARN " -#define CAF_LVL_NAME2() "INFO " -#define CAF_LVL_NAME3() "DEBUG" -#define CAF_LVL_NAME4() "TRACE" - -#define CAF_CONCAT_(LHS, RHS) LHS ## RHS -#define CAF_CONCAT(LHS, RHS) CAF_CONCAT_(LHS, RHS) -#define CAF_UNIFYN(NAME) CAF_CONCAT(NAME, __LINE__) - -#define CAF_PRINT_ERROR_IMPL(lvlname, classname, funname, message) \ - { \ - std::cerr << "[" << lvlname << "] " << classname << "::" << funname \ - << ": " << message << "\n"; \ - } \ - CAF_VOID_STMT - -#ifndef CAF_LOG_LEVEL -inline caf::actor_id caf_set_aid_dummy() { return 0; } -#define CAF_LOG_IMPL(lvlname, classname, funname, message) \ - CAF_PRINT_ERROR_IMPL(lvlname, classname, funname, message) -#define CAF_PUSH_AID(unused) static_cast(0) -#define CAF_PUSH_AID_FROM_PTR(unused) static_cast(0) -#define CAF_SET_AID(unused) caf_set_aid_dummy() -#else -#define CAF_LOG_IMPL(lvlname, classname, funname, message) \ - if (strcmp(lvlname, "ERROR") == 0) { \ - CAF_PRINT_ERROR_IMPL(lvlname, classname, funname, message); \ - } \ - caf::detail::singletons::get_logger()->log(lvlname, classname, funname, \ - __FILE__, __LINE__, \ - (caf::detail::oss_wr{} \ - << std::boolalpha \ - << message).str()) -#define CAF_PUSH_AID(aid_arg) \ - auto CAF_UNIFYN(caf_aid_tmp) \ - = caf::detail::singletons::get_logger()->set_aid(aid_arg); \ - auto CAF_UNIFYN(aid_aid_tmp_guard) = caf::detail::make_scope_guard([=] { \ - caf::detail::singletons::get_logger()->set_aid(CAF_UNIFYN(caf_aid_tmp)); \ - }) -#define CAF_PUSH_AID_FROM_PTR(some_ptr) \ - auto CAF_UNIFYN(caf_aid_ptr) = some_ptr; \ - CAF_PUSH_AID(CAF_UNIFYN(caf_aid_ptr) ? CAF_UNIFYN(caf_aid_ptr)->id() : 0) -#define CAF_SET_AID(aid_arg) \ - caf::detail::singletons::get_logger()->set_aid(aid_arg) -#endif - -#define CAF_PRINT0(lvlname, classname, funname, msg) \ - CAF_LOG_IMPL(lvlname, classname, funname, msg) - -#define CAF_PRINT_IF0(stmt, lvlname, classname, funname, msg) \ - if (stmt) { \ - CAF_LOG_IMPL(lvlname, classname, funname, msg); \ - } \ - CAF_VOID_STMT - -#define CAF_PRINT1(lvlname, classname, funname, msg) \ - CAF_PRINT0(lvlname, classname, funname, msg) - -#define CAF_PRINT_IF1(stmt, lvlname, classname, funname, msg) \ - CAF_PRINT_IF0(stmt, lvlname, classname, funname, msg) - -#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) \ - caf::detail::logging::trace_helper CAF_UNIFYN(caf_log_trace_) { \ - classname, funname, __FILE__, __LINE__, \ - (caf::detail::oss_wr{} << msg).str() \ - } -#endif - -#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 -#define CAF_PRINT3(lvlname, classname, funname, msg) \ - CAF_PRINT0(lvlname, classname, funname, msg) -#define CAF_PRINT_IF3(stmt, lvlname, classname, funname, msg) \ - CAF_PRINT_IF0(stmt, lvlname, classname, funname, msg) -#endif - -#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 -#define CAF_PRINT2(lvlname, classname, funname, msg) \ - CAF_PRINT0(lvlname, classname, funname, msg) -#define CAF_PRINT_IF2(stmt, lvlname, classname, funname, msg) \ - CAF_PRINT_IF0(stmt, lvlname, classname, funname, msg) -#endif - -#define CAF_EVAL(what) what - -/** - * @def CAF_LOGC - * Logs a message with custom class and function names. - */ -#define CAF_LOGC(level, classname, funname, msg) \ - CAF_CAT(CAF_PRINT, level)(CAF_CAT(CAF_LVL_NAME, level)(), classname, \ - funname, msg) - -/** - * @def CAF_LOGF - * Logs a message inside a free function. - */ -#define CAF_LOGF(level, msg) CAF_LOGC(level, "NONE", __func__, msg) - -/** - * @def CAF_LOGMF - * Logs a message inside a member function. - */ -#define CAF_LOGMF(level, msg) \ - CAF_LOGC(level, typeid(*this).name(), __func__, msg) - -/** - * @def CAF_LOGC - * Logs a message with custom class and function names. - */ -#define CAF_LOGC_IF(stmt, level, classname, funname, msg) \ - CAF_CAT(CAF_PRINT_IF, level)(stmt, CAF_CAT(CAF_LVL_NAME, level)(), \ - classname, funname, msg) - -/** - * @def CAF_LOGF - * Logs a message inside a free function. - */ -#define CAF_LOGF_IF(stmt, level, msg) \ - CAF_LOGC_IF(stmt, level, "NONE", __func__, msg) - -/** - * @def CAF_LOGMF - * Logs a message inside a member function. - */ -#define CAF_LOGMF_IF(stmt, level, msg) \ - CAF_LOGC_IF(stmt, level, typeid(*this).name(), __func__, msg) - -// convenience macros to safe some typing when printing arguments -#define CAF_ARG(arg) #arg << " = " << arg -#define CAF_TARG(arg, trans) #arg << " = " << trans(arg) -#define CAF_MARG(arg, memfun) #arg << " = " << arg.memfun() -#define CAF_TSARG(arg) #arg << " = " << to_string(arg) - -/****************************************************************************** - * convenience macros * - ******************************************************************************/ - -#define CAF_LOG_ERROR(msg) CAF_LOGMF(CAF_ERROR, msg) -#define CAF_LOG_WARNING(msg) CAF_LOGMF(CAF_WARNING, msg) -#define CAF_LOG_DEBUG(msg) CAF_LOGMF(CAF_DEBUG, msg) -#define CAF_LOG_INFO(msg) CAF_LOGMF(CAF_INFO, msg) -#define CAF_LOG_TRACE(msg) CAF_LOGMF(CAF_TRACE, msg) - -#define CAF_LOG_ERROR_IF(stmt, msg) CAF_LOGMF_IF(stmt, CAF_ERROR, msg) -#define CAF_LOG_WARNING_IF(stmt, msg) CAF_LOGMF_IF(stmt, CAF_WARNING, msg) -#define CAF_LOG_DEBUG_IF(stmt, msg) CAF_LOGMF_IF(stmt, CAF_DEBUG, msg) -#define CAF_LOG_INFO_IF(stmt, msg) CAF_LOGMF_IF(stmt, CAF_INFO, msg) -#define CAF_LOG_TRACE_IF(stmt, msg) CAF_LOGMF_IF(stmt, CAF_TRACE, msg) - -#define CAF_LOGF_ERROR(msg) CAF_LOGF(CAF_ERROR, msg) -#define CAF_LOGF_WARNING(msg) CAF_LOGF(CAF_WARNING, msg) -#define CAF_LOGF_DEBUG(msg) CAF_LOGF(CAF_DEBUG, msg) -#define CAF_LOGF_INFO(msg) CAF_LOGF(CAF_INFO, msg) -#define CAF_LOGF_TRACE(msg) CAF_LOGF(CAF_TRACE, msg) - -#define CAF_LOGF_ERROR_IF(stmt, msg) CAF_LOGF_IF(stmt, CAF_ERROR, msg) -#define CAF_LOGF_WARNING_IF(stmt, msg) CAF_LOGF_IF(stmt, CAF_WARNING, msg) -#define CAF_LOGF_DEBUG_IF(stmt, msg) CAF_LOGF_IF(stmt, CAF_DEBUG, msg) -#define CAF_LOGF_INFO_IF(stmt, msg) CAF_LOGF_IF(stmt, CAF_INFO, msg) -#define CAF_LOGF_TRACE_IF(stmt, msg) CAF_LOGF_IF(stmt, CAF_TRACE, msg) - -#endif // CAF_LOGGING_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/log_level.hpp actor-framework-0.16.3/libcaf_core/caf/detail/log_level.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/log_level.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/log_level.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,37 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +/// Integer value for the QUIET log level. +#define CAF_LOG_LEVEL_QUIET 0 + +/// Integer value for the ERROR log level. +#define CAF_LOG_LEVEL_ERROR 3 + +/// Integer value for the WARNING log level. +#define CAF_LOG_LEVEL_WARNING 6 + +/// Integer value for the INFO log level. +#define CAF_LOG_LEVEL_INFO 9 + +/// Integer value for the DEBUG log level. +#define CAF_LOG_LEVEL_DEBUG 12 + +/// Integer value for the TRACE log level. +#define CAF_LOG_LEVEL_TRACE 15 diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/mask_bits.hpp actor-framework-0.16.3/libcaf_core/caf/detail/mask_bits.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/mask_bits.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/mask_bits.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,52 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright (C) 2011 - 2017 * + * Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include +#include + +namespace caf { +namespace detail { + +/// Sets all bits after bits_to_keep to 0. +template +void mask_bits(std::array& bytes, size_t bits_to_keep) { + // Calculate how many bytes we keep. + auto bytes_to_keep = bits_to_keep / 8; + if (bytes_to_keep >= NumBytes) + return; + // See whether we have an unclean cut, e.g. keeping 7 bits of a byte. + auto byte_cutoff = bits_to_keep % 8; + auto i = bytes.begin() + bytes_to_keep; + if (byte_cutoff != 0) { + static constexpr uint8_t mask[] = {0x00, 0x80, 0xC0, 0xE0, + 0xF0, 0xF8, 0xFC, 0xFE}; + *i = *i & mask[byte_cutoff]; + ++i; + } + // Zero remaining bytes. + for (; i != bytes.end(); ++i) + *i = 0; +} + +} // namespace detail +} // namespace caf + + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/memory_cache_flag_type.hpp actor-framework-0.16.3/libcaf_core/caf/detail/memory_cache_flag_type.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/memory_cache_flag_type.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/memory_cache_flag_type.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_DETAIL_MEMORY_CACHE_FLAG_TYPE -#define CAF_DETAIL_MEMORY_CACHE_FLAG_TYPE - -namespace caf { -namespace detail { - -enum memory_cache_flag_type { - needs_embedding, - provides_embedding -}; - -} // namespace detail -} // namespace caf - -#endif // CAF_DETAIL_MEMORY_CACHE_FLAG_TYPE diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/memory.hpp actor-framework-0.16.3/libcaf_core/caf/detail/memory.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/memory.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/memory.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,232 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_DETAIL_MEMORY_HPP -#define CAF_DETAIL_MEMORY_HPP - -#include -#include -#include -#include -#include - -#include "caf/config.hpp" -#include "caf/ref_counted.hpp" - -#include "caf/detail/embedded.hpp" -#include "caf/detail/memory_cache_flag_type.hpp" - -namespace caf { -class mailbox_element; -} // namespace caf - -namespace caf { -namespace detail { - -namespace { - -constexpr size_t s_alloc_size = 1024 * 1024; // allocate ~1mb chunks -constexpr size_t s_cache_size = 10 * 1024 * 1024; // cache about 10mb per thread -constexpr size_t s_min_elements = 5; // don't create < 5 elements -constexpr size_t s_max_elements = 20; // don't create > 20 elements - -} // namespace - -using embedded_storage = std::pair, void*>; - -class memory_cache { - public: - virtual ~memory_cache(); - virtual embedded_storage new_embedded_storage() = 0; -}; - -template -class basic_memory_cache; - -#ifdef CAF_NO_MEM_MANAGEMENT - -template -struct rc_storage : public ref_counted { - T instance; - template - rc_storage(Ts&&... xs) - : instance(intrusive_ptr(this, false), - std::forward(xs)...) { - CAF_ASSERT(get_reference_count() >= 1); - } -}; - -template -T* unbox_rc_storage(T* ptr) { - return ptr; -} - -template -T* unbox_rc_storage(rc_storage* ptr) { - return &(ptr->instance); -} - -class memory { - public: - memory() = delete; - - // Allocates storage, initializes a new object, and returns the new instance. - template - static T* create(Ts&&... xs) { - using embedded_t = - typename std::conditional< - T::memory_cache_flag == provides_embedding, - rc_storage, - T - >::type; - return unbox_rc_storage(new embedded_t(std::forward(xs)...)); - } - - static inline memory_cache* get_cache_map_entry(const std::type_info*) { - return nullptr; - } -}; - -#else // CAF_NO_MEM_MANAGEMENT - -template -class basic_memory_cache : public memory_cache { - public: - static constexpr size_t ne = s_alloc_size / sizeof(T); - static constexpr size_t ms = ne < s_min_elements ? s_min_elements : ne; - static constexpr size_t dsize = ms > s_max_elements ? s_max_elements : ms; - - static_assert(dsize > 0, "dsize == 0"); - - using embedded_t = - typename std::conditional< - T::memory_cache_flag == needs_embedding, - embedded, - T - >::type; - - struct wrapper { - union { - embedded_t instance; - }; - - wrapper() { - // nop - } - - ~wrapper() { - // nop - } - }; - - class storage : public ref_counted { - public: - storage() : m_pos(0) { - // nop - } - - ~storage() { - // nop - } - - bool has_next() { - return m_pos < dsize; - } - - embedded_t* next() { - return &(m_data[m_pos++].instance); - } - - private: - size_t m_pos; - wrapper m_data[dsize]; - }; - - embedded_storage new_embedded_storage() override { - // allocate cache on-the-fly - if (!m_cache) { - m_cache.reset(new storage, false); // starts with ref count of 1 - CAF_ASSERT(m_cache->unique()); - } - auto res = m_cache->next(); - if (m_cache->has_next()) { - return {m_cache, res}; - } - // we got the last element out of the cache; pass the reference to the - // client to avoid pointless increase/decrease ops on the reference count - embedded_storage result; - result.first.reset(m_cache.release(), false); - result.second = res; - return result; - } - - private: - intrusive_ptr m_cache; -}; - -class memory { - - memory() = delete; - - template - friend class basic_memory_cache; - - public: - - // Allocates storage, initializes a new object, and returns the new instance. - template - static T* create(Ts&&... xs) { - using embedded_t = - typename std::conditional< - T::memory_cache_flag == needs_embedding, - embedded, - T - >::type; - auto mc = get_or_set_cache_map_entry(); - auto es = mc->new_embedded_storage(); - auto ptr = reinterpret_cast(es.second); - new (ptr) embedded_t(std::move(es.first), std::forward(xs)...); - return ptr; - } - - static memory_cache* get_cache_map_entry(const std::type_info* tinf); - - private: - - static void add_cache_map_entry(const std::type_info* tinf, - memory_cache* instance); - - template - static inline memory_cache* get_or_set_cache_map_entry() { - auto mc = get_cache_map_entry(&typeid(T)); - if (!mc) { - mc = new basic_memory_cache; - add_cache_map_entry(&typeid(T), mc); - } - return mc; - } - -}; - -#endif // CAF_NO_MEM_MANAGEMENT - -} // namespace detail -} // namespace caf - -#endif // CAF_DETAIL_MEMORY_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/merged_tuple.hpp actor-framework-0.16.3/libcaf_core/caf/detail/merged_tuple.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/merged_tuple.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/merged_tuple.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,91 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include "caf/message.hpp" +#include "caf/actor_addr.hpp" +#include "caf/attachable.hpp" +#include "caf/abstract_actor.hpp" + +namespace caf { +namespace detail { + +class merged_tuple : public message_data { +public: + // -- member types ----------------------------------------------------------- + + using message_data::cow_ptr; + + using data_type = std::vector; + + using mapping_type = std::vector>; + + // -- constructors, destructors, and assignment operators -------------------- + + static cow_ptr make(message x, message y); + + merged_tuple(data_type xs, mapping_type ys); + + merged_tuple& operator=(const merged_tuple&) = delete; + + // -- overridden observers of message_data ----------------------------------- + + merged_tuple* copy() const override; + + // -- overridden modifiers of type_erased_tuple ------------------------------ + + void* get_mutable(size_t pos) override; + + error load(size_t pos, deserializer& source) override; + + // -- overridden observers of type_erased_tuple ------------------------------ + + size_t size() const noexcept override; + + uint32_t type_token() const noexcept override; + + rtti_pair type(size_t pos) const noexcept override; + + const void* get(size_t pos) const noexcept override; + + std::string stringify(size_t pos) const override; + + type_erased_value_ptr copy(size_t pos) const override; + + error save(size_t pos, serializer& sink) const override; + + // -- observers -------------------------------------------------------------- + + const mapping_type& mapping() const; + +private: + // -- constructors, destructors, and assignment operators -------------------- + + merged_tuple(const merged_tuple&) = default; + + // -- data members ----------------------------------------------------------- + + data_type data_; + uint32_t type_token_; + mapping_type mapping_; +}; + +} // namespace detail +} // namespace caf + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/message_case_builder.hpp actor-framework-0.16.3/libcaf_core/caf/detail/message_case_builder.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/message_case_builder.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/message_case_builder.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,342 +0,0 @@ -/****************************************************************************** - * ____ _ _____ * - * / ___| / \ | ___| C++ * - * | | / _ \ | |_ Actor * - * | |___ / ___ \| _| Framework * - * \____/_/ \_|_| * - * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * - * * - * 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_DETAIL_MESSAGE_CASE_BUILDER_HPP -#define CAF_DETAIL_MESSAGE_CASE_BUILDER_HPP - -#include - -#include "caf/duration.hpp" -#include "caf/match_case.hpp" -#include "caf/timeout_definition.hpp" - -namespace caf { -namespace detail { - -class timeout_definition_builder { - public: - constexpr timeout_definition_builder(const duration& d) : m_tout(d) { - // nop - } - - template - timeout_definition operator>>(F f) const { - return {m_tout, std::move(f)}; - } - - private: - duration m_tout; -}; - -class message_case_builder { }; - -class trivial_match_case_builder : public message_case_builder { - public: - constexpr trivial_match_case_builder() { - // nop - } - - template - trivial_match_case operator>>(F f) const { - return {std::move(f)}; - } -}; - -class catch_all_match_case_builder : public message_case_builder { - public: - constexpr catch_all_match_case_builder() { - // nop - } - - const catch_all_match_case_builder& operator()() const { - return *this; - } - - template - catch_all_match_case operator>>(F f) const { - return {std::move(f)}; - } -}; - -template -class message_case_pair_builder : public message_case_builder { - public: - message_case_pair_builder(Left l, Right r) - : m_left(std::move(l)), - m_right(std::move(r)) { - // nop - } - - template - auto operator>>(F f) const - -> std::tuple(nullptr) >> f), - decltype(*static_cast(nullptr) >> f)> { - return std::make_tuple(m_left >> f, m_right >> f); - } - - private: - Left m_left; - Right m_right; -}; - -struct tuple_maker { - template - inline auto operator()(Ts&&... xs) - -> decltype(std::make_tuple(std::forward(xs)...)) { - return std::make_tuple(std::forward(xs)...); - } -}; - -struct variadic_ctor {}; - -template -struct get_advanced_match_case { - using ctrait = typename get_callable_trait::type; - - using filtered_pattern = - typename tl_filter_not_type< - Pattern, - anything - >::type; - - using padded_transformers = - typename tl_pad_right< - Transformers, - tl_size::value - >::type; - - using base_signature = - typename tl_map< - filtered_pattern, - std::add_const, - std::add_lvalue_reference - >::type; - - using padded_expr_args = - typename tl_map_conditional< - typename tl_pad_left< - typename ctrait::arg_types, - tl_size::value - >::type, - std::is_lvalue_reference, - false, - std::add_const, - std::add_lvalue_reference - >::type; - - // override base signature with required argument types of Expr - // and result types of transformation - using partial_fun_signature = - typename tl_zip< - typename tl_map< - padded_transformers, - map_to_result_type, - rm_optional, - std::add_lvalue_reference - >::type, - typename tl_zip< - padded_expr_args, - base_signature, - left_or_right - >::type, - left_or_right - >::type; - - // 'inherit' mutable references from partial_fun_signature - // for arguments without transformation - using projection_signature = - typename tl_zip< - typename tl_zip< - padded_transformers, - partial_fun_signature, - if_not_left - >::type, - base_signature, - deduce_ref_type - >::type; - - using type = - advanced_match_case_impl< - Expr, - Pattern, - padded_transformers, - projection_signature - >; -}; - -template -struct pattern_projection_zipper { - using type = Y; -}; - -template -struct pattern_projection_zipper { - using type = none_t; -}; - -template ::type - >::value> -class advanced_match_case_builder : public message_case_builder { - public: - using guards_tuple = - typename tl_apply< - // discard projection if at the same index in Pattern is a wildcard - typename tl_filter_not_type< - typename tl_zip::type, - none_t - >::type, - std::tuple - >::type; - - advanced_match_case_builder() = default; - - template - advanced_match_case_builder(variadic_ctor, Fs... fs) - : m_guards(make_guards(Pattern{}, fs...)) { - // nop - } - - advanced_match_case_builder(guards_tuple arg1) : m_guards(std::move(arg1)) { - // nop - } - - template - typename get_advanced_match_case::type - operator>>(F f) const { - return {f, m_guards}; - } - - private: - template - static guards_tuple make_guards(tail_argument_token&, Fs&... fs) { - return std::make_tuple(std::move(fs)...); - } - - template - static guards_tuple make_guards(std::pair, F> x, Fs&&... fs) { - return make_guards(std::forward(fs)..., x.second); - } - - template - static guards_tuple make_guards(std::pair, F>, Fs&&... fs) { - return make_guards(std::forward(fs)...); - } - - template - static guards_tuple make_guards(type_list, Fs&... fs) { - tail_argument_token eoa; - return make_guards(std::make_pair(wrapped(), std::ref(fs))..., eoa); - } - - guards_tuple m_guards; -}; - -template -struct advanced_match_case_builder - : public message_case_builder { - public: - using guards_tuple = - typename detail::tl_apply< - typename tl_pop_back::type, - std::tuple - >::type; - - using pattern = typename tl_pop_back::type; - - advanced_match_case_builder() = default; - - template - advanced_match_case_builder(variadic_ctor, Fs... fs) - : m_guards(make_guards(Pattern{}, fs...)) { - // nop - } - - advanced_match_case_builder(guards_tuple arg1) : m_guards(std::move(arg1)) { - // nop - } - - template - typename get_advanced_match_case< - F, - Projections, - typename tl_concat< - pattern, - typename tl_map< - typename get_callable_trait::arg_types, - std::decay - >::type - >::type - >::type - operator>>(F f) const { - using padding = - typename tl_apply< - typename tl_replicate::num_args, unit_t>::type, - std::tuple - >::type; - return {f, std::tuple_cat(m_guards, padding{})}; - } - - private: - static guards_tuple make_guards(tail_argument_token&) { - return {}; - } - - template - static guards_tuple make_guards(std::pair, F>, - tail_argument_token&, Fs&... fs) { - return std::make_tuple(std::move(fs)...); - } - - template - static guards_tuple make_guards(std::pair, F> x, Fs&&... fs) { - return make_guards(std::forward(fs)..., x.second); - } - - template - static guards_tuple make_guards(std::pair, F>, Fs&&... fs) { - return make_guards(std::forward(fs)...); - } - - template - static guards_tuple make_guards(type_list, Fs&... fs) { - tail_argument_token eoa; - return make_guards(std::make_pair(wrapped(), std::ref(fs))..., eoa); - } - - guards_tuple m_guards; -}; - -template -typename std::enable_if< - std::is_base_of::value - && std::is_base_of::value, - message_case_pair_builder ->::type -operator||(Left l, Right r) { - return {l, r}; -} - -} // namespace detail -} // namespace caf - -#endif // CAF_DETAIL_MESSAGE_CASE_BUILDER_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/message_data.hpp actor-framework-0.16.3/libcaf_core/caf/detail/message_data.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/message_data.hpp 2015-04-13 15:16:29.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/message_data.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -5,8 +5,7 @@ * | |___ / ___ \| _| Framework * * \____/_/ \_|_| * * * - * Copyright (C) 2011 - 2015 * - * Dominik Charousset * + * Copyright 2011-2018 Dominik Charousset * * * * 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 * @@ -17,137 +16,49 @@ * http://www.boost.org/LICENSE_1_0.txt. * ******************************************************************************/ -#ifndef CAF_DETAIL_MESSAGE_DATA_HPP -#define CAF_DETAIL_MESSAGE_DATA_HPP +#pragma once #include #include #include -#include "caf/intrusive_ptr.hpp" #include "caf/config.hpp" +#include "caf/fwd.hpp" +#include "caf/intrusive_cow_ptr.hpp" +#include "caf/intrusive_ptr.hpp" #include "caf/ref_counted.hpp" -#include "caf/uniform_type_info.hpp" +#include "caf/type_erased_tuple.hpp" #include "caf/detail/type_list.hpp" namespace caf { namespace detail { -class message_data : public ref_counted { - public: - message_data() = default; - message_data(const message_data&) = default; - ~message_data(); - - /**************************************************************************** - * modifiers * - ****************************************************************************/ - - virtual void* mutable_at(size_t pos) = 0; - - /**************************************************************************** - * observers * - ****************************************************************************/ - - // computes "@<>+..." formatted type name - std::string tuple_type_names() const; - - // compares each element using uniform_type_info objects - bool equals(const message_data& other) const; - - virtual size_t size() const = 0; - - virtual const void* at(size_t pos) const = 0; - - // Tries to match element at position `pos` to given RTTI. - virtual bool match_element(size_t pos, uint16_t typenr, - const std::type_info* rtti) const = 0; - - virtual uint32_t type_token() const = 0; +class message_data : public ref_counted, public type_erased_tuple { +public: + // -- nested types ----------------------------------------------------------- - virtual const char* uniform_name_at(size_t pos) const = 0; + using cow_ptr = intrusive_cow_ptr; - virtual uint16_t type_nr_at(size_t pos) const = 0; + // -- constructors, destructors, and assignment operators -------------------- - /**************************************************************************** - * nested types * - ****************************************************************************/ - - class cow_ptr { - public: - cow_ptr() = default; - cow_ptr(cow_ptr&&) = default; - cow_ptr(const cow_ptr&) = default; - cow_ptr& operator=(cow_ptr&&) = default; - cow_ptr& operator=(const cow_ptr&) = default; - - template - cow_ptr(intrusive_ptr p) : m_ptr(std::move(p)) { - // nop - } - - inline cow_ptr(message_data* ptr, bool add_ref) : m_ptr(ptr, add_ref) { - // nop - } - - /************************************************************************** - * modifiers * - **************************************************************************/ - - inline void swap(cow_ptr& other) { - m_ptr.swap(other.m_ptr); - } - - inline void reset(message_data* p = nullptr, bool add_ref = true) { - m_ptr.reset(p, add_ref); - } - - inline message_data* release() { - return m_ptr.release(); - } - - inline void detach() { - static_cast(get_detached()); - } - - inline message_data* operator->() { - return get_detached(); - } - - inline message_data& operator*() { - return *get_detached(); - } - /************************************************************************** - * observers * - **************************************************************************/ + message_data() = default; + message_data(const message_data&) = default; - inline const message_data* operator->() const { - return m_ptr.get(); - } + ~message_data() override; - inline const message_data& operator*() const { - return *m_ptr.get(); - } + // -- pure virtual observers ------------------------------------------------- - inline explicit operator bool() const { - return static_cast(m_ptr); - } + virtual message_data* copy() const = 0; - inline message_data* get() const { - return m_ptr.get(); - } + // -- observers -------------------------------------------------------------- - private: - message_data* get_detached(); - intrusive_ptr m_ptr; - }; + using type_erased_tuple::copy; - virtual cow_ptr copy() const = 0; + bool shared() const noexcept override; }; } // namespace detail } // namespace caf -#endif // CAF_DETAIL_MESSAGE_DATA_HPP diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/move_if_not_ptr.hpp actor-framework-0.16.3/libcaf_core/caf/detail/move_if_not_ptr.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/move_if_not_ptr.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/move_if_not_ptr.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,46 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright (C) 2011 - 2014 * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/detail/type_traits.hpp" + +namespace caf { +namespace detail { + + +/// Moves the value from `x` if it is not a pointer (e.g., `optional` or +/// `expected`), returns `*x` otherwise. +template +T& move_if_not_ptr(T* x) { + return *x; +} + +/// Moves the value from `x` if it is not a pointer (e.g., `optional` or +/// `expected`), returns `*x` otherwise. +template ::value>> +T&& move_if_not_ptr(T& x) { + return std::move(*x); +} + +} // namespace detail +} // namespace caf + + diff -Nru actor-framework-0.13.2/libcaf_core/caf/detail/mpi_splice.hpp actor-framework-0.16.3/libcaf_core/caf/detail/mpi_splice.hpp --- actor-framework-0.13.2/libcaf_core/caf/detail/mpi_splice.hpp 1970-01-01 00:00:00.000000000 +0000 +++ actor-framework-0.16.3/libcaf_core/caf/detail/mpi_splice.hpp 2018-12-27 20:33:32.000000000 +0000 @@ -0,0 +1,90 @@ +/****************************************************************************** + * ____ _ _____ * + * / ___| / \ | ___| C++ * + * | | / _ \ | |_ Actor * + * | |___ / ___ \| _| Framework * + * \____/_/ \_|_| * + * * + * Copyright 2011-2018 Dominik Charousset * + * * + * 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. * + ******************************************************************************/ + +#pragma once + +#include + +#include "caf/replies_to.hpp" + +#include "caf/detail/type_list.hpp" +#include "caf/detail/typed_actor_util.hpp" + +namespace caf { +namespace detail { + +template +struct mpi_splice_by_input; + +template +struct mpi_splice_by_input { + using type = T; +}; + +template +struct mpi_splice_by_input, Lists...> { + // consumed an entire list without match -> fail + using type = none_t; +}; + +// splice two MPIs if they have the same input +template +struct mpi_splice_by_input>, type_list>, Ts...>, Lists...> + : mpi_splice_by_input>, Lists...> { }; + +// skip element in list until empty +template +struct mpi_splice_by_input, Lists...> + : mpi_splice_by_input, Lists...> { }; + +template +struct input_mapped; + +template +struct input_mapped, none_t, type_list<>, Lists...> { + using type = type_list; +}; + +template +struct input_mapped, none_t, type_list, Lists...> + : input_mapped, T, type_list, Lists...> {}; + +template +struct input_mapped, T, FirstList, Lists...> + : input_mapped::type>, none_t, FirstList, Lists...> { }; + +template